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 TitleBut all, what I have seen, displays only such an option (excluding plugins):
Home » Subcategory » Post TitleThe 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.
- paged navigation (like
-
adding a page number (if archive page is second or more);
-
custom symbol of delimiter;
-
custom text for a ‘Home’ link;
-
current crumb styling.
WordPress breadcrumbs function (last updated: 2013.01.04)
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
$showCurrent = 1; // 1 - show current post/page title in breadcrumbs, 0 - don't show
$showOnHome = 0; // 1 - show breadcrumbs on the homepage, 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;
$homeLink = get_bloginfo('url') . '/';
$linkBefore = '<span typeof="v:Breadcrumb">';
$linkAfter = '</span>';
$linkAttr = ' rel="v:url" property="v:title"';
$link = $linkBefore . '<a' . $linkAttr . ' href="%1$s">%2$s</a>' . $linkAfter;
if (is_home() || is_front_page()) {
if ($showOnHome == 1) echo '<div id="crumbs"><a href="' . $homeLink . '">' . $text['home'] . '</a></div>';
} else {
echo '<div id="crumbs" xmlns:v="http://rdf.data-vocabulary.org/#">' . sprintf($link, $homeLink, $text['home']) . $delimiter;
if ( is_category() ) {
$thisCat = get_category(get_query_var('cat'), false);
if ($thisCat->parent != 0) {
$cats = get_category_parents($thisCat->parent, TRUE, $delimiter);
$cats = str_replace('<a', $linkBefore . '<a' . $linkAttr, $cats);
$cats = str_replace('</a>', '</a>' . $linkAfter, $cats);
echo $cats;
}
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, $homeLink . '/' . $slug['slug'] . '/', $post_type->labels->singular_name);
if ($showCurrent == 1) echo $delimiter . $before . get_the_title() . $after;
} else {
$cat = get_the_category(); $cat = $cat[0];
$cats = get_category_parents($cat, TRUE, $delimiter);
if ($showCurrent == 0) $cats = preg_replace("#^(.+)$delimiter$#", "$1", $cats);
$cats = str_replace('<a', $linkBefore . '<a' . $linkAttr, $cats);
$cats = str_replace('</a>', '</a>' . $linkAfter, $cats);
echo $cats;
if ($showCurrent == 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($post->post_parent);
$cat = get_the_category($parent->ID); $cat = $cat[0];
$cats = get_category_parents($cat, TRUE, $delimiter);
$cats = str_replace('<a', $linkBefore . '<a' . $linkAttr, $cats);
$cats = str_replace('</a>', '</a>' . $linkAfter, $cats);
echo $cats;
printf($link, get_permalink($parent), $parent->post_title);
if ($showCurrent == 1) echo $delimiter . $before . get_the_title() . $after;
} elseif ( is_page() && !$post->post_parent ) {
if ($showCurrent == 1) echo $before . get_the_title() . $after;
} elseif ( is_page() && $post->post_parent ) {
$parent_id = $post->post_parent;
$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) echo $delimiter . $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;
}
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>';
}
} // end dimox_breadcrumbs()
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.
вариант для категорий, если необходимо добавить микродаты:
$currentCat = get_category(get_query_var('cat'),false);if ($currentCat->category_parent) :
$parentCats = get_category($currentCat->category_parent);
echo '<li><a href="' . get_category_link( $parentCats->term_id ) . '" title="' . sprintf( __( "View all posts in %s" ), $parentCats->name ) . '" >' . $parentCats->name.'</a></li>';
endif;
echo '<li>' . $before . single_cat_title('', false) . $after . '</li>';
PS. В примере парсит только один уровень родительской категории.
вывод категорий для постов:
найти:
$cat = get_the_category(); $cat = $cat[0];$cats = get_category_parents($cat, TRUE, ' ' . $delimiter . ' ');
заменить на:
$cat = get_the_category(); $cat = $cat[0];if ($cat) :
$cats = get_category_parents($cat, TRUE, ' ' . $delimiter . ' ');
endif;
необходимо в случае, если не задана категория поста. По умолчанию выводится “без категории”, но дебагер выдает ошибку – “$cat не существует”
Ну конечно же, было бы неплохо увидеть текстовые домены. а их нет ни одного…
Hi,
I think you must change, because on some theme and new wordpress version not want to work…
$homeLink = home_url();to
$homeLink = home_url();uh sorry code is:
$homeLink = get_bloginfo('url');to
$homeLink = home_url();Yes sir, that’s what I said last month http://dimox.net/wordpress-breadcrumbs-without-a-plugin/comment-page-8/#comment-1522
Thanks,
Emil
I would like to change the order of the breadcrumb so that instead of:
grandparent > parent > child > grandchild
it would be:
grandchild < child < parent < grandparent
Is that possible ?
Thank you.
Sorry, not possible.
Actually you can, float the anchors right with CSS. This will reverse the order and you could set the delimiter to « and wrap it in a span and float it as well. :)
Hey,
is there a possibility to have a breadcrumb with the Category Base?
for Categories: Home > Category Base > Category
for single posts: Home > Category Base > Category > Post
Regards!
Hi,
Love using this. Wondering if there is a possibility of supporting post formats? So for example if we go to “image” post format link, it will show as
Home > Posts under "image" formator something like that.
Thanks in advance.
Hi – Thanks for this code. It is working great for me, except for one little problem with posts.
When something is tagged with two top-level categories, the breadcrumb includes one of them, apparently chosen randomly (or the first in alpha or category id order?) For example: I have a post with category “News” and category “Kenya” – the breadcrumb shows “Kenya” and ignores “News”. Is there a way to dynamically insert the category based on on referring URL?
Theme is Vigilance pro, if that matters.
Thank you!
Sorry, I have no idea how to make this.
if you want to show parent of custom post type single page
from this: home > post_type_name > post
to this: home > post_type_name > post_parent >post
if ( get_post_type() != 'post' ) {$post_type = get_post_type_object(get_post_type());
$slug = $post_type->rewrite;
echo '<a href="' . $homeLink . '/' . $slug['slug'] . '/" rel="nofollow">' . $post_type->labels->name . '</a>';
if ($post->post_parent){
$ancestors=get_post_ancestors($post->ID);
$root=count($ancestors)-1;
$parent = $ancestors[$root];
echo '<a href="' .get_permalink($parent). '/" rel="nofollow">' . get_the_title($parent) . '</a>';
};
First of all, great function! :)
Is there anyway of getting this to work directly from menus created in:
dashboard->appearence->menus?
I create menus this way and it’s duplicate effort if have to then go into each page and select a parent etc.
Thanks so much
I don’t understood you.
Apologies i will try to be more clear.
If generate my navigation from wp_nav_menu function. The navigation is created by creating a menu in dashboard->appearance->menus.
The problem is that when i use your function, it doesn’t match the different levels of the menu here. It will always only give me:
Home -> Current page
Even if the actual trail is:
Home -> Parent -> Child (current page)
If however i go to:
Dasboard-Pages->Whatever the current page is
And i select the page parent here and update the page, the breadcrumb will then display correctly.
So what I’m saying is if there is anyway I can get around having to do this for every page? Can the function create the breadcrumb based on what I have created in Dashboard->Appearence->Menus without having to specify the parent in Dashboard->pages>the page?
Hopefully that is clearer :)
Thanks
Now I understood. No, this not possible with my function and I don’t know how to make this possible.
great!!! :)
Hi Dimox, thanks for the function!
Im using in my blog, it works but not in all subcategories, i have problems in the breadcrumb subcategory output in the single post view:
Correct output showing the subcategory Cortometrajes:
Inicio » Entretenimiento » Cortometrajes » The Gift (2010) de Carl Rinsch
Incorrect output, missing the subcategory Trailers:
Inicio » Entretenimiento » ¿? ParaNorman (2012)
Both posts have published with marked category and subcategory.
I think the problem is when the first letter of subcategory is low in the abecedari than the first letter of category, in this case the subcategory don’t show, an example on the menu of my blog:
Cine-TV
— Películas (DON’T WORK)
— Series (DON’T WORK)
Entretenimiento
— Canciones (WORK)
— Cortometrajes (WORK)
— Imágenes (DON’T WORK)
— Miniseries (DON’T WORK)
— Programas TV (DON’T WORK)
— Trailers (DON’T WORK)
— Videoclips (DON’T WORK)
— Vídeos (DON’T WORK)
Do you have any idea of how to fix this?
Select only category or only subcategory (not both at the same time) and breadcrumb will be correct.
Thanks Dimox, yes, i know this solution, but there is no way for obtain the real hierarchy in the function and maintain posts with marked category and subcategory?
No way. That’s a feature of the
get_category_parents()WordPress function.sorry, wanted to say when the first letter of category is first in the alphabet than the first letter of subcategory.
Thankyou for this! Nice and easy.
I am using buddypress with wordpress and if you click on a specific member’s profile their page does not appear in the breadcrumb. This is the same case for groups and forum. It will remain saying Home >> Members or Home >> Groups. Is there any way to change this?
I have not used buddypress, so can’t help anything.
Nice job! I appreciate the light-weight, quick block of code. Solved my issue quickly. Thank you for sharing.
Thanks for the script! A little tweaking for the fact that I always custom-build themes.
Hi. Love the script, one slight issue, wonder if you can help?.
On my pages the script works perfectly however once I click on a post, which is categorised under Parent>Child>Post, the breadcrumbs link add in the word category to the links so the breadcrumb links to Home>Category>Parent>Child>Post which doesn’t exist.
How do I remove the category that gets added in?
I don’t know what’s the reason of that.
I have the same problem. Did you manage to find a solution?
Anyone have any ideas as to what this could be?
Playing around with the permalink settings doesn’t help either. It’s strange if I change the ‘category base’ setting in the permalinks dialog, the breadcrumbs category link will point to that change but the page will still not show. Instead I get a blank white page, not even the 404.
Anyone have any ideas? Desperate to get this to work )-:
Thanks!
This tutorial is awesome!!! Thanks!!! works!!!
:D ~ now it works.
I forgot that I have created a ‘fullwidth’ template for the ‘Page’ and didn’t add the breadcrumb. No wonder it didn’t show.
Good code snippet you have there! thanks again! :)
Very easy to implement, thanks for us un-skilled in php.
But i’d like to completely remove the Start Home page Home-page1-page1.
Because i use it in a page already, with a nav menu in place some where else. Should only be used as navigation index on 1 page.
right now , there is only the option to hide, it buy the seperators will still be placed before the 1st menu item, and that looks ugly.Want it only to be placed after page1- not -page1-
because there is no menu item before the 1st one…
Hi, Dimox,
I’ve combined this “WordPress Breadcrumbs Without a Plugin” function and 3 different CSS3 styles. I’d like to know: What is the license for this work? Am I free to share your code, non-commercial as-is? I am giving credit to you, of course.
You can see the CSS3/WordPress breadcrumb “mash-up” on my blog here:
How to Make CSS3 Style WordPress Breadcrumb Navigation
Thanks,
Brian
You can use it with a Creative Commons license.
nice job buddy works pretty fine
This snippet was not working for the password neither protected ‘Post’ or ‘Page’ until I removed this part:
} elseif ( is_attachment() ) {$parent = get_post($post->post_parent);
$cat = get_the_category($parent->ID); $cat = $cat[0];
echo get_category_parents($cat, TRUE, ' ' . $delimiter . ' ');
echo '' . $parent->post_title . '';
if ($showCurrent == 1) echo ' ' . $delimiter . ' ' . $before . get_the_title() . $after;
and replaced it with this:
} elseif ( !is_single() && !is_page() && get_post_type() != 'post' && post_password_required() ) {$parent = get_post($post->post_parent);
$cat = get_the_category($parent->ID); $cat = $cat[0];
echo get_category_parents($cat, TRUE, ' ' . $delimiter . ' ');
echo '' . $parent->post_title . '';
if ($showCurrent == 1) echo ' ' . $delimiter . ' ' . $before . get_the_title() . $after;
Now for the password protected ‘Page’ this snippet works just fine.
But I wonder why for the password protected ‘Post’ this snippet is only showing the image attachment? even after a user entered the password?
Also It will only display the full content in the homepage and not in the archive page.
Any clue of how to fix this?
Thanks!
Hi Dimox, great code, thank you. Tried to add a function no minimize the title length (in best case everywhere, parents, children AND current title, but don’t get it running, any idea?
Cheers, gbennyb
define('BREADCRUMB_TITLE_SIZE', '5');
function dimox_breadcrumbs() {
$showOnHome = 0; // 1 - show breadcrumbs on the homepage, 0 - don't show
//$delimiter = '⇨'; // delimiter between crumbs - TODO pfeil
$delimiter = '';
$home = ' '; // text for the 'Home' link
$showCurrent = 1; // 1 - show current post/page title in breadcrumbs, 0 - don't show
$before = ''; // tag before the current crumb
$after = ''; // tag after the current crumb
global $post;
$homeLink = get_bloginfo('url');
if (is_home() || is_front_page()) {
if ($showOnHome == 1) echo '' . $home . '';
} else {
echo '' . $home . ' ' . $delimiter . ' ';
if ( is_category() ) {
global $wp_query;
$cat_obj = $wp_query->get_queried_object();
$thisCat = $cat_obj->term_id;
$thisCat = get_category($thisCat);
$parentCat = get_category($thisCat->parent);
if(strlen($parentCat->name) > intval(BREADCRUMB_TITLE_SIZE)) {
$parentCat->name = substr($parentCat->name, 0, intval(BREADCRUMB_TITLE_SIZE)).'...';
}
$catTitle = single_cat_title('', false);
if(strlen($catTitle) > BREADCRUMB_TITLE_SIZE) {
$catTitle = substr($catTitle, 0, BREADCRUMB_TITLE_SIZE).'...';
}
if ($thisCat->parent != 0) echo(get_category_parents($parentCat, TRUE, ' ' . $delimiter . ' '));
echo $before . '' . $catTitle . '' . $after;
} elseif ( is_day() ) {
echo '' . get_the_time('Y') . ' ' . $delimiter . ' ';
echo '' . get_the_time('F') . ' ' . $delimiter . ' ';
echo $before . get_the_time('d') . $after;
} elseif ( is_month() ) {
echo '' . 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;
echo '' . $post_type->labels->singular_name . ' ' . $delimiter . ' ';
if ($showCurrent == 1) echo $before . get_the_title() . $after;
} else {
$cat = get_the_category(); $cat = $cat[0];
echo get_category_parents($cat, TRUE, ' ' . $delimiter . ' ');
if ($showCurrent == 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($post->post_parent);
$cat = get_the_category($parent->ID); $cat = $cat[0];
echo get_category_parents($cat, TRUE, ' ' . $delimiter . ' ');
echo '' . $parent->post_title . ' ' . $delimiter . ' ';
if ($showCurrent == 1) echo $before . get_the_title() . $after;
} elseif ( is_page() && !$post->post_parent ) {
if ($showCurrent == 1) echo $before . get_the_title() . $after;
} elseif ( is_page() && $post->post_parent ) {
$parent_id = $post->post_parent;
$breadcrumbs = array();
while ($parent_id) {
$page = get_page($parent_id);
$breadcrumbs[] = 'ID) . '">' . get_the_title($page->ID) . '';
$parent_id = $page->post_parent;
}
$breadcrumbs = array_reverse($breadcrumbs);
foreach ($breadcrumbs as $crumb) echo $crumb . ' ' . $delimiter . ' ';
if ($showCurrent == 1) echo $before . get_the_title() . $after;
} elseif ( is_search() ) {
echo $before . 'Suchergebnisse für "' . get_search_query() . '"' . $after;
} elseif ( is_tag() ) {
echo $before . 'Schlagwort "' . single_tag_title('', false) . '"' . $after;
} elseif ( is_author() ) {
global $author;
$userdata = get_userdata($author);
echo $before . 'Erstellt von ' . $userdata->display_name . $after;
} elseif ( is_404() ) {
echo $before . 'Kein passender Inhalt gefunden / Seite nicht gefunden' . $after;
}
if ( get_query_var('paged') ) {
if ( is_category() || is_day() || is_month() || is_year() || is_search() || is_tag() || is_author() ) echo ' (';
echo 'Seite ' . ' ' . get_query_var('paged');
if ( is_category() || is_day() || is_month() || is_year() || is_search() || is_tag() || is_author() ) echo ')';
}
echo '';
}
} // end dimox_breadcrumbs()
Hey,
Is there a way to display breadcrumbs on a post that contain parent and child page links instead of category links?
I’m not using Categories. I have custom taxonomies, so I want to use them to create an “if post is in this custom taxonomy, then show this parent and child page breadcrumb”.
Ex – if “Maytag 3000″ post is in the “Dishwasher” custom taxonomy then I’d want the breadcrumb to be:
Home >> Appliances >> Dishwasher >> Maytag 3000
The “Appliances” link goes to the Appliance Page (that I created) and “Dishwashers” link goes to the Dishwasher Page (that I created).
I’ve been searching everywhere for this and just can’t find it.
Thanks in advance.
Hi!
Beautiful work on this. I’m using a theme where your code is incorporated, and it has a link to this page here.
I’m wondering, is it possible to display just home » parent » current crumbs, instead of the whole chain? The thing is I don’t need to display the “archives” crumb, just “Home » Portfolio » Graphics” for instance. The original code would display “archives between Home and Portfolio.
Hi, I’m not using a static page for the blog/posts page. Instead I am using blog.php
I now find that the breadcrumb link to blog while viewing blog posts doesn’t link back to the actual blog page.
Home » Blog » Uncategorized » Some Post
When clicking blog it just links back to the same post instead of blog page.
Any help for this?
Awesome breadcrumbs! This is exactly what I was looking for since I couldn’t find breadcrumbs for PAGES in wordpress, all of them where for posts, but this works awesomely for pages too! Thanks a lot for saving me a lot of time!
Thank you for your information :D
finally, I have a breadcrumb
sorry, forget to ask this question
“Can i attach your code in my new article (not publish yet) about -”Membuat Breadcrumb Untuk template Wordpress Twenty Twelve”. In Inggris ” How to Make Breadcrumb for Twenty Twelve Wordpress template”?
I will link to this page as the source of the code. Can I?
Yes, you can.