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.
It worked like a charm. You made my day.
Thanx a ton :)
Great function, but it doesn’t seem to work when using a custom page template. Any idea what the problem is?
Scrap that! The call to the function hadn’t been added to the custom template! Doh!
Many thanks, this is an excellent solution.
Thanks for the code!
I was hoping to excluded my blog posts and only have pages included. Is there a way that know of to do this?
-Lee
Replace the first
} else {with} elseif (!is_single()) {I’ve updated the function – added the support of schema.org rich snippets for breadcrumbs.
Thanks for this function.
When viewing the post, I don’t want the post title to show so I just add:
if ( is_single()) $showCurrent = 0;When viewing an attachment, it throws an error:
Notice: Undefined offset: 0If I remove/comment this code, the image will display find:
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('', '' . $linkAfter, $cats);
echo $cats;
printf($link, get_permalink($parent), $parent->post_title);
if ($showCurrent == 1) echo $delimiter . $before . get_the_title() . $after;
}
How can this be fixed?
I don’t know what’s the reason. I have no any errors on attachments pages.
works like a charm! what a great time saver!
Can you *please* provide a downloadable file for this function? It is a total pain to cut and paste this code! I want a *file* not code on the screen. :-(
With all due respect, I think that’s more than fair given the routine is provided for free! A simple “click – hold – drag” took just 2-3 seconds for me.
For me it was much harder — took a number of tries and it really sucked that when I did a ’save page as’, the code was massively peppered with ’s, so I couldn’t just pull the page itself into my text editor and extract the code that way. I did eventualy get the code, but it was a massive hassle — I ended up using two clicks — the second with ’shift’ — I could not drag since I kept overshooting the end of the code — I need to drag the pointer off the bottom of the window to get the screen to scroll down. Copy and paste is fine for *small* snippets (ones that fit completely on the screen), but for longer pieces of code, it is always better to have a downloadable file. I guess I just don’t have the hand-eye coordination. Partly it was my laptop, with its small screen.
I’ve changed the code highlighter, so now you can hover the mouse on the code and click “Get the Code” link.
Thanks! :-)
Thanks for the code, mate. One issue though I’d like to share:
$cat = get_the_category();will get categories in random order, so a parent and children categories can be wrong.In order to fix this, replace the line with
$args = array('orderby' => 'id', 'order' => 'desc');$cat = wp_get_post_terms( $post->ID , 'category', $args);
Hi there,
I love this plugin so much, but when I paste the code into the function, everything is OK except the gallery in pages,
I insert the gallery in posts, they attachment page is OK,
but when I click the attachment the page, it get errors:
Object of class WP_Error could not be converted to string in
} elseif ( is_page() && $post->post_parent ) {
I want to hide the breadcrumb for date based archive only. How can I do it? What line do I have to change to do that or to create an option?
Personally I dislike the date based archive.
I’m sorry and thanks.
May be a simple edit I’m missing, but I’m working in a custom css Wordpress that I didn’t create and I need to center the breadcrumb. How to do this?
#crumbs {text-align: center}3.5.1 picture page display garbled!
I’m here to say thank you for your tutorial. This tutorial had help our site build a better breadcrumb. Looking for more tutorial from you.
Thank you once again.
It seems to have issues with pages that use pagination. Instead of being HOME » CONTENT » BLOG » PAGE 2, it comes out HOME » CONTENT » BLOGPAGE 2
This is the code that is used in Responsive theme. This code should be working.
http://pastebin.com/mYPY0WFn
Hi,
great function, really nice work. It works well, except I got this error:
on line
…
Any ideas ?
Don’t know the reason. I have no such error.
Possible to remove the hyperlinks for all level ?
Thanks
Perhaps it is possible to make somehow, but I can’t help.
it’s really nice function!
Would be great if you also provide some of CSS design options…
Thanks.
For anyone who wishes to hide the home crumb, a simple fix…
add too Options section:
$nohomecrumb = 1; // 1 - do not show crumb for home
change the following:
echo '' . sprintf($link, $homeLink, $text['home']) . $delimiter;to:
if($nohomecrumb == 1) {
echo '';
} else {
echo '' . sprintf($link, $homeLink, $text['home']) . $delimiter;
}
Thanks man, can I use this code in a commercial theme?
Yes, you can.
beautiful! thanks for the helpful function. seo could be improved by setting the $before and $after tags to h1
hi… i follow the instruction put in the code …
the breadcrumbs should be look like this in formal way
Home > Software Protection > Rockey 2
but when i click the rockey 2 button it just only show
Home > Rockey2
How to get the solution on this …. any one can help?
Software Protection is not the parent page of the Rockey 2, therefore it not appearing in this chain.
Hi Dimox,
I have a question, not sure if you can answer it. My WP template use a modified version of your breadcrumbs code. I have some issues that the output is not correct. Unfortunately the seller of the template don’t give a s**t on supporting his stuff, so i need to figure the issue out on my own. I found in the code that the source was origin from you, so i, well… need some help and hope to find it here ^^
Its a multilingual page (EN / JP) and the crumbs working fine in english but not in japanese. There the links beyond the displayed crumbs are correct, however the crumbs itself are only showing the “destination”, or the last page.
The link to the specific page (didn’t do more yet since figured out this issue) is here:
EN: (works) http://advantec-is.com/products/sonotron-ndt/isonic-utpod/?l=en
JP: (wrong) http://advantec-is.com/products/sonotron-ndt/isonic-utpod/?l=ja
Perhaps you can help me sorting that out, and i dont mind to donate for your support.
Thanks in advance & best regards
Startx04
…forgot… let me know what you need on further information..
Hi, I don’t understand what is the problem. I’m seeing full crumbs in both cases.
Thx for the quick response.
Right, they are there but the japanese version shows:
Home→ISONIC utPod→ISONIC utPod→ISONIC utPod
while it should be:
Home→Products→Sonotron NDT→ISONIC utPod
(Apart from the issue that the japanese title in the crumbs is not displayed as it should, but thats another issue)
Dimox, would you accept a job offer? I am thinking to send you my template and you help me fixing this issue.
I am not able to fix that and really need some support on that. No time to change everything over to a new template at the moment..
Give me a price and lets discuss. Let me know if you don’t want to support, then i need to look elsewhere since i cant fix that on my own.
Thanks
I’m getting error:
Catchable fatal error: Object of class WP_Error could not be converted to stringOn line:
$cat = get_the_category($parent->ID); $cat = $cat[0];Of:
} 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('', '' . $linkAfter, $cats);
echo $cats;
printf($link, get_permalink($parent), $parent->post_title);
if ($showCurrent == 1) echo $delimiter . $before . get_the_title() . $after;
Any ideas?
Thank you very much for this great code!
Daniel
Thank you for this function.
Any idea why the content marked up with RDFa is not valid in W3C?
thank you very much ;)