Usage
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
Examples
Simple Implementation
<?php nebula()->breadcrumbs(); ?>
Replace the delimiter and home link with text
<?php nebula()->breadcrumbs(array('delimiter' => '»', '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
nebula()->breadcrumbs(array(
'home' => '<i class="fas fa-home"></i>',
'delimiter' => '»',
'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 nebula()->breadcrumbs(array('prefix' => false)); ?>
Change settings globally by changing default parameters across the entire site
<?php
//Add this to a functions file
add_filter('nebula_breadcrumb_defaults', function($defaults){
$defaults['delimiter'] = '›';
$defaults['home'] = '<i class="fas fa-home"></i>';
return $defaults;
});
//Now it can be called in template files without parameters:
nebula()->breadcrumbs();
?>
Source File
Located in /libs/Functions.php on line 1589.
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 3 to-do comments.
public function breadcrumbs($options=array()){
$override = apply_filters('pre_nebula_breadcrumbs', null);
if ( isset($override) ){return;}
if ( $this->is_background_request() ){return null;}
$this->timer('Breadcrumbs', 'start', '[Nebula] Markup');
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 null;
} 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_tag() ){
$tag = get_queried_object();
if ( $tag && !is_wp_error($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'] . '<a class="current-breadcrumb-link" href="' . esc_url(get_tag_link($tag->term_id)) . '" itemprop="item"><span itemprop="name">' . $prefix . esc_html($tag->name) . '</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());
if ( isset($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 "Nebulla" 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_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', ' (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):
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:
add_filter('pre_nebula_breadcrumbs', '__return_false');