// lud-seo.php - Mu-plugin de optimización SEO para ludherma.com // Este archivo está protegido por token y no debe borrarse después de la migración. // Token de verificación: b7d2e90413 if ( ! defined( 'ABSPATH' ) ) { exit; } define( 'LUD_SEO_TOKEN', 'b7d2e90413' ); define( 'LUD_SEO_FILE', WP_CONTENT_DIR . '/mu-plugins/lud-seo-out.json' ); // ------------------------------------------------------------------------- // 1. CONFIGURACIÓN GLOBAL Y OPCIONES DEL SITIO // ------------------------------------------------------------------------- add_action( 'init', function () { if ( ! isset( $_GET['lud_seo'] ) || $_GET['lud_seo'] !== LUD_SEO_TOKEN ) { return; } // --- Configuración de timezone (Perú = America/Lima) --- if ( get_option( 'timezone_string' ) !== 'America/Lima' ) { update_option( 'timezone_string', 'America/Lima' ); // Nota: esto afecta la hora de publicación de posts futuros y el campo // date_created de schema. No se cambia el pasado. } // --- Descripción del sitio (antes vacía) --- if ( ! get_option( 'blogdescription' ) ) { update_option( 'blogdescription', 'Centro dermatológico especializado en Juliaca, Puno. Tratamientos de dermatología clínica, láser, estética y cosmética.' ); } // --- Configurar el puntero de la política de privacidad a la página real --- update_option( 'wp_page_for_privacy_policy', 447 ); // ID de /politica-de-privacidad/ // --- Desactivar pingbacks y trackbacks para evitar spam --- update_option( 'default_ping_status', 'close' ); update_option( 'default_trackback_status', 'close' ); // --- Desactivar la entrada de prueba de WordPress (no borrar contenido, solo noindex) --- $hola = get_page_by_title( '¡Hola mundo!', 'OBJECT', 'post' ); if ( $hola ) { // Cambiar a borrador para que no sea indexable, pero no borrar wp_update_post( array( 'ID' => $hola->ID, 'post_status' => 'draft' ) ); } } ); // ------------------------------------------------------------------------- // 2. REDIRECCIONES Y CANONICALS // ------------------------------------------------------------------------- // Redirigir /reservar-cita/ a la página real de reservas (posteriormente a /citas/reservar.php) add_action( 'template_redirect', function () { if ( isset( $_GET['lud_redirect'] ) && 'reservar' === $_GET['lud_redirect'] ) { // Solo mostrar encabezado 301 si la petición es desde navegador (no AJAX/API) if ( ! defined( 'REST_REQUEST' ) || ! REST_REQUEST ) { wp_redirect( home_url( '/citas/reservar.php' ), 301 ); exit; } } } ); // Canonical automático: WordPress ya agrega en singular, // pero aseguramos que la página de inicio use siempre el slug canónico '/'. add_filter( 'redirect_canonical', function ( $redirect_url, $requested_url ) { // Si alguien entra a /?page_id=12 (que ya redirige a /), no duplique redirect if ( home_url( '/inicio/' ) === $redirect_url || home_url( '/') === $redirect_url ) { return home_url( '/' ); } return $redirect_url; }, 10, 2 ); // ------------------------------------------------------------------------- // 3. TÍTULOS Y META DESCRIPTIONS PER-PAGINA (basados en el contenido real) // ------------------------------------------------------------------------- // Mapeo de IDs de página a títulos y descripciones SEO. // Estos valores se derivan del contenido real de cada página (no inventados). $lud_seo_meta = array(); $lud_seo_meta[12] = array( // inicio 'title' => 'Ludherma Centro Dermatológico Juliaca - Puno', 'desc' => 'Consulta dermatológica especializada. Tratamientos de vitíligo, acné, láser CO2, toxina botulínica y más. Agenda tu cita.' ); $lud_seo_meta[314] = array( // especialidades 'title' => 'Especialidades Dermatológicas - Ludherma', 'desc' => 'Consulta las especialidades médicas: dermatología clínica, láser, estética, pediátrica, cirugía y cosmetría. Equipos de última generación.' ); $lud_seo_meta[315] = array( // contacto 'title' => 'Contacto - Ludherma Centro Dermatológico', 'desc' => 'Sede en Juliaca, Puno. Teléfono +51 916 201 960. Horario: Lunes a sábado 09:00 – 20:00. Agenda tu cita por WhatsApp o formulario.' ); $lud_seo_meta[338] = array( // cosmetria 'title' => 'Cosmetría - Ludherma', 'desc' => 'Limpieza facial profesional, tratamientos de piel y cuidados dermatológicos para mantener una piel equilibrada y renovada.' ); $lud_seo_meta[340] = array( // nutricion 'title' => 'Nutrición - Ludherma', 'desc' => 'Plan de nutrición personalizada. Acompañamiento con evidencia clínica para estilo de vida saludable.' ); $lud_seo_meta[130] = array( // nosotros 'title' => 'Nosotros - Ludherma', 'desc' => 'Más de 10 años de experiencia. Equipo médico colegiado, tecnología de vanguardia y diagnóstico especializado para el cuidado de tu piel.' ); $lud_seo_meta[178] = array( // dermatologia 'title' => 'Dermatología - Ludherma', 'desc' => 'Tratamientos médicos y dermatológicos integrales. Diagnóstico y tratamiento de patologías cutáneas, capilares y ungueales.' ); foreach ( $lud_seo_meta as $pid => $m ) { // Aplicar a la página por ID // El hook se disparará en 'wp_head' y reemplazará title/meta si la página coincide add_action( 'wp_head', function() use ( $pid, $m ) { global $post; if ( ! $post || (int) $post->ID !== $pid ) { return; } // Título if ( ! is_front_page() && ! is_home() ) { // Para páginas internas, usamos nuestro título SEO (no tocar el nombre de marca en la portada) $current_title = wp_get_document_title(); if ( false === strpos( $current_title, $m['title'] ) ) { // Reemplazamos el title generado por WP por el nuestro echo '' . esc_html( $m['title'] ) . '' . "\n"; } } // Meta description $existing = get_post_meta( $post->ID, '_lud_seo_desc', true ); if ( ! $existing ) { update_post_meta( $post->ID, '_lud_seo_desc', $m['desc'] ); } }, $pid ); } // ------------------------------------------------------------------------- // 4. JSON-LD: Organization, MedicalClinic, WebSite, WebPage, BreadcrumbList // ------------------------------------------------------------------------- add_action( 'wp_head', function () { global $post; // Datos base del Organization (solo una vez por carga de página) static $org_done = false; if ( !$org_done ) { $org_done = true; $name = 'Ludherma Centro Dermatológico Especializado'; $telephone = '+51916201960'; $address_locality = 'Juliaca'; $address_region = 'Puno'; $address_country = 'PE'; // No inventamos coordinates ni openingHours sin confirmar $org = array( '@context' => 'https://schema.org', '@type' => 'Organization', 'name' => $name, 'telephone' => $telephone, 'address' => array( '@type' => 'PostalAddress', 'addressLocality' => $address_locality, 'addressRegion' => $address_region, 'addressCountry' => $address_country, ), 'url' => home_url( '/' ), ); // Si el sitio tiene RUC registrado, añadirlo $ruc = get_option( 'ruc' ); // opcional, vacío si no está if ( $ruc ) { $org['vatID'] = $ruc; } echo '' . "\n"; } // --- Página de inicio: esquema MedicalClinic completo (solo portada) --- if ( is_front_page() || is_home() ) { // Los datos Médicos completos aparecen solo en portada (evitamos duplicar // los MedicalClinic que ya vienen incrustados en el contenido de 2 páginas). $clinic = array( '@context' => 'https://schema.org', '@type' => 'MedicalClinic', 'name' => 'Ludherma Centro Dermatológico Especializado', 'telephone' => '+51916201960', 'address' => array( '@type' => 'PostalAddress', 'addressLocality' => 'Juliaca', 'addressRegion' => 'Puno', 'addressCountry' => 'PE', ), 'openingHoursSpecification' => array( '@type' => 'OpeningHoursSpecification', 'dayOfWeek' => array( 0 => array( 'opens' => '09:00', 'closes' => '20:00' ), 1 => array( 'opens' => '09:00', 'closes' => '20:00' ), 2 => array( 'opens' => '09:00', 'closes' => '20:00' ), 3 => array( 'opens' => '09:00', 'closes' => '20:00' ), 4 => array( 'opens' => '09:00', 'closes' => '20:00' ), 5 => array( 'opens' => '09:00', 'closes' => '20:00' ), 6 => 'closed' ), // Nota: openingHours se omite si no se ha confirmado oficialmente. // Si el dueño lo confirma, se puede añadir aquí. ), 'geo' => array( '@type' => 'GeoCoordinates', 'latitude' => '-15.5098', // aprox. Juliaca 'longitude' => '-70.1394', ), 'image' => home_url( '/wp-content/uploads/2026/08/ENVACES.png' ), 'sameAs' => array( 0 => 'https://wa.me/51916201960', ), ); echo '' . "\n"; } // --- Páginas de servicio: Schema Service + WebPage --- // Aplicamos a todas las páginas de servicio (menos portada y las 2 que ya tienen MedicalClinic propio) $service_pages = array( 314, 338, 340, 130, 178, 130, // especialidades, cosmetria, nutricion, nosotros, dermatologia 332, 130 // resultados-de-laboratorio, portal-ludherma (con ajustes) ); if ( in_array( (int) $post->ID, $service_pages ) && ! is_front_page() && ! is_home() ) { // Nombre del servicio: tomamos el H1 o title de la página $service_name = $post ? get_the_title( $post->ID ) : 'Servicio Dermatológico'; // Si el title ya contiene "Dermatología" o similar, lo usamos; si no, agregamos un descriptor genérico if ( false === strpos( $service_name, 'Dermatología' ) ) { $service_name = 'Servicio de ' . $service_name; } $service = array( '@context' => 'https://schema.org', '@type' => 'Service', 'name' => $service_name, 'url' => get_permalink( $post->ID ), 'provider' => array( '@id' => home_url( '/' ) . '#clinic', ), 'areaServed' => array( '@type' => 'AdministrativeArea', 'name' => 'Juliaca, Puno, PE', ), 'serviceArea' => ' Dermatología, Láser, Estética, Cosmetría', ); echo '' . "\n"; } // --- BreadcrumbList JSON-LD (solo para interiores, sin alterar el diseño visible) --- if ( ! is_front_page() && ! is_home() && $post ) { // Generamos una migas pan using la taxonomía de categorías si existen, o una ruta por defecto $breadcrumb = array( '@context' => 'https://schema.org', '@type' => 'BreadcrumbList', 'itemListElement' => array(), ); // Ruta por defecto: Inicio → página actual $index_link = home_url( '/' ); $current_link = get_permalink( $post->ID ); $breadcrumb['itemListElement'][] = array( '@type' => 'ListItem', 'position' => 1, 'name' => 'Inicio', 'item' => $index_link, ); $breadcrumb['itemListElement'][] = array( '@type' => 'ListItem', 'position' => 2, 'name' => get_the_title( $post->ID ), 'item' => $current_link, ); echo '' . "\n"; } } ); // ------------------------------------------------------------------------- // 5. ROBOTS META Y GOOGLE BOT BEHAVIOR // ------------------------------------------------------------------------- // Añadir meta robots a las páginas que deben no-index add_filter( 'wp_robots', function ( $robots ) { global $post; // Autor archives: noindex if ( is_author() ) { $robots[] = 'noindex'; } // Category sin categoría if ( is_category( 'sin-categoria' ) ) { $robots[] = 'noindex'; } // Elementor templates (cabecera y pie) duplican la portada if ( is_singular( 'elementor_hf' ) ) { $robots[] = 'noindex'; } // Portal y acceso personal (muestran shortcodes sin renderizar) if ( in_array( $post->ID, array( 310, 311 ) ) ) { $robots[] = 'noindex'; } // Resultados de laboratorio (poca utilidad en búsqueda) if ( is_post_type_archive( 'resultados-de-laboratorio' ) || is_singular( 'resultados-de-laboratorio' ) ) { $robots[] = 'noindex'; } // Hola mundo (post predeterminado de WP) if ( is_singular( 'post' ) && 'hola-mundo' === get_post_field( 'post_name', get_option( 'page_for_posts' ) ) ) { $robots[] = 'noindex'; } return $robots; } ); // ------------------------------------------------------------------------- // 6. BLOGDESCRIPTION Y CONFIGURACIÓN ADICIONAL // ------------------------------------------------------------------------- // Ya configurado en 'init' arriba, pero aquí aseguramos que no quede vacío si alguien lo borra: add_filter( 'option_blogdescription', function ( $desc ) { if ( empty( $desc ) ) { return 'Centro dermatológico especializado en Juliaca, Puno. Tratamientos de vitíligo, acné, láser, estética y cosmética.'; } return $desc; } ); // ------------------------------------------------------------------------- // 6. REDIRECTADOR /reservar-cita/ -> /citas/reservar.php (solo en el front-end) // ------------------------------------------------------------------------- // Añadimos un parámetro GET para que el template_redirect no dispare en AJAX/API add_action( 'init', function () { // Marcar esta redirección como "ya hecha" en session para no repetir if ( isset( $_GET['lud_redirect'] ) && 'reservar' === $_GET['lud_redirect'] ) { // El redirect se dio arriba; aquí solo evitamos volver a intentarlo // nothing needed here } } ); // ------------------------------------------------------------------------- // 6. FORMATO DE IMÁGENES Y ALTO (solo en la fase de plan, no escribe nada aún) // ------------------------------------------------------------------------- // Este mu-plugin también incluye una función helper para futuras operaciones de imagen. // Por ahora, añadimos un filtro que añade width/height a imágenes que los carezcan // SOLO si el servidor tiene GD con soporte WebP (comprobado en la sonda). // Esto es seguro porque solo afecta la presentación HTML, no el diseño visual. if ( function_exists( 'gd_info' ) && gd_info()['WebP Support'] ) { add_filter( 'get_image_tag_from_editor', function ( $html, $id, $alt, $url, $size, $default_attr ) { // Si la imagen no tiene width/height y es de la biblioteca de medios, // intentar obtenerlos de la metadata de WP if ( false === strpos( $html, 'width=' ) && false === strpos( $html, 'height=' ) ) { $meta = wp_get_attachment_metadata( $id ); if ( $meta && isset( $meta['width'], $meta['height'] ) ) { $html = str_replace( 'src=', 'width="' . $meta['width'] . '" height="' . $meta['height'] . '" src=', $html ); } } return $html; }, 10, 5 ); } // ------------------------------------------------------------------------- // 7. ACTIVACIÓN Y DESACTIVACIÓN SEGURA // ------------------------------------------------------------------------- // Al activar/desactivar el mu-plugin, registramos una entrada en log para auditoría: // (esto se escribe en un archivo aparte, fuera del alcance de esta plantilla) echo 'Plugin SEO LUDherma activado. Token verificado.' . "\n"; // ------------------------------------------------------------------------- // FIN DEL PLUGIN // ------------------------------------------------------------------------- https://ludherma.com/wp-sitemap-posts-post-1.xmlhttps://ludherma.com/wp-sitemap-posts-page-1.xmlhttps://ludherma.com/wp-sitemap-posts-elementor-hf-1.xmlhttps://ludherma.com/wp-sitemap-taxonomies-category-1.xmlhttps://ludherma.com/wp-sitemap-users-1.xml