Como crear breadcrumbs simples sin plugins en PHP en WordPress

Contents

Introducción: ¿Por qué implementar breadcrumbs sin plugins?

Los breadcrumbs (migas de pan) son una ayuda visual y de navegación muy útil en sitios WordPress: mejoran la experiencia de usuario, la accesibilidad y el SEO al mostrar la jerarquía de la página. Usar un plugin no siempre es necesario: con unas pocas líneas de PHP en tu tema puedes crear breadcrumbs simples, ligeros y personalizables, sin sobrecargar la instalación.

Requisitos y dónde colocar el código

Este tutorial asume conocimientos básicos de WordPress y PHP. El código que verás lo puedes añadir en el archivo functions.php de tu tema (o mejor aún, del tema hijo), o encapsularlo en un pequeño plugin si prefieres mantener el código separado del tema.

Objetivos de la función

  • Soportar: página de inicio, entradas individuales, páginas anidadas (padres), categorías, etiquetas, taxonomías personalizadas, archivos de tipo de entrada personalizada, archivos por fecha, autor, búsqueda y 404.
  • Manejo de paginación (page 2, etc.).
  • Opciones configurables: separador, etiqueta de inicio, mostrar/ocultar la página actual y posibilidad de devolver el HTML o imprimirlo directamente.
  • Salida semántica y ligera, fácil de estilizar vía CSS.

Función completa: breadcrumbs simples para WordPress

Inserta la siguiente función en functions.php. Ajusta las opciones por defecto según tus necesidades.

  / ,
        home_label     => Inicio,
        show_on_home   => true,     // mostrar breadcrumb sólo en home?
        show_current   => true,     // mostrar título de la página actual
        echo           => true,     // imprimir directamente o devolver string
        before         => ,       // texto antes del título actual
        after          => ,       // texto después del título actual
    )
    opts = wp_parse_args( args, defaults )

    // No hacer nada si estamos en la página de inicio y no queremos mostrar
    if ( ( is_front_page()  is_home() )  ! opts[show_on_home] ) {
        return
    }

    breadcrumbs = array()

    // Añadir enlace a inicio
    home_url = home_url( / )
    breadcrumbs[] =  . esc_html( opts[home_label] ) . 

    if ( is_front_page()  ! is_home() ) {
        // Página estática como front page
        if ( opts[show_current] ) {
            breadcrumbs[] = opts[before] . get_the_title( get_option(page_on_front) ) . opts[after]
        }
    } elseif ( is_home()  ! is_front_page() ) {
        // Página principal del blog (listado de entradas)
        blog_label = get_the_title( get_option(page_for_posts) ) ? get_the_title( get_option(page_for_posts) ) : Blog
        breadcrumbs[] = opts[before] . esc_html( blog_label ) . opts[after]
    } elseif ( is_single() ) {
        post = get_post()
        post_type = get_post_type( post )

        if ( post_type != post ) {
            // Post type personalizado: mostrar enlace al archivo del CPT si existe
            pt_obj = get_post_type_object( post_type )
            if ( pt_obj ) {
                archive_link = get_post_type_archive_link( post_type )
                if ( archive_link ) {
                    breadcrumbs[] =  . esc_html( pt_obj->labels->name ) . 
                } else {
                    // Si no hay archivo, enlazar al singular label
                    breadcrumbs[] = esc_html( pt_obj->labels->singular_name )
                }
            }
        } else {
            // Post tipo post: mostrar categorías (primera)
            categories = get_the_category( post->ID )
            if ( ! empty( categories ) ) {
                // Ordenar por jerarquía, usar la primero que devuelva WordPress
                category = categories[0]
                category_links = array()
                anc = get_ancestors( category->term_id, category )
                anc = array_reverse( anc )
                foreach ( anc as cat_id ) {
                    cat = get_category( cat_id )
                    category_links[] = term_id ) ) . > . esc_html( cat->name ) . 
                }
                category_links[] = term_id ) ) . > . esc_html( category->name ) . 
                breadcrumbs = array_merge( breadcrumbs, category_links )
            }
        }

        // Añadir título de la entrada actual
        if ( opts[show_current] ) {
            breadcrumbs[] = opts[before] . get_the_title() . opts[after]
        }

    } elseif ( is_page() ) {
        // Páginas: mostrar jerarquía de padres
        global post
        if ( post->post_parent ) {
            anc = get_post_ancestors( post->ID )
            anc = array_reverse( anc )
            foreach ( anc as ancestor_id ) {
                breadcrumbs[] =  . esc_html( get_the_title( ancestor_id ) ) . 
            }
        }
        if ( opts[show_current] ) {
            breadcrumbs[] = opts[before] . get_the_title() . opts[after]
        }

    } elseif ( is_category() ) {
        cat = get_queried_object()
        if ( cat->parent ) {
            anc = get_ancestors( cat->term_id, category )
            anc = array_reverse( anc )
            foreach ( anc as cat_id ) {
                c = get_category( cat_id )
                breadcrumbs[] = term_id ) ) . > . esc_html( c->name ) . 
            }
        }
        breadcrumbs[] = opts[before] . single_cat_title( , false ) . opts[after]

    } elseif ( is_tag() ) {
        breadcrumbs[] = opts[before] . single_tag_title( , false ) . opts[after]

    } elseif ( is_tax() ) {
        // Taxonomía personalizada
        term = get_queried_object()
        taxonomy = get_taxonomy( term->taxonomy )
        // Si la taxonomía tiene jerarquía
        if ( term->parent ) {
            anc = get_ancestors( term->term_id, term->taxonomy )
            anc = array_reverse( anc )
            foreach ( anc as term_id ) {
                t = get_term( term_id, term->taxonomy )
                breadcrumbs[] =  . esc_html( t->name ) . 
            }
        }
        breadcrumbs[] = opts[before] . esc_html( term->name ) . opts[after]

    } elseif ( is_author() ) {
        author = get_queried_object()
        breadcrumbs[] = opts[before] . esc_html( author->display_name ) . opts[after]

    } elseif ( is_search() ) {
        breadcrumbs[] = opts[before] . sprintf( Resultados de búsqueda: %s, get_search_query() ) . opts[after]

    } elseif ( is_day() ) {
        breadcrumbs[] =  . get_the_time(Y) . 
        breadcrumbs[] =  . get_the_time(F) . 
        breadcrumbs[] = opts[before] . get_the_time(d) . opts[after]

    } elseif ( is_month() ) {
        breadcrumbs[] =  . get_the_time(Y) . 
        breadcrumbs[] = opts[before] . get_the_time(F) . opts[after]

    } elseif ( is_year() ) {
        breadcrumbs[] = opts[before] . get_the_time(Y) . opts[after]

    } elseif ( is_post_type_archive() ) {
        post_type = get_query_var( post_type )
        if ( is_array( post_type ) ) {
            post_type = reset( post_type )
        }
        pt_obj = get_post_type_object( post_type )
        if ( pt_obj ) {
            breadcrumbs[] = opts[before] . esc_html( pt_obj->labels->name ) . opts[after]
        }

    } elseif ( is_404() ) {
        breadcrumbs[] = opts[before] . 404 . opts[after]
    }

    // Paginación: si hay paged
    paged = get_query_var( paged )
    if ( paged  paged > 1 ) {
        breadcrumbs[] = Página  . intval( paged )
    }

    // Construir salida uniendo con separador
    output = implode( opts[separator], breadcrumbs )

    // Envolver en 

para salida (es sencillo y fácil de estilizar) html =

if ( opts[echo] ) { echo html } else { return html } } ?>

Cómo llamar a la función desde las plantillas

Coloca la llamada en el archivo de tu tema donde quieras que aparezcan las migas (por ejemplo header.php, single.php, page.php o dentro de un template-part):


Si prefieres devolver el HTML para manipularlo antes de imprimir:

 false ) )
echo 
. bc_html .
?>

Ejemplos de configuración

  • Usar separador > y ocultar la última parte:
      > , show_current => false ) ) ?>
    
  • Etiqueta de inicio personalizada y devolver HTML:
     Mi Sitio, echo => false ) ) ?>
    

Estilos CSS recomendados

Este CSS básico te ayudará a que las migas se vean bien en la mayoría de los temas. Ajusta colores, tamaños y espaciado según tu diseño.

.breadcrumbs {
  font-size: 13px
  color: #666
  margin: 12px 0
}
.breadcrumbs a {
  color: #0073aa
  text-decoration: none
}
.breadcrumbs a:hover {
  text-decoration: underline
}
.breadcrumbs a:after {
  / nada aquí: el separador lo pone PHP si prefieres, elimina separador en PHP y lo añades con CSS /
}

Consideraciones y mejoras

  1. Accesibilidad: hemos usado aria-label en el párrafo si prefieres una estructura más semántica, usa un elemento nav con role y list items, pero si tu theme requiere solo etiquetas permitidas, mantén p y enlaces con texto claro.
  2. Schema.org: para SEO puedes añadir microdatos (itemtype/itemprop) a los enlaces o generar JSON-LD. Si necesitas microdatos, recuerda adaptar los atributos de las etiquetas HTML en la función.
  3. Rendimiento: esta implementación es muy ligera frente a plugins que añaden funciones extra. Es apta para la mayoría de sitios.
  4. Soporte para taxonomías complejas: la función incluye manejo básico de taxonomías jerárquicas si tu proyecto tiene taxonomías no jerárquicas o reglas especiales, añade los casos específicos.
  5. Internacionalización: para proyectos multilenguaje, envuelve etiquetas estáticas en funciones __() o _e() y asegúrate de traducir Inicio u otros textos.

Casos prácticos y notas sobre comportamiento

  • Páginas anidadas: la función recorre ancestros con get_post_ancestors y los muestra en orden jerárquico.
  • Entradas: intenta mostrar la categoría principal si deseas otra lógica (por ejemplo la categoría más profunda o la favorita), modifica la selección de categoría.
  • Custom Post Types (CPT): si tu CPT tiene archivo habilitado, la función enlaza al archivo del CPT y muestra su label. Si no tiene archivo, muestra el label singular.
  • Paginación: añade Página X si el query está paginado.
  • 404: muestra simplemente 404 para que el usuario sepa dónde está.

Conclusión

Con unas decenas de líneas en functions.php tienes un breadcrumb funcional, ligero y personalizable, sin necesidad de instalar plugins. La función es una base sólida: puedes extenderla añadiendo microdatos, mejorando la lógica de selección de categoría para posts, o integrando con frameworks de temas.



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 *