Hi, I'm a web developer and blogger from Russia. My nickname is Dimox.
Sorry for my English, it's not my native. Read more about me and my blog.

WordPress Breadcrumbs Without a Plugin

WordPress Breadcrumbs Without a Plugin

Breadcrumbs is an important element of a web site navigation, which boosts his usability. Especially it concerns to a sites with a complex structure. Unfortunatelly, I don’t use breadcrumbs on my sites, may be because their structure is very simple or because I could not find a way of making breadcrumbs, suitable for me.

I have seen a different ways of a breadcrumbs implementation on WordPress sites, but not one of them I does not like, because all of them does not display a full chain of links. So I have created my version of WordPress breadcrumbs without a plugin.

Yes, there is a ready plugins for WordPress breadcrumbs, but I prefer to use a short code snippets, which doing the same.

Features of my version of WordPress breadcrumbs

  • Displays a full chain of links to the current page. For example, if the current post is in a second level category, so breadcrumbs will looks like this:

    Home » Category » Subcategory » Post Title

    But all, what I have seen, displays only such an option (excluding plugins):

    Home » Subcategory » Post Title

    The same applies to pages and subpages. For example, for a 3rd level page breadcrumbs will looks like this:

    Home » Page Level 1 » Page Level 2 » Page Level 3

  • Breadcrumbs is appearing on a following types of WordPress pages:

    • paged navigation (like sitename.com/page/2/);
    • category archive;
    • tag archive;
    • daily archive;
    • monthly archive;
    • yearly archive;
    • author archive;
    • single post page;
    • single page;
    • attachment page;
    • search results;
    • 404 error page.
  • adding a page number (if archive page is second or more);

  • custom symbol of delimiter;

  • custom text for a ‘Home’ link;

  • current crumb styling;

  • integrated Google rich snippets.

WordPress breadcrumbs function (last updated: 2014.01.19)

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

	$show_current   = 1; // 1 - show current post/page/category title in breadcrumbs, 0 - don't show
	$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_title     = 1; // 1 - show the title for the links, 0 - don't show
	$delimiter      = ' » '; // delimiter between crumbs
	$before         = '<span class="current">'; // tag before the current crumb
	$after          = '</span>'; // tag after the current crumb
	/* === END OF OPTIONS === */

	global $post;
	$home_link    = home_url('/');
	$link_before  = '<span typeof="v:Breadcrumb">';
	$link_after   = '</span>';
	$link_attr    = ' rel="v:url" property="v:title"';
	$link         = $link_before . '<a' . $link_attr . ' href="%1$s">%2$s</a>' . $link_after;
	$parent_id    = $parent_id_2 = $post->post_parent;
	$frontpage_id = get_option('page_on_front');

	if (is_home() || is_front_page()) {

		if ($show_on_home == 1) echo '<div class="breadcrumbs"><a href="' . $home_link . '">' . $text['home'] . '</a></div>';

	} else {

		echo '<div class="breadcrumbs" xmlns:v="http://rdf.data-vocabulary.org/#">';
		if ($show_home_link == 1) {
			echo '<a href="' . $home_link . '" rel="v:url" property="v:title">' . $text['home'] . '</a>';
			if ($frontpage_id == 0 || $parent_id != $frontpage_id) echo $delimiter;

		if ( is_category() ) {
			$this_cat = get_category(get_query_var('cat'), false);
			if ($this_cat->parent != 0) {
				$cats = get_category_parents($this_cat->parent, TRUE, $delimiter);
				if ($show_current == 0) $cats = preg_replace("#^(.+)$delimiter$#", "$1", $cats);
				$cats = str_replace('<a', $link_before . '<a' . $link_attr, $cats);
				$cats = str_replace('</a>', '</a>' . $link_after, $cats);
				if ($show_title == 0) $cats = preg_replace('/ title="(.*?)"/', '', $cats);
				echo $cats;
			if ($show_current == 1) echo $before . sprintf($text['category'], single_cat_title('', false)) . $after;

		} elseif ( is_search() ) {
			echo $before . sprintf($text['search'], get_search_query()) . $after;

		} elseif ( is_day() ) {
			echo sprintf($link, get_year_link(get_the_time('Y')), get_the_time('Y')) . $delimiter;
			echo sprintf($link, get_month_link(get_the_time('Y'),get_the_time('m')), get_the_time('F')) . $delimiter;
			echo $before . get_the_time('d') . $after;

		} elseif ( is_month() ) {
			echo sprintf($link, get_year_link(get_the_time('Y')), get_the_time('Y')) . $delimiter;
			echo $before . get_the_time('F') . $after;

		} elseif ( is_year() ) {
			echo $before . get_the_time('Y') . $after;

		} elseif ( is_single() && !is_attachment() ) {
			if ( get_post_type() != 'post' ) {
				$post_type = get_post_type_object(get_post_type());
				$slug = $post_type->rewrite;
				printf($link, $home_link . '/' . $slug['slug'] . '/', $post_type->labels->singular_name);
				if ($show_current == 1) echo $delimiter . $before . get_the_title() . $after;
			} else {
				$cat = get_the_category(); $cat = $cat[0];
				$cats = get_category_parents($cat, TRUE, $delimiter);
				if ($show_current == 0) $cats = preg_replace("#^(.+)$delimiter$#", "$1", $cats);
				$cats = str_replace('<a', $link_before . '<a' . $link_attr, $cats);
				$cats = str_replace('</a>', '</a>' . $link_after, $cats);
				if ($show_title == 0) $cats = preg_replace('/ title="(.*?)"/', '', $cats);
				echo $cats;
				if ($show_current == 1) echo $before . get_the_title() . $after;

		} elseif ( !is_single() && !is_page() && get_post_type() != 'post' && !is_404() ) {
			$post_type = get_post_type_object(get_post_type());
			echo $before . $post_type->labels->singular_name . $after;

		} elseif ( is_attachment() ) {
			$parent = get_post($parent_id);
			$cat = get_the_category($parent->ID); $cat = $cat[0];
			if ($cat) {
				$cats = get_category_parents($cat, TRUE, $delimiter);
				$cats = str_replace('<a', $link_before . '<a' . $link_attr, $cats);
				$cats = str_replace('</a>', '</a>' . $link_after, $cats);
				if ($show_title == 0) $cats = preg_replace('/ title="(.*?)"/', '', $cats);
				echo $cats;
			printf($link, get_permalink($parent), $parent->post_title);
			if ($show_current == 1) echo $delimiter . $before . get_the_title() . $after;

		} elseif ( is_page() && !$parent_id ) {
			if ($show_current == 1) echo $before . get_the_title() . $after;

		} elseif ( is_page() && $parent_id ) {
			if ($parent_id != $frontpage_id) {
				$breadcrumbs = array();
				while ($parent_id) {
					$page = get_page($parent_id);
					if ($parent_id != $frontpage_id) {
						$breadcrumbs[] = sprintf($link, get_permalink($page->ID), get_the_title($page->ID));
					$parent_id = $page->post_parent;
				$breadcrumbs = array_reverse($breadcrumbs);
				for ($i = 0; $i < count($breadcrumbs); $i++) {
					echo $breadcrumbs[$i];
					if ($i != count($breadcrumbs)-1) echo $delimiter;
			if ($show_current == 1) {
				if ($show_home_link == 1 || ($parent_id_2 != 0 && $parent_id_2 != $frontpage_id)) echo $delimiter;
				echo $before . get_the_title() . $after;

		} elseif ( is_tag() ) {
			echo $before . sprintf($text['tag'], single_tag_title('', false)) . $after;

		} elseif ( is_author() ) {
	 		global $author;
			$userdata = get_userdata($author);
			echo $before . sprintf($text['author'], $userdata->display_name) . $after;

		} elseif ( is_404() ) {
			echo $before . $text['404'] . $after;

		} elseif ( has_post_format() && !is_singular() ) {
			echo get_post_format_string( get_post_format() );

		if ( get_query_var('paged') ) {
			if ( is_category() || is_day() || is_month() || is_year() || is_search() || is_tag() || is_author() ) echo ' (';
			echo __('Page') . ' ' . get_query_var('paged');
			if ( is_category() || is_day() || is_month() || is_year() || is_search() || is_tag() || is_author() ) echo ')';

		echo '</div><!-- .breadcrumbs -->';

} // end dimox_breadcrumbs()

Gist on GitHub.

Simply paste this function into a functions.php file of your theme and then paste the following code in a place of your theme, where breadcrumbs must appearing:

<?php if (function_exists('dimox_breadcrumbs')) dimox_breadcrumbs(); ?>

All that remains to do for now, is to design your breadcrumbs with CSS. You can use #crumbs for styling breadcrumbs block and #crumbs .current for styling a current crumb.

You can also look at breadcrumbs video tutorial, which show you how to install this function on TwentyTen WordPress theme.

Function works on WordPress 3.0 or higher.

Cоmmеnts (595):
  1. 526

    This function is working great, thank you.
    I have one question:
    If my home page is set to a page, say ‘landing-page’ and landing-page has sub pages, when I visit a sub-page, the breadcrumb looks like this: home/landing-page/sub-page. The home and landing-page both have the same link, to the site root. So it is doubling the link to the site root, one with ‘home’, one with the name of the page that is set to be my home page. I would like sub-pages of my ‘home’ page to look like: home/sub-page. Can you help. Thanks.

    • 528

      Sorry, I don’t know how to fix this.

      • 529

        Thanks for your work!

        I finally worked it out, maybe it can help someone in the future with this issue:
        At line 25:
        if (is_home() || is_front_page()) {

        if ($showOnHome == 1) echo '' . $text['home'] . '';

        } else { //run as normal if not on the front page.
        if ($post->post_parent != get_option('page_on_front'))
        echo '' . sprintf($link, $homeLink, $text['home']) . $delimiter;
        // remove the delimiter from the home link if on the front page.
        else echo '' . sprintf($link, $homeLink, $text['home']) ;

        if ( is_category() ) {

        And near line 103: $parent_id = $post->post_parent;
        // check if the front page is not the parent of the current item and run as usual, if it is the parent don't add it as a breadcrumb.
        if ($post->post_parent != get_option('page_on_front'))
        $breadcrumbs = array();

        while ($parent_id)
        $page = get_page($parent_id);
        $breadcrumbs[] = sprintf($link, get_permalink($page->ID), get_the_title($page->ID));
        $parent_id = $page->post_parent;
        $breadcrumbs = array_reverse($breadcrumbs);
        for ($i = 0; $i < count($breadcrumbs); $i++)
        echo $breadcrumbs[$i];
        if ($i != count($breadcrumbs)-1) echo $delimiter;

        if ($showCurrent == 1)

  2. 530

    Hi Dimox,
    Thank you for the great code! Is it possible to exclude a page from including the breadcrumbs? I have a page called http://aspireid.com/hvac-marketing that will be used as a landing page and I don’t want the breadcrumbs to appear here. Thank you for any assistance you can provide!

    • 531

      Change < ?php if (function_exists('dimox_breadcrumbs')) dimox_breadcrumbs(); ?> on:

      < ?php if (function_exists('dimox_breadcrumbs') && !is_page('123')) dimox_breadcrumbs(); ?>

      123 – ID of a page.

  3. 533
    grappler said:


    I tried your latest version. There seemed to be some issues. Have you tested it with child and grandchild pages? Have you tested it with child pages of the home page?

    Would you mind using gist so that we can see that changes that you make?

    Please make the text translateable.
    $text['home'] = __('Home','text-domain'); // text for the 'Home' link
    $text['category'] = __('Archive for %s','text-domain'); // text for a category page
    $text['search'] = __('Search results for: %s','text-domain'); // text for a search results page
    $text['tag'] = __('Posts tagged %s','text-domain'); // text for a tag page
    $text['author'] = __('View all posts by %s','text-domain'); // text for an author page
    $text['404'] = __('Error 404','text-domain'); // text for the 404 page

    I have faced some errors before and needed to update the gloabl to this
    global $post, $paged, $page;

    Please could you update the home link to the new WordPress best practice.
    $home_link = home_url('/');

    Let me know if you have any questions

    • 534

      I’ve updated the function. Gist is here.

      • 535
        grappler said:


        Another issue came to mind.

        The code in line 107-111causes issues on posts that are split into multiple sections and that are at the same child pages.

        The solution would be:

        $page_child = get_page($parent_id);
        if ($parent_id != $frontpage_id) {
        $breadcrumbs[] = sprintf($link, get_permalink($page_child->ID), get_the_title($page_child->ID));
        $parent_id = $page_child->post_parent;

        Also if a page has multiple pages than the page numbers are not shown. The fix is in line 22 and line 138

        The solution is the following code respectively
        global $post, $paged, $page;
        echo $delimiter . sprintf( __( 'Page %s', 'responsive' ), max( $paged, $page ) );

        If you set a blog page using the static pages in the reading settings then the breadcrumb will not be displayed the cause for this is is_home() in Line 31

        Once I removed it I still only got the “Home” link and not the blog title.

  4. 537

    The delimiter isn’t showing up on parent pages. I see

    Home About Us

    instead of

    Home >> About Us

    Where do I add the delimiter to show up here?

    On child pages, everything works fine:

    Home >> About Us >> Mee the Staff

  5. 539

    My post is in 3 categories. How can I exclude 2 of them and show the right one? This 2 categories are for other purpose.

  6. 542
    Theodoro Caliari said:

    Hey Dimox, thanks for share your code…
    In my wordpress I use a postspage child of a parent page… I change your code to show this in breadcrumb in this page my code is below. The plus (+) is the line I add or change:


    In posts page works fina and looks like Home >> Parent Page >> Posts Page, but, when I click in Parent Page link I go to full post page and not to parent page, when I view full post the parent page link not show I think in full post the breadcrumb should be Home >> Parent Page >> Posts Page >> Category >> Post Title. How can I do that and fix it do you help me? :)


  7. 544
    Francisco Diaz said:

    Thank you, the breadcrumbs function works perfectly!!!!

  8. 545

    Adding this makes the breadcrumbs work better when on a custom taxonomy archive page (only tested a non-hierarchical taxonomy):

    if ( is_category() ) {

    } elseif ( is_tax() ) {
    $termSlug = get_query_var( ‘term’ );
    $taxonomyName = get_query_var( ‘taxonomy’ );
    $term = get_term_by( ‘slug’, $termSlug, $taxonomyName );
    $termName = $term->name;

    $args = array(
    ‘name’ => $taxonomyName,
    $output = ‘objects’;
    $taxonomies = get_taxonomies( $args, $output );

    if ( $taxonomies ) {
    echo esc_html( $taxonomies[$taxonomyName]->label );

    if ($showCurrent == 1 && strlen( $termName ) )
    echo ‘ ‘ . $delimiter . ‘ ‘ . $before . esc_html( $termName ) . $after;

    } elseif ( is_search() ) {

    • 590
      } elseif ( is_tax() ) {
       				$taxonomy_name = get_query_var( 'taxonomy' );
       				$term = get_term_by( 'slug', get_query_var( 'term' ), $taxonomy_name );
       				$term_output = '';
       				while($term->parent != '') {
       					$term_output = $delimiter . ' ' . $before . sprintf($link, get_term_link($term), esc_html($term->name))  . $after . $term_output;
       					$term = get_term($term->parent, get_query_var('taxonomy') );
       				$term_output = $delimiter . ' ' . $before . sprintf($link, get_term_link($term), esc_html($term->name)) . $after . $term_output;
       				$taxonomy = get_taxonomy($taxonomy_name);
       				if ( $taxonomy ) {
       					echo esc_html( $taxonomy->label );
       					if ($show_current == 1 &amp;&amp; strlen( $term_output ) ) echo ' ' . $term_output;

      This works with hierarchical taxonomies…

  9. 546

    Excuse me, would you please tell me how to add Nofollow attribute in the Home?

  10. 549

    How do I remove the title tag “View all posts in”?

    • 550

      Add the following row:

      $cats = str_replace('View all posts in ', '', $cats);

      after this:

      if ($show_title == 0) $cats = preg_replace('/ title="(.*?)"/', '', $cats);

      in 3 places.

  11. 551
    leeuniverse said:

    Hey, wonderful to see a working breadcrumbs manual addition…. and everyone else making it better.

    One odd ball question however???
    If the script apparently “detects” the pages it’s on, what’s the deal with manually putting the function in the pages we want it to display? Is the detection part simply for those who are lazy and just put the code into ALL of their pages?

    Sorry, just seemed weird….

  12. 553

    thank you for useful code.
    how can i add link to current page/post ?

  13. 555

    Hi, the function works well. But I have a problem. I want to remove the title attribute of category link tag in single post page. I googled it but couldn’t find any way to work.

  14. 557

    Hi there,

    thanks a lot for this great code. Big time saver!

    Just one question: Is it possible to get anchor links, too?


  15. 562

    Very nice breadcrumbs code!

    One small question: is it possible to show/hide the title attribute for the links

    <a href="page" rel="nofollow">pagename</a>

    Or is the option ‘$show_title’ used for this.
    If so, it ain’t working in my installation.
    Can I see a working example somewhere?


    • 563

      This option works only for posts and attachments. I’ve never seen that page link had title.

      • 564

        Humm, the html code in my first comment was changed :-(
        Let’s try again.
        A page (or post) has a page-title.
        A link has a title attribute (in your tag cloud below it shows the amount of post).
        I would like to see the title attribute in the links that are created/shown in the breadcrumb. Is this possible?

        • 565

          Found a solution, add title=”%2$s” to $link

          $link = $link_before . '<a' . $link_attr . ' href="%1$s" title="%2$s">%2$s</a>' . $link_after;
  16. 566

    Hi Dimox. Thanks for this function. I’ve been trying to figure out how to adjust this to show the blog page within the breadcrumbs but no luck. For example I have a page “Home” as a static front page. A page “Blog” as the blog feed with categories under it for the posts.

    For the blog page I’m trying to get Home > Blog to show instead of just Home. Also for a single post I’m trying to get Home > Blog > Category > post title instead of just Home > Category > post title.

    Do you have any suggestions or can you advise me on how to achieve this. Thanks!

    • 567

      After this row:

      if ($frontpage_id == 0 || $parent_id != $frontpage_id) echo $delimiter;

      add the following:

      echo '<a href="link_to_the_blog" rel="v:url" property="v:title">Blog</a>' . $delimiter;
      • 570

        Actually that added “Blog” to all the pages. But I was able to kind of get what I wanted by replacing this line:

        if ($show_current == 1) echo $before . sprintf($text['category'], single_cat_title('', false)) . $after;

        with this:

        if ($show_current == 1) echo '<a href="link_to_the_blog" rel="v:url" property="v:title">Blog</a>' . $delimiter . $before . sprintf($text['category'], single_cat_title('', false)) . $after;

        Thanks for your help!

  17. 568


    Great work, I’m having trouble editing some portions though.

    On a single post, I would like it to display as – Home / Main Category / Sub Category.
    That’s it, I don’t want the post’s name/slug to be displayed at all. SO the Sub Category(Main if no sub) would be the current crumb.

    I would also like each crumb to be seperated, i.e Home in one block, Main in another block, so there is a space between the block background.

    Any help?

    • 569

      That’s it, I don’t want the post’s name/slug to be displayed at all.

      Use $show_current option.

      I would also like each crumb to be seperated, i.e Home in one block, Main in another block, so there is a space between the block background.

      Can’t help anything.

  18. 571

    The code works great except I have several pages that use custom post types, and on those pages it shows “Home > Location > Store1″ and Location doesnt exist, instead its Locations (plural).

    Any info to currect this would be great.

  19. 572

    Hello Dimox,

    First of all A MILLION thanks for sharing this hard work with others.
    I get a copy of it from your gist.
    Works fine, super easy to implement/modify, well commented, looks great.
    I just want to know under what license are you giving this great beautiful piece of work ?
    I’m actually working on a theme that i intend to sell on ThemeForest.
    Do you allow me to use it in my theme ?
    If you allow me, i’ll put it in a separated file with the following in the header of the file :
    * Courtesy and permission of Dimox
    * Dimox Breadcrumbs
    * http://dimox.net/wordpress-breadcrumbs-without-a-plugin/
    * https://gist.github.com/Dimox/5654092
    Waiting for your answer before using it :)
    Thanks again for sharing.

    • 573

      Hello. Yes, you can use it. License is MIT.

      • 574

        Hello DImox,

        I was telling myself that for sharing this great hard work you must be an MIT supporter :)
        It’s with people like you that WordPress evolve !
        I’ll tell you when my theme is finish.
        Thanks again !

  20. 575
    Domingos said:

    Hello Dimox,

    I’e added the funtion call to my index.php file, but your breadcrumb will not show. It only show’s when I paste the funtion call in pages like single.php and page.php.

    I want your breadcrumb to be shown on all pages, included the homepage.

    Thank you in advance,

    Greetings Domingos

  21. 577

    Hey Dimox… really nice implementation of breadcrumbs. It’s very complete and works great. Thanks!

  22. 578

    Hi, the function worked well. Now I have created a custom post type and I want the breadcrumbs show on the custom post type archive and single post page, how to do?


  23. 580

    Hi Dimox, I’m having some trouble with the breadcrumbs. Can you help me out?

    I was able to add custom post type followed by the taxonomy term to the breadcrumbs by altering the code a bit, which can be seen here (full breadcrumb.php code):


    One problem I am having is my archives for custom taxonomy terms are not showing the breadcrumb for the taxonomy, only the custom post type, and I’m not sure which part of the code to change and to what. Here is an example:


    Also, for these two tag archives it says “Music” for some reason and not “Posts Tagged: (tag)”, one of my custom post types that carries the tag, but not the only one:



    And for this one it says “News”, which is the only custom post type that carries the tag:


    However when I visit a regular category archive, it works just fine:


    Any ideas as to how I can fix some of this? If you could even help with only a portion of it that would be great. Thanks!


    P.S. – I wouldn’t mind paying you via paypal to help me tweak the code and solve some of these problems. Just let me know.

  24. 582

    Hello again Dimox!

    Any chance to update the WordPress Breadcrumbs to support Post Format archives soon?
    I have it here for an ‘Audio‘ Post Format

    The page is generated from taxonomy-post_format.php, which is a template for displaying typical archive-type pages for posts with a post format.

    Thank you!

    ~ A u d e e

  25. 585

    Great function, thanks for sharing! Is there any possibility to show the names I added in the wp_nav_menu and not the title? Because my titles are much longer than the ones in the menu. Greetings!

  26. 587


    This is a great code, and working very well with custom post types.

    I would like to have one more option though…
    Would it be possible not showing the custom post type if it’s ‘has_archive’ is set to false?

    For example instead showing:
    home / custom post type / custom post title

    Just showing:
    home / custom post title (if it’s ‘has_archive’ is set to false)

    Thank you very much.

  27. 589

    Worked a treat, thank you!

  28. 591

    Firstly thank you so much for this…..

    I have used this on a Multi site install and I would like to alter the

    $delimiter   = ' &raquo; ';

    but just in my child theme to add font awesome arrow to one site

    $delimiter   = ' <i class="fa fa-arrow-right"></i> ';

    is this possible in the child theme functions.php
    Many Thanks

    • 592

      Sorry, I don’t know how to make this.

      • 593

        Thank’s if I figure it out I come back and post the answer, Might help someone else.

        • 594

          I have worked it out, If you wrap the whole function in the below in your functions.php file

          if( !function_exists('dimox_breadcrumbs') )
           function dimox_breadcrumbs() {rest of code goes here!}

          Then you can override your parent theme in the child themes functions.php.
          I have now one version with Bootstrap, one with Font Awesome and one as standard :)

  29. 595

    For all the people asking how to get a custom post type to work with the breadcrumbs, it does work. Just make sure you have you permalinks set to ‘POSTNAME’ it works once you’ve done that.

    I often don’t change that until I make the site live and couldn’t find it mentioned on this page.

Соmmеnt раgеs: « 1 9 10 11
Lеаvе а Соmmеnt

© 2009–2014 Dimox.net  •  Privacy Policy