Skip to content

Instantly share code, notes, and snippets.

@Dimox
Last active November 15, 2025 12:43
Show Gist options
  • Select an option

  • Save Dimox/5654092 to your computer and use it in GitHub Desktop.

Select an option

Save Dimox/5654092 to your computer and use it in GitHub Desktop.
WordPress Breadcrumbs Without a Plugin - http://dimox.net/wordpress-breadcrumbs-without-a-plugin/
<?php
/*
* WordPress Breadcrumbs
* author: Dimox
* version: 2019.03.03
* license: MIT
*/
function dimox_breadcrumbs() {
/* === OPTIONS === */
$text['home'] = 'Home'; // text for the 'Home' link
$text['category'] = 'Archive by Category "%s"'; // text for a category page
$text['search'] = 'Search Results for "%s" Query'; // text for a search results page
$text['tag'] = 'Posts Tagged "%s"'; // text for a tag page
$text['author'] = 'Articles Posted by %s'; // text for an author page
$text['404'] = 'Error 404'; // text for the 404 page
$text['page'] = 'Page %s'; // text 'Page N'
$text['cpage'] = 'Comment Page %s'; // text 'Comment Page N'
$wrap_before = '<div class="breadcrumbs" itemscope itemtype="http://schema.org/BreadcrumbList">'; // the opening wrapper tag
$wrap_after = '</div><!-- .breadcrumbs -->'; // the closing wrapper tag
$sep = '<span class="breadcrumbs__separator"> › </span>'; // separator between crumbs
$before = '<span class="breadcrumbs__current">'; // tag before the current crumb
$after = '</span>'; // tag after the current crumb
$show_on_home = 0; // 1 - show breadcrumbs on the homepage, 0 - don't show
$show_home_link = 1; // 1 - show the 'Home' link, 0 - don't show
$show_current = 1; // 1 - show current page title, 0 - don't show
$show_last_sep = 1; // 1 - show last separator, when current page title is not displayed, 0 - don't show
/* === END OF OPTIONS === */
global $post;
$home_url = home_url('/');
$link = '<span itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem">';
$link .= '<a class="breadcrumbs__link" href="%1$s" itemprop="item"><span itemprop="name">%2$s</span></a>';
$link .= '<meta itemprop="position" content="%3$s" />';
$link .= '</span>';
$parent_id = ( $post ) ? $post->post_parent : '';
$home_link = sprintf( $link, $home_url, $text['home'], 1 );
if ( is_home() || is_front_page() ) {
if ( $show_on_home ) echo $wrap_before . $home_link . $wrap_after;
} else {
$position = 0;
echo $wrap_before;
if ( $show_home_link ) {
$position += 1;
echo $home_link;
}
if ( is_category() ) {
$parents = get_ancestors( get_query_var('cat'), 'category' );
foreach ( array_reverse( $parents ) as $cat ) {
$position += 1;
if ( $position > 1 ) echo $sep;
echo sprintf( $link, get_category_link( $cat ), get_cat_name( $cat ), $position );
}
if ( get_query_var( 'paged' ) ) {
$position += 1;
$cat = get_query_var('cat');
echo $sep . sprintf( $link, get_category_link( $cat ), get_cat_name( $cat ), $position );
echo $sep . $before . sprintf( $text['page'], get_query_var( 'paged' ) ) . $after;
} else {
if ( $show_current ) {
if ( $position >= 1 ) echo $sep;
echo $before . sprintf( $text['category'], single_cat_title( '', false ) ) . $after;
} elseif ( $show_last_sep ) echo $sep;
}
} elseif ( is_search() ) {
if ( get_query_var( 'paged' ) ) {
$position += 1;
if ( $show_home_link ) echo $sep;
echo sprintf( $link, $home_url . '?s=' . get_search_query(), sprintf( $text['search'], get_search_query() ), $position );
echo $sep . $before . sprintf( $text['page'], get_query_var( 'paged' ) ) . $after;
} else {
if ( $show_current ) {
if ( $position >= 1 ) echo $sep;
echo $before . sprintf( $text['search'], get_search_query() ) . $after;
} elseif ( $show_last_sep ) echo $sep;
}
} elseif ( is_year() ) {
if ( $show_home_link && $show_current ) echo $sep;
if ( $show_current ) echo $before . get_the_time('Y') . $after;
elseif ( $show_home_link && $show_last_sep ) echo $sep;
} elseif ( is_month() ) {
if ( $show_home_link ) echo $sep;
$position += 1;
echo sprintf( $link, get_year_link( get_the_time('Y') ), get_the_time('Y'), $position );
if ( $show_current ) echo $sep . $before . get_the_time('F') . $after;
elseif ( $show_last_sep ) echo $sep;
} elseif ( is_day() ) {
if ( $show_home_link ) echo $sep;
$position += 1;
echo sprintf( $link, get_year_link( get_the_time('Y') ), get_the_time('Y'), $position ) . $sep;
$position += 1;
echo sprintf( $link, get_month_link( get_the_time('Y'), get_the_time('m') ), get_the_time('F'), $position );
if ( $show_current ) echo $sep . $before . get_the_time('d') . $after;
elseif ( $show_last_sep ) echo $sep;
} elseif ( is_single() && ! is_attachment() ) {
if ( get_post_type() != 'post' ) {
$position += 1;
$post_type = get_post_type_object( get_post_type() );
if ( $position > 1 ) echo $sep;
echo sprintf( $link, get_post_type_archive_link( $post_type->name ), $post_type->labels->name, $position );
if ( $show_current ) echo $sep . $before . get_the_title() . $after;
elseif ( $show_last_sep ) echo $sep;
} else {
$cat = get_the_category(); $catID = $cat[0]->cat_ID;
$parents = get_ancestors( $catID, 'category' );
$parents = array_reverse( $parents );
$parents[] = $catID;
foreach ( $parents as $cat ) {
$position += 1;
if ( $position > 1 ) echo $sep;
echo sprintf( $link, get_category_link( $cat ), get_cat_name( $cat ), $position );
}
if ( get_query_var( 'cpage' ) ) {
$position += 1;
echo $sep . sprintf( $link, get_permalink(), get_the_title(), $position );
echo $sep . $before . sprintf( $text['cpage'], get_query_var( 'cpage' ) ) . $after;
} else {
if ( $show_current ) echo $sep . $before . get_the_title() . $after;
elseif ( $show_last_sep ) echo $sep;
}
}
} elseif ( is_post_type_archive() ) {
$post_type = get_post_type_object( get_post_type() );
if ( get_query_var( 'paged' ) ) {
$position += 1;
if ( $position > 1 ) echo $sep;
echo sprintf( $link, get_post_type_archive_link( $post_type->name ), $post_type->label, $position );
echo $sep . $before . sprintf( $text['page'], get_query_var( 'paged' ) ) . $after;
} else {
if ( $show_home_link && $show_current ) echo $sep;
if ( $show_current ) echo $before . $post_type->label . $after;
elseif ( $show_home_link && $show_last_sep ) echo $sep;
}
} elseif ( is_attachment() ) {
$parent = get_post( $parent_id );
$cat = get_the_category( $parent->ID ); $catID = $cat[0]->cat_ID;
$parents = get_ancestors( $catID, 'category' );
$parents = array_reverse( $parents );
$parents[] = $catID;
foreach ( $parents as $cat ) {
$position += 1;
if ( $position > 1 ) echo $sep;
echo sprintf( $link, get_category_link( $cat ), get_cat_name( $cat ), $position );
}
$position += 1;
echo $sep . sprintf( $link, get_permalink( $parent ), $parent->post_title, $position );
if ( $show_current ) echo $sep . $before . get_the_title() . $after;
elseif ( $show_last_sep ) echo $sep;
} elseif ( is_page() && ! $parent_id ) {
if ( $show_home_link && $show_current ) echo $sep;
if ( $show_current ) echo $before . get_the_title() . $after;
elseif ( $show_home_link && $show_last_sep ) echo $sep;
} elseif ( is_page() && $parent_id ) {
$parents = get_post_ancestors( get_the_ID() );
foreach ( array_reverse( $parents ) as $pageID ) {
$position += 1;
if ( $position > 1 ) echo $sep;
echo sprintf( $link, get_page_link( $pageID ), get_the_title( $pageID ), $position );
}
if ( $show_current ) echo $sep . $before . get_the_title() . $after;
elseif ( $show_last_sep ) echo $sep;
} elseif ( is_tag() ) {
if ( get_query_var( 'paged' ) ) {
$position += 1;
$tagID = get_query_var( 'tag_id' );
echo $sep . sprintf( $link, get_tag_link( $tagID ), single_tag_title( '', false ), $position );
echo $sep . $before . sprintf( $text['page'], get_query_var( 'paged' ) ) . $after;
} else {
if ( $show_home_link && $show_current ) echo $sep;
if ( $show_current ) echo $before . sprintf( $text['tag'], single_tag_title( '', false ) ) . $after;
elseif ( $show_home_link && $show_last_sep ) echo $sep;
}
} elseif ( is_author() ) {
$author = get_userdata( get_query_var( 'author' ) );
if ( get_query_var( 'paged' ) ) {
$position += 1;
echo $sep . sprintf( $link, get_author_posts_url( $author->ID ), sprintf( $text['author'], $author->display_name ), $position );
echo $sep . $before . sprintf( $text['page'], get_query_var( 'paged' ) ) . $after;
} else {
if ( $show_home_link && $show_current ) echo $sep;
if ( $show_current ) echo $before . sprintf( $text['author'], $author->display_name ) . $after;
elseif ( $show_home_link && $show_last_sep ) echo $sep;
}
} elseif ( is_404() ) {
if ( $show_home_link && $show_current ) echo $sep;
if ( $show_current ) echo $before . $text['404'] . $after;
elseif ( $show_last_sep ) echo $sep;
} elseif ( has_post_format() && ! is_singular() ) {
if ( $show_home_link && $show_current ) echo $sep;
echo get_post_format_string( get_post_format() );
}
echo $wrap_after;
}
} // end of dimox_breadcrumbs()
@cassandre
Copy link
Copy Markdown

You may fix the empty search results error (Notice: Tryin to get property of non-object...) by replacing line 40 ($parent_id = $post->post_parent) by the following code:

if (have_posts()) {
    $parent_id = $post->post_parent;
}

@krishna19
Copy link
Copy Markdown

Please add support for Woo Commerce & BBPress.

Thanks

@ohsik
Copy link
Copy Markdown

ohsik commented Dec 4, 2015

When displaying a post has no category set up will show the error.

Notice: undefined offset:0 on $cat = get_the_category(); $cat = $cat[0];

Catchable fatal error: Object of class WP_Error could not be converted to string in $cats = preg_replace('#<a([^>]+)>([^<]+)<\/a>#', $link_before . '<a$1' . $link_attr .'>' . $link_in_before . '$2' . $link_in_after .'</a>' . $link_after, $cats);

@krishna19
Copy link
Copy Markdown

It happened to me also. Please help to fix the error when the post has no category.

@jnadd
Copy link
Copy Markdown

jnadd commented Dec 12, 2015

I had a problem trying to condition this:
-- $thisCat = get_category(get_query_var ('cat'), false); --
-- $thisCat->parent != 0 --

The solution for me:
global $wp_query;
$thisCat = $wp_query->queried_object;

@kbytin
Copy link
Copy Markdown

kbytin commented Dec 21, 2015

After getting err (Notice: Tryin to get property of non-object...)

changed
$parent_id = $post->post_parent;

to this

$thisPostID = get_the_ID();
$parent_id = wp_get_post_parent_id( $thisPostID );

@sanjeevthakur58
Copy link
Copy Markdown

Can any one tell me I don't want breadcrumb links, it will only text, how to remove the anchor tag from this code

@Anydog
Copy link
Copy Markdown

Anydog commented Jun 13, 2016

Yeah, on line 101 and 125 there's an error if post is not assigned to any category (there are some cases):
This
$cat = get_the_category(); $cat = $cat[0];
should be replaced with this (after line 101, for example):

$cat = get_the_category(); 
$cat = isset( $cat ) ? $cat[0] : '';
if( $cat ) {
    $cats = get_category_parents($cat, TRUE, $sep);
    if (!$show_current || get_query_var('cpage')) $cats = preg_replace("#^(.+)$sep$#", "$1", $cats);
    $cats = preg_replace('#<a([^>]+)>([^<]+)<\/a>#', $link_before . '<a$1' . $link_attr .'>' . $link_in_before . '$2' . $link_in_after .'</a>' . $link_after, $cats);
    echo $cats;
    if ( get_query_var('cpage') ) {
        echo $sep . sprintf($link, get_permalink(), get_the_title()) . $sep . $before . sprintf($text['cpage'], get_query_var('cpage')) . $after;
    } else {
        if ($show_current) echo $before . get_the_title() . $after;
    }
}else{
    if ($showCurrent == 1) {
        $breadcrumb_html .= $before . esc_html( strip_tags( get_the_title() ) ) . $after; 
    }
}

Apply the same logic on line 125 (line number will change after line 101 fix)

@rhcarlosweb
Copy link
Copy Markdown

Maybe can improve this code for custom taxonomy?

I'm using this function to added custom taxonomy on breadcrumb in conditional is_tax(), but i'm don't understand much about php, so is only a suggest :)

function get_taxonomy_parents( $id, $taxonomy = 'category', $link = false, $separator = '/', $nicename = false, $visited = array() ) {

        $chain = '';
        $parent = get_term( $id, $taxonomy );

        if ( is_wp_error( $parent ) )
                return $parent;

        if ( $nicename )
                $name = $parent->slug;
        else
                $name = $parent->name;

        if ( $parent->parent && ( $parent->parent != $parent->term_id ) && !in_array( $parent->parent, $visited ) ) {
                $visited[] = $parent->parent;
                $chain .= get_taxonomy_parents( $parent->parent, $taxonomy, $link, $separator, $nicename, $visited );
        }

        if ( $link )
                $chain .= '<a href="' . esc_url( get_term_link( $parent,$taxonomy ) ) . '" title="' . esc_attr( sprintf( __( "View all posts in %s" ), $parent->name ) ) . '">'.$name.'</a>' . $separator;
        else
                $chain .= $name.$separator;

        return $chain;
}

@Ninetheme
Copy link
Copy Markdown

thank you!

@haipham
Copy link
Copy Markdown

haipham commented Oct 14, 2019

Please fix missing field "id" in Google Search Console. Thank you.

@webarter
Copy link
Copy Markdown

Hello!

Google today started issuing a warning data-vocabulary.org schema deprecated

From April 2020 the current markup won't be supported anymore and Google won't display rich results unless we migrate to a different markup in this code.

@Dimox can you please look into this and let us know if you feel like updating it? Here's detailed info on the issue and example of the new markup: https://www.spyloadedng.com/webmasters-board/breadcrumbs-issue-how-to-fix-data-vocabulary-schema-deprecated/

The alternative seems to be using Yoast SEO's breadcrumbs from their new version.

@MKH67
Copy link
Copy Markdown

MKH67 commented Jan 22, 2020

About Google data vocabulary problem, using last version of the code solved it for me :)

@Dimox
Copy link
Copy Markdown
Author

Dimox commented Jan 22, 2020

@webarter, I'm not using data-vocabulary.

@alex-wdmg
Copy link
Copy Markdown

A custom WordPress nav walker class to implement the Bootstrap 4 breadcrumbs style in a custom theme using the WordPress. Google schema validation is Ok.
wp_breadcrumbs.php

@tweenpix
Copy link
Copy Markdown

tweenpix commented Jul 12, 2021

чтобы работало в категориях woocommerce

        elseif (is_product_category()) {
            $parents = get_ancestors(get_query_var('cat'), 'category');
            foreach (array_reverse($parents) as $cat) {
                $position += 1;
                if ($position > 1) echo $sep;
                echo sprintf($link, get_category_link($cat), get_cat_name($cat), $position);
            }
            if (get_query_var('paged')) {
                $position += 1;
                $cat = get_query_var('cat');
                echo $sep . sprintf($link, get_category_link($cat), get_cat_name($cat), $position);
                echo $sep . $before . sprintf($text['page'], get_query_var('paged')) . $after;
            } else {
                if ($show_current) {
                    if ($position >= 1) echo $sep;
                    echo $before . sprintf($text['category'], single_cat_title('', false)) . $after;
                } elseif ($show_last_sep) echo $sep;
            }
        } 

@DimonFreeman
Copy link
Copy Markdown

чтобы работало в категориях woocommerce

        elseif (is_product_category()) {
            $parents = get_ancestors(get_query_var('cat'), 'category');
            foreach (array_reverse($parents) as $cat) {
                $position += 1;
                if ($position > 1) echo $sep;
                echo sprintf($link, get_category_link($cat), get_cat_name($cat), $position);
            }
            if (get_query_var('paged')) {
                $position += 1;
                $cat = get_query_var('cat');
                echo $sep . sprintf($link, get_category_link($cat), get_cat_name($cat), $position);
                echo $sep . $before . sprintf($text['page'], get_query_var('paged')) . $after;
            } else {
                if ($show_current) {
                    if ($position >= 1) echo $sep;
                    echo $before . sprintf($text['category'], single_cat_title('', false)) . $after;
                } elseif ($show_last_sep) echo $sep;
            }
        } 

не совсем корректно работает,
Главная->Категория, или Главная->Подкатегория.
Каталог с категориями пропускает + категорию пропускает

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment