La academia llevaba meses funcionando sin sobresaltos. Cursos publicados, fichas de profesores, landing de captación, blog con artículos semanales. Todo indexado, todo accesible, todo respondiendo como se esperaba. El tráfico orgánico crecía de forma estable y las URLs nuevas aparecían en Google en pocos días. No había razón para sospechar de nada.
El problema empezó justo después de activar un tema hijo para personalizar ciertas plantillas sin modificar el tema principal. Dos semanas más tarde, varias páginas de cursos habían desaparecido de los resultados de búsqueda. No todas: algunas seguían posicionadas con normalidad. El sitio no mostraba errores visibles, las páginas cargaban correctamente y el panel de WordPress no lanzaba ningún aviso. Pero Google había dejado de indexar contenido que antes sí recogía.
La caída no fue brusca. Fue lenta, parcial y silenciosa. Exactamente el tipo de síntoma que tarda en notarse y que, cuando se nota, ya lleva tiempo activo. La primera pregunta era directa: ¿qué había cambiado? Y la respuesta obvia era el tema. Pero lo obvio no siempre es lo real.

Operario: WordPin
Archivo del caso: El tema hijo de WordPress que heredaba noindex
Empresa o negocio: Academia online con cursos indexables
Archivado en: Plugins, temas y conflictos
Nivel: Intermedio
El tema hijo y las páginas que Google dejó de ver
Lo primero que hice fue comprobar el estado de indexación desde Google Search Console. Las URLs afectadas aparecían como rastreadas pero no indexadas, y en varios casos el motivo era explícito: la página contenía una directiva noindex. El patrón no era aleatorio. Las URLs excluidas correspondían mayoritariamente a páginas de cursos individuales y a algunas páginas de archivo de categorías de formación.
Revisé el plugin SEO activo. Era la primera sospecha lógica, porque es el lugar donde normalmente se gestiona la visibilidad de cada tipo de contenido. Pero la configuración estaba limpia: los cursos tenían permitida la indexación, las categorías también, y no había reglas globales que aplicasen noindex a ningún tipo de entrada. Revisé también la configuración por URL individual en varias de las páginas afectadas, y todas mostraban index, follow como valor activo.
Esto no encajaba.
La pista que apuntaba a los ajustes de lectura
WordPress tiene una opción en Ajustes > Lectura que permite disuadir a los motores de búsqueda de indexar el sitio. Es una casilla que inyecta una meta etiqueta noindex global. Fui directamente a comprobarlo, porque más de una vez he visto esa casilla activada por error tras una migración o un cambio de entorno.
La casilla estaba desmarcada. Además, para confirmar, ejecuté una consulta rápida contra wp_options:
SELECT option_value FROM wp_options WHERE option_name = 'blog_public';El resultado era 1, lo que significaba que WordPress no estaba bloqueando la indexación desde sus ajustes generales. Segundo descarte limpio. El sitio, desde su configuración interna, quería ser visible.
Abrí entonces las herramientas de desarrollo del navegador y fui al <head> de una de las páginas afectadas. Y ahí estaba la señal que no debería estar:
<meta name="robots" content="noindex, follow">La etiqueta existía en el HTML renderizado. No venía del plugin SEO, no venía de los ajustes de lectura, pero estaba ahí. La pregunta ya no era si existía un noindex, sino quién lo estaba inyectando. Que una página cargue bien no significa que esté enviando las señales correctas a los buscadores.
Lo que el tema hijo escondía en sus cabeceras
Activé Query Monitor para inspeccionar lo que se estaba ejecutando durante la carga. Su panel de Hooks & Actions lista todos los hooks disparados en la petición en orden cronológico, y para cada uno muestra los callbacks registrados, su prioridad y el componente que los originó. Al localizar la entrada de wp_head dentro del listado y revisar sus callbacks, había uno que no procedía ni del plugin SEO ni del core: el componente apuntaba directamente al tema hijo activo, con prioridad 1.
En ese momento, la sospecha dejó de ser difusa. Pero antes de confirmar nada, necesitaba ver el código.
Un fragmento heredado que nadie había revisado
Accedí por FTP al directorio del tema hijo y abrí su functions.php. El archivo no era largo, apenas unas funciones de personalización visual y un par de filtros para el menú principal. Pero entre ellos había un bloque que no tenía relación con la apariencia del sitio:
add_action( 'wp_head', function() {
if ( is_singular( 'curso' ) || is_tax( 'categoria_curso' ) ) {
echo '<meta name="robots" content="noindex, follow">';
}
}, 1 );Esa función anónima se ejecutaba en cada carga de página y comprobaba si la URL correspondía a un curso individual o a una taxonomía de categoría de curso. Si se cumplía la condición, inyectaba directamente una meta etiqueta noindex en el <head>. Sin filtro intermedio, sin opción de sobreescritura, sin relación con el plugin SEO.
El fragmento no era nuevo. Al revisar el historial del archivo, el bloque había sido copiado del tema padre durante la creación del child theme. En su momento, el tema padre lo usaba como medida temporal para ocultar contenidos en fase de pruebas. Cuando se creó la plantilla derivada, alguien copió el functions.php completo en lugar de partir de un archivo limpio, y ese fragmento viajó con él sin que nadie lo detectase.
El plugin SEO configuraba las meta robots correctamente, pero el fragmento del tema activo se ejecutaba antes y con mayor prioridad. El resultado era que ambas etiquetas convivían en el <head>: una diciendo index y otra diciendo noindex. Google, ante la contradicción, aplicaba la directiva más restrictiva. WordPress no avisa cuando dos fuentes emiten señales opuestas sobre indexación. Solo las ejecuta en orden.
El efecto acumulado
El impacto no fue inmediato porque Google no recrawlea todas las URLs al mismo tiempo. A medida que el bot iba pasando por las páginas afectadas y encontraba la señal de noindex, iba retirando las URLs del índice. Por eso la caída fue gradual y difícil de detectar a simple vista: el sitio no cayó de golpe, sino que fue perdiendo visibilidad curso a curso, categoría a categoría.
Las páginas estáticas como la home, las landings y las entradas del blog no usaban las plantillas singular-curso ni la taxonomía categoria_curso, por lo que nunca activaban la condición del fragmento. Esas páginas seguían indexadas con normalidad, lo que reforzaba la sensación de que el sitio en general funcionaba bien. El error parcial siempre es más peligroso que una caída total, porque deja demasiadas cosas funcionando.
Retirar la señal sin alterar la herencia limpia
La corrección directa era eliminar el bloque del functions.php. Pero antes de hacerlo, revisé si la función usaba un nombre declarado o era una closure anónima, porque eso cambiaba las opciones disponibles. Era una función anónima. Eso significaba que no podía neutralizarse con remove_action() desde otro archivo sin una referencia directa al objeto, algo que en ese contexto no era práctico. La única vía limpia era editar el archivo y retirar el bloque directamente.
Antes de tocar nada en producción, activé WP_DEBUG en el entorno de staging que la academia tenía configurado. Copié el tema hijo tal cual estaba, retiré el bloque en staging y cargué varias páginas de cursos y categorías. Ningún error PHP, ningún warning, ningún cambio en la estructura visual. El fragmento era completamente independiente del resto de funciones del archivo.
Qué limpiar primero y qué dejar documentado
Una vez confirmado en staging, apliqué la misma corrección en producción: editar el functions.php del tema hijo por FTP y retirar el bloque completo del hook. Lo que sí tenía sentido añadir después era una nota en el propio archivo que documentase por qué ese espacio estaba vacío: qué función había existido ahí, qué hacía y por qué se retiró. No es un mecanismo técnico, pero en un entorno donde varias personas pueden tocar el código, esa documentación evita que alguien vuelva a pegar el mismo fragmento pensando que falta algo. Retirar código sin explicar el motivo es la mitad de la solución.
Tras aplicar la corrección, inspeccioné de nuevo el <head> de las páginas de cursos:
<meta name="robots" content="index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1">Una sola etiqueta. La del plugin SEO. Sin duplicados, sin contradicciones. Revisé también las cabeceras HTTP con curl -I para confirmar que no hubiese una directiva X-Robots-Tag a nivel de servidor que pudiese interferir. Todo limpio.
En Google Search Console solicité la reinspección de las URLs más importantes y monitoricé el estado de indexación durante los días siguientes. Las primeras páginas volvieron al índice en menos de 72 horas. En diez días, la cobertura de indexación del sitio había recuperado su estado anterior. Un tema hijo que hereda código sin revisión puede arrastrar directivas invisibles durante semanas sin que nadie mire en la dirección correcta.

💡 Qué he aprendido
He aprendido que un tema hijo no solo hereda estilos y plantillas. Hereda todo lo que alguien haya dejado dentro de su functions.php, incluidas funciones que ya no tienen sentido en el contexto actual del sitio. Este caso me confirmó que la creación de un child theme no debería partir de una copia directa del archivo de funciones del tema padre, sino de un archivo limpio al que se añade solo lo necesario. Lo que se copia sin revisar acaba actuando sin que nadie lo vigile.
También he aprendido a no confiar únicamente en la configuración del plugin SEO para validar el estado de indexación. El plugin puede estar perfectamente configurado y aun así convivir con señales que lo contradicen desde otra capa. Inspeccionar el <head> renderizado debería ser una comprobación rutinaria después de cualquier cambio de tema o de plantilla activa.
La próxima vez que revise un tema derivado, lo primero que haré será leer su functions.php de principio a fin antes de buscar en cualquier otro sitio.
Cuaderno de WordPin
Forense WordPress
🧩 Notas técnicas
⬋⬋
Una academia online perdió visibilidad orgánica de forma gradual tras activar un tema hijo para personalizar sus plantillas. Las páginas de cursos y categorías de formación dejaron de aparecer en Google, mientras que el resto del sitio seguía indexado con normalidad.
La causa era un fragmento de código heredado en el functions.php del tema hijo, que inyectaba una meta etiqueta noindex en las plantillas de cursos con prioridad 1 en wp_head. La directiva se ejecutaba antes que la del plugin SEO y Google priorizaba la señal más restrictiva. Se retiró el bloque directamente del archivo, se verificó en staging y se confirmó la recuperación de la indexación en los días siguientes.
🔎 Pistas detectadas
⬋⬋
- Google Search Console mostraba URLs de cursos como rastreadas pero no indexadas, con motivo noindex explícito.
- El plugin SEO tenía la indexación correctamente habilitada para todos los tipos de contenido afectados.
- La opción
blog_publicenwp_optionsdevolvía valor 1, descartando el bloqueo desde ajustes de lectura. - El
<head>renderizado contenía dos etiquetas meta robots contradictorias: una con index y otra con noindex. - Query Monitor mostró en el listado de hooks disparados un callback registrado en
wp_headcon prioridad 1, cuyo componente de origen era el tema hijo activo.
🚫 Errores en WordPress detectados
⬋⬋
- Fragmento heredado en
functions.phpdel tema hijo inyectaba noindex en plantillas de cursos, bloqueando su indexación sin aviso visible en el panel. - Función anónima enganchada a
wp_headcon prioridad 1, ejecutándose antes que el plugin SEO e impidiendo cualquier sobreescritura posterior por configuración. - Duplicidad de meta etiquetas robots en el
<head>, provocando que Google aplicase la directiva más restrictiva de las dos presentes. - Creación del tema hijo mediante copia completa del
functions.phpdel padre, arrastrando lógica temporal que ya no tenía contexto en el sitio en producción. - Ausencia de validación del
<head>renderizado tras la activación del nuevo tema, lo que permitió que el problema pasase inadvertido durante semanas.
📘 Glosario de WordPress
⬋⬋
- tema hijo (child theme): tema que hereda funcionalidad y estilos de un tema padre, permitiendo personalizaciones sin modificar el original.
- wp_head: acción de WordPress que permite a temas y plugins inyectar código dentro de la etiqueta
<head>del HTML. - noindex: directiva de meta robots que indica a los buscadores que no incluyan la página en su índice de resultados.
- functions.php: archivo del tema activo donde se registran funciones, hooks y filtros que modifican el comportamiento de WordPress.
- closure anónima: función sin nombre declarado en PHP que, al registrarse con
add_action(), no puede eliminarse posteriormente conremove_action()sin una referencia directa al objeto.
📏 Mini guía práctica
⬋⬋
- Revisa el
functions.phpdel tema hijo línea por línea antes de activarlo, especialmente si fue creado copiando archivos del tema padre. - Inspecciona el
<head>renderizado en el navegador después de cada cambio de tema para detectar etiquetas duplicadas o contradictorias. - Usa Query Monitor y localiza en su panel de hooks el listado de callbacks disparados durante
wp_head: muestra prioridad y componente de origen para cada uno. - Comprueba en Google Search Console el estado de indexación de los tipos de contenido principales tras cualquier cambio en el tema activo.
- Crea los temas hijo siempre desde un
functions.phpvacío, añadiendo únicamente las funciones que necesitas personalizar y documentando cualquier decisión de retirada de código.
Deja una respuesta
La etiqueta canonical que mentía · Serpion 007
SEO desde cero y el cliente que lo desconocía · Serpion 000
Expedientes y Archivos