Skip to Content
Menu

breadcrumbs()

This custom breadcrumb function allows for easy addition of a site breadcrumb to any page.

PHP March 26, 2019

Usage

PHP
nebula()->breadcrumbs($options)

Parameters

$options
(Optional) (Array) An array of options
Default: None

Parameter Notes

Options

delimiter
The string between nodes.
Default: /

home
Text for the home link
Default: get_bloginfo('title')

home_link
The URL for the home link
Default: home_url('/')

prefix
What type of prefix to use before certain post types (categories, tags, etc.). Ex: text, icons, off (or false)
Default: text

current
Show or hide the current title in the breadcrumb
Default: true

before
Tag before the current node
Default: <span class="current">

after
Tag after the current crumb
Default: </span>

force
Override the breadcrumbs with an array of specific links (See example below)
Default: false

Request or provide clarification »

Examples

Simple Implementation

PHP
<?php nebula()->breadcrumbs(); ?>

Replace the delimiter and home link with text

PHP
<?php nebula()->breadcrumbs(array('delimiter' => '&raquo;', 'home' => '<i class="fas fa-home"></i>')); ?>

Replace the delimiter and home text, and also manually control the nodes. Notice the current page is not passed in the 'force' option; it is controlled by the 'current' option which defaults to true (so it is not passed here).

PHP
<?php
    nebula()->breadcrumbs(array(
        'home' => '<i class="fas fa-home"></i>',
        'delimiter' => '&raquo;',
        'force' => array(
            array('Home', home_url()),
            array(get_the_title(127), get_permalink(127)),
            array(get_field('product_type'), get_permalink(get_page_by_title(get_field('product_type')))),
        ),
    ));
?>

Disable prefixes for categories and tags

PHP
<?php nebula()->breadcrumbs(array('prefix' => false)); ?>

Change settings globally by changing default parameters across the entire site

PHP
<?php
    //Add this to a functions file
    add_filter('nebula_breadcrumb_defaults', function($defaults){
        $defaults['delimiter'] = '&rsaquo;';
        $defaults['home'] = '<i class="fas fa-home"></i>';
        return $defaults;
    });

    //Now it can be called in template files without parameters:
    nebula()->breadcrumbs();
?>
Was this page helpful? Yes No


    A feedback message is required to submit this form.


    Please check that you have entered a valid email address.

    Enter your email address if you would like a response.

    Thank you for your feedback!

    Source File

    Located in /libs/Functions.php on line 1391.

    7 Hooks

    Find these filters and actions in the source code below to hook into them. Use do_action() and add_filter() in your functions file or plugin.

    Filters
    "pre_nebula_breadcrumbs"
    "nebula_breadcrumb_defaults"
    "nebula_breadcrumbs_category"
    "nebula_breadcrumbs_tag"
    "nebula_breadcrumbs_author"
    "nebula_breadcrumbs_error"
    "nebula_breadcrumbs_paged"
    Need a new filter hook? Request one here.

    Actions
    This function has no action hooks available. Request one?

    Note: This function contains 4 to-do comments.

    PHP
            public function breadcrumbs($options=array()){
                $override = apply_filters('pre_nebula_breadcrumbs', null);
                if ( isset($override) ){return;}
    
                $this->timer('Breadcrumbs');
    
                global $post;
                $defaults = apply_filters('nebula_breadcrumb_defaults', array(
                    'delimiter' => '/', //Delimiter between crumbs
                    'home' => get_bloginfo('title'), //Text for the 'Home' link
                    'home_link' => home_url('/'),
                    'prefix' => 'off', //Prefix categories and tags with "text", "icon", or none with "off" (default)
                    'current' => true, //Show/Hide the current title in the breadcrumb
                    'before' => '<li class="current" itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem">', //Tag before the current crumb
                    'after' => '</li>', //Tag after the current crumb
                    'force' => false //Override the breadcrumbs with an array of specific links
                ));
    
                $data = array_merge($defaults, $options);
                $data['delimiter_html'] = '<li class="delimiter">' . $data['delimiter'] . '</li>';
                $data['current_node'] = $data['before'] . '<a class="current-breadcrumb-link" href="' . get_the_permalink() . '" itemprop="item"><span itemprop="name">' . strip_tags(get_the_title()) . '</span></a>';
                $position = 1; //Incrementer for each node (for schema tags)
    
                if ( !empty($data['force']) ){ //If using forced override
                    echo '<ol class="nebula-breadcrumbs" itemscope itemtype="http://schema.org/BreadcrumbList">';
    
                    foreach ( $data['force'] as $node ){
                        $node_text = ( !empty($node['text']) )? $node['text'] : $node[0];
                        $node_url = false;
                        if ( !empty($node['url']) ){
                            $node_url = $node['url'];
                        } else {
                            if ( !empty($node[1]) ){
                                $node_url = $node[1];
                            }
                        }
    
                        if ( !empty($node_text) ){
                            if ( !empty($node_url) ){
                                echo '<li itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a href="' . $node_url . '" itemprop="item">';
                            }
    
                            echo '<span itemprop="name">' . $node_text . '</span>';
    
                            if ( !empty($node_url) ){
                                echo '</a><meta itemprop="position" content="' . $position . '" /></li>';
                            }
    
                            echo ' ' . $data['delimiter_html'] . ' ';
                        }
    
                        $position++;
                    }
    
                    if ( !empty($data['current']) ){
                        echo $data['current_node'] . '<meta itemprop="position" content="' . $position . '" />' . $data['after'];
                    }
    
                    echo '</ol>';
                } elseif ( is_home() || is_front_page() ){
                    echo '<ol class="nebula-breadcrumbs" itemscope itemtype="http://schema.org/BreadcrumbList"><li itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a href="' . $data['home_link'] . '" itemprop="item"><span itemprop="name">' . $data['home'] . ' <span class="visually-hidden">' . get_bloginfo('title') . '</span></span></a><meta itemprop="position" content="' . $position . '" /></li></ol>';
                    $position++;
                    return false;
                } else {
                    echo '<ol class="nebula-breadcrumbs" itemscope itemtype="http://schema.org/BreadcrumbList"><li itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a href="' . $data['home_link'] . '" itemprop="item"><span itemprop="name">' . $data['home'] . ' <span class="visually-hidden">' . get_bloginfo('title') . '</span></span></a><meta itemprop="position" content="' . $position . '" /></li> ' . $data['delimiter_html'] . ' ';
                    $position++;
    
                    if ( is_category() ){
                        $thisCat = get_category(get_query_var('cat'), false);
                        if ( $thisCat->parent !== 0 ){
                            $parents = get_ancestors($thisCat->parent, 'category', 'taxonomy');
                            array_unshift($parents, $thisCat->parent);
                            foreach ( array_reverse($parents) as $term_id ){
                                $parent = get_term($term_id, 'category');
                                echo '<li itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a href="' . esc_url(get_term_link($parent->term_id, 'category')) . '" itemprop="item"><span itemprop="name">' . $parent->name . '</span></a><meta itemprop="position" content="' . $position . '" /></li> ' . $data['delimiter_html'] . ' ';
                                $position++;
                            }
                        }
    
                        $prefix = '';
                        if ( $data['prefix'] === 'icon' ){
                            $prefix = '<i class="fa-solid fa-bookmark"></i>';
                        } elseif ( $data['prefix'] === 'text' ){
                            $prefix = 'Category: ';
                        }
    
                        echo apply_filters('nebula_breadcrumbs_category', $data['before'] . '<a class="current-breadcrumb-link" href="' . get_category_link($thisCat->term_id) . '" itemprop="item"><span itemprop="name">' . $prefix . single_cat_title('', false) . '</span></a><meta itemprop="position" content="' . $position . '" />' . $data['after'], $data);
                        $position++;
                    } elseif ( is_search() ){
                        echo $data['before'] . 'Search results' . $data['after'];
                    } elseif ( is_day() ){
                        echo '<li itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a href="' . get_year_link(get_the_time('Y')) . '" itemprop="item"><span itemprop="name">' . get_the_time('Y') . '</span></a><meta itemprop="position" content="' . $position . '" /></li> ' . $data['delimiter_html'] . ' ';
                        $position++;
    
                        echo '<li itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a href="' . get_month_link(get_the_time('Y'), get_the_time('m')) . '" itemprop="item"><span itemprop="name">' . get_the_time('F') . '</span></a><meta itemprop="position" content="' . $position . '" /></li> ' . $data['delimiter_html'] . ' ';
                        $position++;
    
                        echo $data['before'] . get_the_time('d') . $data['after'];
                    } elseif ( is_month() ){
                        echo '<li itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a href="' . get_year_link(get_the_time('Y')) . '" itemprop="item"><span itemprop="name">' . get_the_time('Y') . '</span></a><meta itemprop="position" content="' . $position . '" /></li> ' . $data['delimiter_html'] . ' ';
                        $position++;
    
                        echo $data['before'] . get_the_time('F') . $data['after'];
                    } elseif ( is_year() ){
                        echo $data['before'] . get_the_time('Y') . $data['after'];
                    } elseif ( is_single() && !is_attachment() ){
                        if ( get_post_type() !== 'post' ){ //Custom Post Type
                            $post_type = get_post_type_object(get_post_type());
    
                            $slug = $post_type->rewrite;
                            if ( is_string($post_type->has_archive) ){ //If the post type has a custom archive slug
                                $slug['slug'] = $post_type->has_archive; //Replace slug with the custom archive slug string
                            }
    
                            echo '<li itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a href="' . $data['home_link'] . $slug['slug'] . '/" itemprop="item"><span itemprop="name">' . $post_type->labels->name . '</span></a><meta itemprop="position" content="' . $position . '" /></li>'; //Changed from singular_name so plurals would appear in breadcrumb nodes
                            $position++;
    
                            //Check for parent "pages" on the custom post type and output them if they exist
                            $parent_id = $post->post_parent;
                            if ( !empty($parent_id) ){
                                echo $data['delimiter_html'];
                                $breadcrumbs = array();
    
                                while ( $parent_id ){
                                    $page = get_page($parent_id);
                                    $breadcrumbs[] = '<li itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a href="' . get_permalink($page->ID) . '" itemprop="item"><span itemprop="name">' . strip_tags(get_the_title($page->ID)) . '</span></a><meta itemprop="position" content="' . $position . '" /></li>';
                                    $position++;
                                    $parent_id = $page->post_parent;
                                }
    
                                $breadcrumbs = array_reverse($breadcrumbs);
                                $breadcrumbs_nodes = count($breadcrumbs);
                                for ( $i = 0; $i < $breadcrumbs_nodes; $i++ ){
                                    echo $breadcrumbs[$i];
                                    if ( $i !== $breadcrumbs_nodes-1 ){
                                        echo ' ' . $data['delimiter_html'] . ' ';
                                    }
                                }
                            }
    
                            if ( !empty($data['current']) ){
                                echo ' ' . $data['delimiter_html'] . ' ' . $data['current_node'] . '<meta itemprop="position" content="' . $position . '" />' . $data['after'];
                            }
                        } else { //Post Category
                            $cat = get_the_category();
                            if ( !empty($cat) ){
                                $cat = $cat[0];
    
                                echo '<li itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a href="' . esc_url(get_term_link($cat->term_id, 'category')) . '" itemprop="item"><span itemprop="name">' . $cat->name . '</span></a><meta itemprop="position" content="' . $position . '" /></li> ' . $data['delimiter_html'] . ' ';
                                $position++;
    
                                if ( !empty($data['current']) ){
                                    echo $data['current_node'] . '<meta itemprop="position" content="' . $position . '" />' . $data['after'];
                                }
                            }
                        }
                    } elseif ( !is_single() && !is_page() && get_post_type() !== 'post' && !is_404() ){
                        $post_type = get_post_type_object(get_post_type());
                        echo $data['before'] . '<span itemprop="name">' . $post_type->labels->name . '</span><meta itemprop="position" content="' . $position . '" />' . $data['after'];
                    } elseif ( is_attachment() ){ //@TODO "Nebula" 0: Check for gallery pages? If so, it should be Home > Parent(s) > Gallery > Attachment
                        if ( !empty($post->post_parent) ){ //@TODO "Nebula" 0: What happens if the page parent is a child of another page?
                            echo '<li itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a href="' . get_permalink($post->post_parent) . '" itemprop="item"><span itemprop="name">' . strip_tags(get_the_title($post->post_parent)) . '</span></a><meta itemprop="position" content="' . $position . '" /></li> ' . $data['delimiter_html'] . ' ' . strip_tags(get_the_title());
                            $position++;
                        } else {
                            echo strip_tags(get_the_title());
                        }
                    } elseif ( is_page() && !$post->post_parent ){ //Page without ancestors/parents
                        if ( !empty($data['current']) ){
                            echo $data['current_node'] . '<meta itemprop="position" content="' . $position . '" />' . $data['after'];
                        }
                    } elseif ( is_page() && $post->post_parent ){ //Page with ancestors/parents
                        $parent_id = $post->post_parent;
                        $breadcrumbs = array();
    
                        while ( $parent_id ){
                            $page = get_page($parent_id);
                            $breadcrumbs[] = '<li itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a href="' . get_permalink($page->ID) . '" itemprop="item"><span itemprop="name">' . strip_tags(get_the_title($page->ID)) . '</span></a><meta itemprop="position" content="' . $position . '" /></li>';
                            $position++;
                            $parent_id = $page->post_parent;
                        }
    
                        $breadcrumbs = array_reverse($breadcrumbs);
                        $breadcrumbs_nodes = count($breadcrumbs);
                        for ( $i = 0; $i < $breadcrumbs_nodes; $i++ ){
                            echo $breadcrumbs[$i];
                            if ( $i !== $breadcrumbs_nodes-1 ){
                                echo ' ' . $data['delimiter_html'] . ' ';
                            }
                        }
    
                        if ( !empty($data['current']) ){
                            echo ' ' . $data['delimiter_html'] . ' ' . $data['current_node'] . '<meta itemprop="position" content="' . $position . '" />' . $data['after'];
                        }
                    } elseif ( is_tag() ){
                        $prefix = '';
                        if ( $data['prefix'] === 'icon' ){
                            $prefix = '<i class="fa-solid fa-tag"></i>';
                        } elseif ( $data['prefix'] === 'text' ){
                            $prefix = 'Tag: ';
                        }
    
                        echo apply_filters('nebula_breadcrumbs_tag', $data['before'] . $prefix . '<span itemprop="name">' . single_tag_title('', false) . '</span><meta itemprop="position" content="' . $position . '" />' . $data['after'], $data);
                        //echo $data['before'] . '<a class="current-breadcrumb-link" href="' . get_tag_link($thisTag->term_id) . '">'. $prefix . single_tag_title('', false) . '</a>' . $data['after']; //@todo "Nebula": Need to get $thisTag like $thisCat above
                    } elseif ( is_author() ){
                        //@TODO "Nebula" 0: Support for multi author? is_multi_author()
    
                        global $author;
                        $userdata = get_userdata($author);
                        echo apply_filters('nebula_breadcrumbs_author', $data['before'] . '<span itemprop="name">' . $userdata->display_name . '</span><meta itemprop="position" content="' . $position . '" />' . $data['after'], $data);
                    } elseif ( is_404() ){
                        echo apply_filters('nebula_breadcrumbs_error', $data['before'] . '<span itemprop="name">Error 404</span>' . $data['after'], $data);
                    }
    
                    if ( get_query_var('paged') ){
                        echo apply_filters('nebula_breadcrumbs_paged', '&nbsp;(Page ' . get_query_var('paged') . ')', $data); //nbsp is needed here because something is stripping out the first space
                    }
                    echo '</ol>';
                }
    
                $this->timer('Breadcrumbs', 'end');
            }
    

    Override

    To override this PHP function, use this hook in your child theme or plugin ("my_custom" can be changed):

    PHP
    add_filter('pre_nebula_breadcrumbs', 'my_custom_breadcrumbs', 10, 2); //The last integer must be 1 more than the actual parameters
    function my_custom_breadcrumbs($null, $options){ //$null is required, but can be ignored
        //Write your own code here
    
        return true; //Return true to prevent the original function from running afterwords
    }

    You can completely disable this PHP function with a single line actions:

    PHP
     add_filter('pre_nebula_breadcrumbs', '__return_false');