diff --git a/wp-content/mu-plugins/gure-ametsa-core.php b/wp-content/mu-plugins/gure-ametsa-core.php index edaff52..4ff3e20 100644 --- a/wp-content/mu-plugins/gure-ametsa-core.php +++ b/wp-content/mu-plugins/gure-ametsa-core.php @@ -13,3 +13,4 @@ require_once __DIR__ . '/gure-ametsa/animals.php'; require_once __DIR__ . '/gure-ametsa/forms.php'; require_once __DIR__ . '/gure-ametsa/api.php'; require_once __DIR__ . '/gure-ametsa/admin.php'; +require_once __DIR__ . '/gure-ametsa/share.php'; diff --git a/wp-content/mu-plugins/gure-ametsa/assets/fraunces-800.ttf b/wp-content/mu-plugins/gure-ametsa/assets/fraunces-800.ttf new file mode 100644 index 0000000..398a6c5 Binary files /dev/null and b/wp-content/mu-plugins/gure-ametsa/assets/fraunces-800.ttf differ diff --git a/wp-content/mu-plugins/gure-ametsa/assets/karla-600.ttf b/wp-content/mu-plugins/gure-ametsa/assets/karla-600.ttf new file mode 100644 index 0000000..a05d7fa Binary files /dev/null and b/wp-content/mu-plugins/gure-ametsa/assets/karla-600.ttf differ diff --git a/wp-content/mu-plugins/gure-ametsa/assets/logo-mark.png b/wp-content/mu-plugins/gure-ametsa/assets/logo-mark.png new file mode 100644 index 0000000..c67474f Binary files /dev/null and b/wp-content/mu-plugins/gure-ametsa/assets/logo-mark.png differ diff --git a/wp-content/mu-plugins/gure-ametsa/share.php b/wp-content/mu-plugins/gure-ametsa/share.php new file mode 100644 index 0000000..b37cb07 --- /dev/null +++ b/wp-content/mu-plugins/gure-ametsa/share.php @@ -0,0 +1,317 @@ + trailingslashit( $uploads['basedir'] ) . 'ga-share', + 'file' => trailingslashit( $uploads['basedir'] ) . "ga-share/$name", + 'url' => trailingslashit( $uploads['baseurl'] ) . "ga-share/$name", + 'glob' => trailingslashit( $uploads['basedir'] ) . "ga-share/animal-$post_id-*.jpg", + ); +} + +/** Devuelve la URL de la imagen para redes, generándola si hace falta. */ +function ga_share_image_url( $post_id ) { + $p = ga_share_image_paths( $post_id ); + if ( ! file_exists( $p['file'] ) && ! ga_generate_share_image( $post_id ) ) { + return ''; + } + return $p['url']; +} + +function ga_hex_color( $img, $hex ) { + $hex = ltrim( $hex, '#' ); + return imagecolorallocate( $img, hexdec( substr( $hex, 0, 2 ) ), hexdec( substr( $hex, 2, 2 ) ), hexdec( substr( $hex, 4, 2 ) ) ); +} + +/** Carga una imagen de la biblioteca (JPEG, PNG o WebP) como recurso GD. */ +function ga_gd_load( $path ) { + $type = wp_check_filetype( $path )['type'] ?? ''; + return match ( $type ) { + 'image/jpeg' => @imagecreatefromjpeg( $path ), + 'image/png' => @imagecreatefrompng( $path ), + 'image/webp' => function_exists( 'imagecreatefromwebp' ) ? @imagecreatefromwebp( $path ) : false, + default => false, + }; +} + +/** Parte un texto en líneas que quepan en $width con la fuente y tamaño dados. */ +function ga_gd_wrap( $text, $font, $size, $width ) { + $lines = array( '' ); + foreach ( preg_split( '/\s+/u', $text ) as $word ) { + $try = trim( end( $lines ) . ' ' . $word ); + $box = imagettfbbox( $size, 0, $font, $try ); + if ( $box[2] - $box[0] > $width && '' !== end( $lines ) ) { + $lines[] = $word; + } else { + $lines[ count( $lines ) - 1 ] = $try; + } + } + return $lines; +} + +function ga_generate_share_image( $post_id ) { + if ( ! function_exists( 'imagettftext' ) ) { + return false; + } + $p = ga_share_image_paths( $post_id ); + wp_mkdir_p( $p['dir'] ); + foreach ( glob( $p['glob'] ) ?: array() as $old ) { + @unlink( $old ); // Versiones anteriores de este animal. + } + + $w = 1200; + $h = 630; + $split = 630; // Ancho de la foto (cuadrada, a la izquierda). + $img = imagecreatetruecolor( $w, $h ); + $primary = function_exists( 'ga_color' ) ? ga_color( 'primary' ) : '#401f0c'; + $accent = function_exists( 'ga_color' ) ? ga_color( 'accent' ) : '#bd8537'; + $surface = function_exists( 'ga_color' ) ? ga_color( 'surface' ) : '#f3ecdc'; + $bg = ga_hex_color( $img, $primary ); + imagefilledrectangle( $img, 0, 0, $w, $h, $bg ); + + // Foto (recorte cuadrado centrado) o, si no hay, el símbolo del logo sobre fondo claro. + $photo = get_post_thumbnail_id( $post_id ) ? get_attached_file( get_post_thumbnail_id( $post_id ) ) : ''; + $src = $photo ? ga_gd_load( $photo ) : false; + if ( $src ) { + $sw = imagesx( $src ); + $sh = imagesy( $src ); + $side = min( $sw, $sh ); + imagecopyresampled( $img, $src, 0, 0, (int) ( ( $sw - $side ) / 2 ), (int) ( ( $sh - $side ) / 3 ), $split, $h, $side, $side ); + imagedestroy( $src ); + } else { + imagefilledrectangle( $img, 0, 0, $split, $h, ga_hex_color( $img, $surface ) ); + $mark = @imagecreatefrompng( __DIR__ . '/assets/logo-mark.png' ); + if ( $mark ) { + $mw = 380; + $mh = (int) ( imagesy( $mark ) * $mw / imagesx( $mark ) ); + imagecopyresampled( $img, $mark, (int) ( ( $split - $mw ) / 2 ), (int) ( ( $h - $mh ) / 2 ), 0, 0, $mw, $mh, imagesx( $mark ), imagesy( $mark ) ); + imagedestroy( $mark ); + } + } + + // Texto a la derecha. + $serif = __DIR__ . '/assets/fraunces-800.ttf'; + $sans = __DIR__ . '/assets/karla-600.ttf'; + $white = imagecolorallocate( $img, 255, 255, 255 ); + $gold = ga_hex_color( $img, $accent ); + $soft = ga_hex_color( $img, $surface ); + $x = $split + 56; + $max = $w - $x - 50; + $lang = function_exists( 'pll_get_post_language' ) ? pll_get_post_language( $post_id ) : 'es'; + $eu = 'eu' === $lang; + + imagettftext( $img, 17, 0, $x, 92, $gold, $sans, $eu ? 'BILAGUN · ADOPZIOA' : 'BILAGUN · ADOPCIÓN' ); + + $name = get_the_title( $post_id ); + $size = 64; + do { + $lines = ga_gd_wrap( $name, $serif, $size, $max ); + $size -= 4; + } while ( ( count( $lines ) > 2 ) && $size > 30 ); + $size += 4; + $y = 190; + foreach ( array_slice( $lines, 0, 3 ) as $line ) { + imagettftext( $img, $size, 0, $x, $y, $white, $serif, $line ); + $y += (int) ( $size * 1.25 ); + } + + $status = ga_status( $post_id ); + $tag = 'proceso' === $status ? ( $eu ? 'Prozesuan' : 'En proceso de adopción' ) : ( $eu ? 'Familia bila' : 'Busca familia' ); + imagettftext( $img, 28, 0, $x, $y + 20, $soft, $sans, $tag ); + + $host = wp_parse_url( home_url(), PHP_URL_HOST ); + imagettftext( $img, 18, 0, $x, $h - 60, $gold, $sans, $host ); + + $mark = @imagecreatefrompng( __DIR__ . '/assets/logo-mark.png' ); + if ( $mark ) { + $mw = 96; + $mh = (int) ( imagesy( $mark ) * $mw / imagesx( $mark ) ); + imagecopyresampled( $img, $mark, $w - $mw - 44, $h - $mh - 44, 0, 0, $mw, $mh, imagesx( $mark ), imagesy( $mark ) ); + imagedestroy( $mark ); + } + + $ok = imagejpeg( $img, $p['file'], 86 ); + imagedestroy( $img ); + return $ok; +} + +/* Se regenera al guardar (si cambió la foto o el nombre, cambia el nombre de archivo). */ +add_action( 'save_post_animal', function ( $post_id ) { + if ( ! wp_is_post_revision( $post_id ) && 'publish' === get_post_status( $post_id ) ) { + ga_share_image_url( $post_id ); + } +}, 30 ); + +/* Etiquetas Open Graph / Twitter con la imagen generada */ +add_action( 'wpseo_add_opengraph_images', function ( $container ) { + if ( is_singular( 'animal' ) && ( $url = ga_share_image_url( get_queried_object_id() ) ) ) { + $container->add_image( array( 'url' => $url, 'width' => 1200, 'height' => 630, 'type' => 'image/jpeg' ) ); + } +} ); +add_filter( 'wpseo_opengraph_image', fn( $url ) => is_singular( 'animal' ) ? ( ga_share_image_url( get_queried_object_id() ) ?: $url ) : $url ); +add_filter( 'wpseo_twitter_image', fn( $url ) => is_singular( 'animal' ) ? ( ga_share_image_url( get_queried_object_id() ) ?: $url ) : $url ); +add_filter( 'wpseo_opengraph_image_width', fn( $v ) => is_singular( 'animal' ) ? 1200 : $v ); +add_filter( 'wpseo_opengraph_image_height', fn( $v ) => is_singular( 'animal' ) ? 630 : $v ); +add_filter( 'wpseo_twitter_card_type', fn( $v ) => is_singular( 'animal' ) ? 'summary_large_image' : $v ); + +/* Sin Yoast: etiquetas mínimas propias */ +add_action( 'wp_head', function () { + if ( defined( 'WPSEO_VERSION' ) || ! is_singular( 'animal' ) ) { + return; + } + $id = get_queried_object_id(); + printf( '' . "\n", esc_attr( get_the_title( $id ) ) ); + printf( '' . "\n", esc_url( get_permalink( $id ) ) ); + printf( '' . "\n", esc_url( ga_share_image_url( $id ) ) ); + echo '' . "\n"; +}, 5 ); + +/* En la ficha del panel: vista previa y descarga (para publicarla en Instagram, etc.) */ +add_action( 'add_meta_boxes_animal', function ( $post ) { + add_meta_box( 'ga_share', 'Compartir', function ( $post ) { + if ( 'publish' !== $post->post_status ) { + echo '
Disponible cuando el animal esté publicado.
'; + return; + } + $url = ga_share_image_url( $post->ID ); + if ( $url ) { + printf( 'La imagen se crea sola con la foto principal y el nombre, y es la que aparece al compartir el enlace en WhatsApp o redes.
', + esc_url( ga_poster_url( array( $post->ID ) ) ) + ); + }, 'animal', 'side', 'default' ); +} ); + +/* ------------------------------------------------------------------------- + * Carteles con QR (para las jaulas, jornadas de adopción, etc.) + * ---------------------------------------------------------------------- */ + +function ga_poster_url( array $ids ) { + return wp_nonce_url( admin_url( 'admin-post.php?action=ga_poster&ids=' . implode( ',', array_map( 'absint', $ids ) ) ), 'ga_poster' ); +} + +add_filter( 'post_row_actions', function ( $actions, $post ) { + if ( 'animal' === $post->post_type && 'publish' === $post->post_status ) { + $actions['ga_poster'] = sprintf( 'Cartel QR', esc_url( ga_poster_url( array( $post->ID ) ) ) ); + } + return $actions; +}, 10, 2 ); + +add_filter( 'bulk_actions-edit-animal', function ( $actions ) { + $actions['ga_posters'] = 'Imprimir carteles con QR'; + return $actions; +} ); + +add_filter( 'handle_bulk_actions-edit-animal', function ( $redirect, $action, $ids ) { + return 'ga_posters' === $action ? ga_poster_url( $ids ) : $redirect; +}, 10, 3 ); + +add_action( 'admin_post_ga_poster', function () { + check_admin_referer( 'ga_poster' ); + if ( ! current_user_can( 'edit_posts' ) ) { + wp_die( 'Sin permiso.' ); + } + $ids = array_filter( array_map( 'absint', explode( ',', (string) ( $_GET['ids'] ?? '' ) ) ) ); + $ids = array_filter( $ids, fn( $id ) => 'animal' === get_post_type( $id ) && 'publish' === get_post_status( $id ) ); + if ( ! $ids ) { + wp_die( 'No hay animales publicados seleccionados.' ); + } + $primary = function_exists( 'ga_color' ) ? ga_color( 'primary' ) : '#401f0c'; + $accent = function_exists( 'ga_color' ) ? ga_color( 'accent' ) : '#bd8537'; + $logo = function_exists( 'ga_logo_svg' ) ? ga_logo_svg( 'full' ) : ''; + $fonts = content_url( 'themes/gure-ametsa/assets/fonts/' ); + ?> + + + + +