Como añadir la etiqueta canonical correcta con PHP en WordPress

Contents

Introducción

En SEO, la etiqueta rel=canonical indica a los motores de búsqueda cuál es la URL canónica (preferida) para una página concreta, evitando problemas de contenido duplicado y consolidando señales de enlace. WordPress añade una canonical por defecto en muchas instalaciones, pero en entornos con contenido personalizado, paginación avanzada, parámetros, taxonomías o búsquedas, a menudo conviene generar y normalizar manualmente la URL canonical mediante PHP.

Objetivos de este tutorial

  • Explicar cuándo y por qué añadir una canonical personalizada en WordPress.
  • Proveer un ejemplo simple y un ejemplo avanzado (cubriendo singulars, taxonomías, archivos, paginación, attachments y parámetros).
  • Mostrar cómo evitar conflictos con plugins SEO (Yoast, Rank Math) y cómo normalizar urls (https, www, trailing slash, parámetros de tracking).

Conceptos clave y buenas prácticas

  • Canonical por defecto: WordPress core tiene una función rel_canonical() que se engancha a wp_head. En muchos casos basta con esto, pero cuando necesitas control total conviene reemplazarla.
  • Normalización: Decide una única forma de URL (https vs http, www vs no-www, trailing slash) y asegúrate de que la canonical la refleje.
  • Paginación: Puedes apuntar la canonical a la propia URL paginada (recomendado por muchos desarrolladores hoy) o al primer volumen lo importante es ser consistente y usar rel=prev/next si corresponde.
  • Parametros: Quitar parámetros de tracking (utm_) de la canonical para no crear duplicados.
  • Compatibilidad con plugins SEO: No dupliques etiquetas si Yoast/RankMath ya generan la canonical detecta y evita añadir otra.

Lista rápida de funciones útiles de WordPress

Condición Función para obtener URL
Entrada/Página/CPT get_permalink()
Home / Front page home_url(/)
Archivo de taxonomy get_term_link()
Archivo de post type get_post_type_archive_link()
Autor get_author_posts_url()
Paginas con paginación get_pagenum_link()
Quitar parámetros remove_query_arg()

Implementación: Ejemplo simple

Esta primera versión cubre los casos más comunes: singulares, home, taxonomías y autor. También elimina parámetros UTM y normaliza con user_trailingslashit.

ID )
    } elseif ( is_front_page()  is_home() ) {
        canonical = home_url( / )
    } elseif ( is_category()  is_tag()  is_tax() ) {
        term = get_queried_object()
        canonical = get_term_link( term )
    } elseif ( is_author() ) {
        author = get_queried_object()
        canonical = get_author_posts_url( author->ID )
    } else {
        // Fallback a la URL actual
        canonical = home_url( add_query_arg( NULL, NULL ) )
    }

    // Quitar parámetros comunes de tracking
    canonical = remove_query_arg( array( utm_source, utm_medium, utm_campaign, utm_term, utm_content ), canonical )

    // Normalizar trailing slash según la instalación
    canonical = user_trailingslashit( canonical )

    echo n
}
?>

Notas sobre este ejemplo

  • remove_action() evita que WordPress inyecte su canonical por defecto si quieres la tuya.
  • La detección de plugins es básica (WPSEO_VERSION para Yoast y la existencia de la clase RankMathPlugin para Rank Math). Si tu plugin SEO es otro, añade su comprobación.

Implementación avanzada: cubrir paginación, attachments, parámetros dinámicos y normalización HTTPS/WWW

El siguiente ejemplo es robusto: maneja paginación (opción para canonical a self o al first page), attachments (canonical a parent o a sí misma si no hay parent), taxonomías, archives de CPT, autor, búsqueda y 404 y normaliza parámetros y esquemas.

post_parent ) {
                canonical = get_permalink( post->post_parent )
            } else {
                canonical = get_permalink( post->ID )
            }
        } else {
            canonical = get_permalink( post->ID )
        }

    } elseif ( is_front_page()  is_home() ) {
        canonical = home_url( / )

    } elseif ( is_category()  is_tag()  is_tax() ) {
        term = get_queried_object()
        canonical = get_term_link( term )

    } elseif ( is_post_type_archive() ) {
        post_type = get_query_var( post_type )
        canonical = get_post_type_archive_link( post_type )

    } elseif ( is_author() ) {
        author = get_queried_object()
        canonical = get_author_posts_url( author->ID )

    } elseif ( is_search() ) {
        // Opcional: decidir si indexas búsquedas. Frecuente: noindex   evitar canonical.
        // Si quieres canonicalizar búsquedas a home o a sí misma, ajusta aquí.
        return
    } else {
        // Fallback a la URL actual
        canonical = home_url( add_query_arg( NULL, NULL ) )
    }

    // Paginación: decidir política
    paged = get_query_var( paged ) ? intval( get_query_var( paged ) ) : 0
    use_self_for_paged = true // si true -> cada página paginada se canonicaliza a sí misma
    if ( paged > 1 ) {
        if ( use_self_for_paged ) {
            canonical = get_pagenum_link( paged )
        } else {
            // canonical al primer volumen (sin paginación)
            if ( is_singular() ) {
                canonical = get_permalink()
            } else {
                // para archives usa la versión sin paged
                canonical = remove_query_arg( paged, canonical )
            }
        }
    }

    // Quitar parámetros de tracking y algunos parámetros innecesarios
    canonical = remove_query_arg( array( utm_source, utm_medium, utm_campaign, utm_term, utm_content, fbclid ), canonical )

    // Forzar https y/o no-www si tu sitio está configurado así. Ejemplo: forzar scheme y host de home_url()
    home = parse_url( home_url( / ) )
    parsed = wp_parse_url( canonical )
    if ( isset( home[scheme] )  isset( home[host] ) ) {
        parsed[scheme] = home[scheme]
        parsed[host]   = home[host]
    }
    // Reconstruir la URL normalizada
    norm = ( isset( parsed[scheme] ) ? parsed[scheme] . :// :  ) .
            ( isset( parsed[host] ) ? parsed[host] :  ) .
            ( isset( parsed[path] ) ? parsed[path] :  ) .
            ( isset( parsed[query] ) ? ? . parsed[query] :  ) .
            ( isset( parsed[fragment] ) ? # . parsed[fragment] :  )

    // Aplicar trailing slash según la configuración de WP
    norm = user_trailingslashit( norm )

    echo n
}
?>

Explicaciones importantes del ejemplo avanzado

  • get_pagenum_link() devuelve la URL correcta para páginas paginadas y respeta la estructura de enlaces permanentes.
  • remove_query_arg() elimina parámetros de tracking que no aportan significado al contenido.
  • El bloque que fuerza scheme/host al valor de home_url() evita inconsistencias entre http/https o www/no-www en la canonical.
  • La variable use_self_for_paged te permite elegir la estrategia de paginación la documentación de Google ha variado con el tiempo, pero lo más importante es ser consistente y no generar duplicados.

Compatibilidad con plugins SEO

Si tu sitio usa Yoast SEO, Rank Math u otros plugins, normalmente éstos ya generan la etiqueta canonical (y añaden otras metaetiquetas importantes). Recomendación:

  1. Comprobar si el plugin ya añade canonical. Si es así, no añadir una segunda etiqueta para evitar duplicados.
  2. Si el plugin lo genera pero quieres customizar sólo ciertos casos, detecta la presencia del plugin y aplica tu lógica sólo cuando sea necesario.
  3. Para Yoast puedes comprobar defined(WPSEO_VERSION) o la existencia de funciones/clases propias. Para Rank Math, la existencia de la clase RankMathPlugin.

Pruebas y verificación

  1. Inspeccionar el código fuente en el front (ctrl U) y comprobar que sólo hay una etiqueta rel=canonical y que su href coincide con la URL normalizada deseada.
  2. Probar tipos de páginas: home, posts, páginas, attachments, categorías, etiquetas, taxonomías personalizadas, archivos de post type, autor, búsqueda, 404, y páginas paginadas.
  3. Verificar con la Google Search Console (inspección de URLs) y herramientas de crawling (Screaming Frog, Sitebulb) que las canonicales se leen correctamente.
  4. Comprobar redirecciones y versiones www/no-www y https para que la canonical coincida con la versión que devuelve 200 y no con la que redirige.

Errores y problemas comunes

  • Añadir múltiples canonicales (core plugin tu código). Evitar duplicados detectando plugins o no llamando a remove_action si confías en Core/plugin.
  • Canonical que apunta a la página 1 desde todas las páginas paginadas, provocando pérdida de indexación de contenido paginado si no se usa rel=prev/next correctamente.
  • Dejar parámetros de tracking en la canonical (utm_, fbclid) creando URLs distintas para el mismo contenido.
  • Canonical a una URL que devuelve redirección en lugar de 200 — siempre canonicalizar a la URL final (200).

Resumen / Checklist de implementación

  1. Decide si usarás la canonical que genera WordPress core, un plugin SEO o tu propio código.
  2. Si implementas tu propia canonical, elimina la que no quieras (remove_action) para evitar duplicados.
  3. Gestiona casos: singular, attachment, taxonomy, author, archives y paginación.
  4. Quita parámetros de tracking y normaliza esquema/host/trailing-slash.
  5. Comprueba compatibilidad con Yoast/RankMath antes de inyectar tu etiqueta.
  6. Verifica con herramientas y Google Search Console.

Enlaces útiles

Conclusión

Implementar una etiqueta rel=canonical correcta en WordPress con PHP requiere entender los distintos tipos de página, decidir una política de normalización (scheme/host/trailing slash) y manejar paginación y parámetros. Con los ejemplos provistos (simple y avanzado) tienes una base sólida para personalizar la canonical según las necesidades de tu proyecto y evitar problemas de contenido duplicado. Aplica las comprobaciones de plugins SEO, prueba en todas las plantillas y verifica en Search Console para asegurarte de que Google entiende la URL preferida.



Acepto donaciones de BAT's mediante el navegador Brave 🙂



Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *