Creating breadcrumbs without plugin WordPress

25,673

Solution 1

WordPress doesn't provide builtin breadcrumbs functionality. Thus you'll have to either use a plugin or else code it yourself (or copy from the reference below).

As a matter of fact, the plugin or custom code, if providing similar functionality, make not much of a difference. Thus use the one which is more convenient for you.

If you would like to add a custom code, here are few resources which I could look up on search:

https://www.techpulsetoday.com/wordpress-breadcrumbs-without-plugin/

https://www.thewebtaylor.com/articles/wordpress-creating-breadcrumbs-without-a-plugin

https://www.codexworld.com/wordpress-how-to-display-breadcrumb-without-plugin/

https://gist.github.com/tinotriste/5387124

You can look into them and modify them as you wish!

I hope it helps!

Solution 2

I can't understand how an answer with only pasted links can get to that many upvote. The regular WordPress breadcrumb approach is painfully unoptimized, most of the one out there do not suit custom themes. I decided to built a URL based breadcrumb which is, from my point of view, far more efficient and adaptable. I wanted something generic, SEO friendly, without any default styling. It needed also to properly handle posts and pages title.

Version
Requires at least WordPress: 3.0.0
Requires PHP: 8.0
Tested up to WordPress: 5.8.2

The latest version is available on my GitHub as an unofficial WordPress plugin.

<?php

if ( ! function_exists( 'get_the_crumbs' ) ) {

    /**
     * Retrieve the crumbs.
     * 
     * @since 1.0.0
     *
     * @return Array Crumbs array.
     */
    function get_the_crumbs() {

        $flour = $_SERVER['REQUEST_URI'];

        if ( str_contains( $flour, '?' ) ) {

            $flour = substr( $flour, 0, strpos( $flour, '?' ) );

        };

        if ( str_ends_with( $flour, '/' ) ) {

            $flour = explode( '/', substr( $flour, 1, -1 ) );

        } else {

            $flour = explode( '/', substr( $flour, 1 ) );

        };

        $crumbs = array();

        foreach ( $flour as $crumb ) {

            $slug = esc_html( $crumb );

            $url = esc_url( $_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['HTTP_HOST'] . '/' . substr( implode( '/', $flour ), 0, strpos( implode( '/', $flour ), $crumb ) ) . $crumb. '/' );

            array_push( $crumbs, 
                array(
                    'slug' => $slug,
                    'url' => $url,
                )
            );

        };

        $banned_slugs = array();
        
        //round up all post types
        $post_types = get_post_types( 
            array(
                'public' => true,
            ),
            'objects'
        );

        foreach ( $post_types as $post_type ) {

            array_push( $banned_slugs, $post_type->name );

            if ( isset( $post_type->rewrite['slug'] ) ) array_push( $banned_slugs, $post_type->rewrite['slug'] );

        };

        //round up all taxonomies
        $taxonomies = get_taxonomies( 
            array(
                'public' => true,
            ),
            'objects'
        );
        
        foreach ( $taxonomies as $taxonomy ) {

            array_push( $banned_slugs, $taxonomy->name );
            
            if ( isset( $taxonomy->rewrite['slug'] ) ) array_push( $banned_slugs, $taxonomy->rewrite['slug'] );

        };

        $banned_crumbs = array();

        foreach ( $banned_slugs as $banned_slug ) {

            $slug = esc_html( $banned_slug );

            $url = esc_url( $_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['HTTP_HOST'] . '/' . substr( implode( '/', $flour ), 0, strpos( implode( '/', $flour ), $banned_slug ) ) . $banned_slug. '/' );

            array_push( $banned_crumbs, 
                array(
                    'slug' => $slug,
                    'url' => $url,
                )
            );

        };

        $crumbs = array_filter( $crumbs, function( $crumb ) use ( $banned_slugs ) {

            if ( ! in_array( $crumb['slug'], $banned_slugs ) && ! in_array( $crumb['url'], $banned_slugs ) ) {

                return ! in_array( $crumb['slug'], $banned_slugs );

            };

        } );

        return $crumbs;

    };

};

if ( ! function_exists( 'the_bread' ) ) {

    /**
     * Display the bread, a formatted crumbs list.
     * 
     * @since 1.0.0
     * 
     * @param   Array   $ingredients                    The bread arguments.
     * @param   Array   $ingredients['root']            Root crumb. Default to null.
     * @param   String  $ingredients['root']['slug']    Root crumb slug.
     * @param   String  $ingredients['root']['url']     Root crumb url.
     * @param   String  $ingredients['separator']       The crumb's separator. The separator is not escaped.
     * @param   Integer $ingredients['offset']          Crumbs offset. Accept positive/negative Integer. Default to "0". Refer to array_slice, https://www.php.net/manual/en/function.array-slice.php.
     * @param   Integer $ingredients['length']          Crumbs length. Accept positive/negative Integer. Default to "null". Refer to array_slice, https://www.php.net/manual/en/function.array-slice.php.
     * 
     * @return  Array   The formatted crumbs list.
     */
    function the_bread( $ingredients = array() ) {

        $root = ( empty( $ingredients['root'] ) ? null : $ingredients['root'] );

        $offset = ( empty( $ingredients['offset'] ) ? 0 : $ingredients['offset'] );

        $length = ( empty( $ingredients['length'] ) ? null : $ingredients['length'] );

        $crumbs = get_the_crumbs();

        if ( ! empty( $root ) ) {

            array_unshift( $crumbs, $ingredients['root'] );

        };

        $crumbs = array_slice( $crumbs, $offset, $length );

        if ( ! empty( $crumbs ) ) {

            echo '<ol class="🍞 bread" itemscope itemtype="https://schema.org/BreadcrumbList">';

            $i = 0;
            
            foreach ( $crumbs as $crumb ) {

                $i++;

                if ( url_to_postid( $crumb['url'] ) ) {

                    $title = get_the_title( url_to_postid( $crumb['url'] ) );

                } elseif ( get_page_by_path( $crumb['slug'] ) ) {

                    $title = get_the_title( get_page_by_path( $crumb['slug'] ) );

                } else {
  
                    $title = ucfirst( str_replace( '-', ' ', $crumb['slug'] ) );

                };

                echo '<li class="crumb" itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
                    <a itemprop="item" href="' . $crumb['url'] . '">
                        <span itemprop="name">' . $title . '</span>
                    </a>
                    <meta itemprop="position" content="' . $i . '">
                </li>';

                if ( $i !== sizeof( $crumbs ) && ! empty( $ingredients['separator'] ) ) {

                    echo $ingredients['separator'];

                };
    
            };
    
            echo '</ol>';

        };

    };

};

Displaying the bread, a formatted crumbs list.

<?php

the_bread( $ingredients = array() );

Parameters

Parameter Description
$ingredients (Optional) Array of arguments for displaying the bread.
$ingredients['root'] Array Root crumb. Default to null.
$ingredients['root']['slug'] (Required if $ingredients['root']). Root crumb slug.
$ingredients['root']['url'] (Required if $ingredients['root']). Root crumb url.
$ingredients['separator'] The crumb's separator. The separator is not escaped.
$ingredients['offset'] Crumbs offset. Accept positive/negative Integer. Default to 0. Refer to array_slice.
$ingredients['length'] Crumbs length. Accept positive/negative Integer. Default to null. Refer to array_slice.

Example: The bread with a custom separator

<?php

$ingredients = array(
    'separator' => '→',
);

the_bread( $ingredients );

Example: Displaying the last 3 crumbs

<?php

$ingredients = array(
    'offset' => -3,
    'length' => 3,
);

the_bread( $ingredients );

Example: The bread with a root crumb

<?php

$ingredients = array(
    'root' => array(
        'slug' => 'home',
        'url' => get_home_url(),
    ),
);

the_bread( $ingredients );

HTML5 structure output

<ol class="🍞 bread" itemscope="" itemtype="https://schema.org/BreadcrumbList">
    <li class="crumb" itemprop="itemListElement" itemscope="" itemtype="https://schema.org/ListItem">
        <a itemprop="item" href="http://example.com/where/">
            <span itemprop="name">Where</span>
        </a>
        <meta itemprop="position" content="1">
    </li>
    >
    <li class="crumb" itemprop="itemListElement" itemscope="" itemtype="https://schema.org/ListItem">
        <a itemprop="item" href="http://example.com/where/is/">
            <span itemprop="name">Is</span>
        </a>
        <meta itemprop="position" content="2">
    </li>
    >
    <li class="crumb" itemprop="itemListElement" itemscope="" itemtype="https://schema.org/ListItem">
        <a itemprop="item" href="http://example.com/where/is/my/">
            <span itemprop="name">My</span>
        </a>
        <meta itemprop="position" content="3">
    </li>         
    >
    <li class="crumb" itemprop="itemListElement" itemscope="" itemtype="https://schema.org/ListItem">
        <a itemprop="item" href="http://example.com/where/is/my/bread/">
            <span itemprop="name">Bread</span>
        </a>
        <meta itemprop="position" content="4">
    </li>
</ol>

Minimal css boilerplate (Optional)

.🍞,
.bread {
  list-style-type: none;
  margin:0;
  padding:0;
}

.🍞 li,
.bread li {
  display:inline-block;
}

.🍞 li.crumb:last-child a,
.bread li.crumb:last-child a {
  text-decoration: none;
  pointer-events: none;
  color: inherit;
}

Retrieving the crumbs

Even tho we recommend you to use the_bread() function to display and build your own breadcrumb, you can use get_the_crumbs() to retrieve the crumbs object.

Example: Outputting the crumbs object

<?php

var_dump( get_the_crumbs() );
Share:
25,673
GANESH JAGDHANE
Author by

GANESH JAGDHANE

Updated on July 29, 2022

Comments

  • GANESH JAGDHANE
    GANESH JAGDHANE over 1 year

    How can i create breadcrumb home->page->post name when we click on main menu any page, open the list of post that time breadcrumb create home ->page name its ok but now when we click on any post that time breadcrumb create home->post category name->post name is is that when we click on post category name on breadcrumb layout shown different we want to its goes on page link, not category link. so we need to when we open any post we need to create the breadcrumb like this home->page name->post name so when we click on page name open the post list page, not category page.

  • Vörös Imi
    Vörös Imi almost 5 years
    1st one works without a hitch. Bonus - it's nice and compact, doesn't do that irritating spaced out code thing.
  • That Brazilian Guy
    That Brazilian Guy almost 4 years
    Link-only answers should be avoided.
  • InanisAtheos
    InanisAtheos almost 3 years
    This is really neat and light-weight. The only problem I've seen thus farr, is that there isn't any handling of static permalink parts, such as /category/ which doesn't have any content, nor a page ID. I could probably customize it to not print those out though.
  • InanisAtheos
    InanisAtheos almost 3 years
    I didn't notice the Github link, nor that there is a later version. I'll have a look. And yea I could create that page I guess. However I solved it with an array of "banned" links to check against before printing the results.
  • amarinediary
    amarinediary over 2 years
    @Athoxx Version 1.0.3 automatically filter out posts types and taxonomies root crumbs.
  • InanisAtheos
    InanisAtheos over 2 years
    awesome, I'll check it out when I'm back on a WP project :)