How To Add WordPress Breadcrumbs Without a Plugin
Breadcrumbs or breadcrumb trail is a navigation aid used in a Website. It gives users a way to keep track of their locations within the Website. Breadcrumbs typically appear horizontally at the top of a Web page. Breadcrumbs provide a trail for the user to follow back to the starting or entry point.
Breadcrumb trail is an important supplementary element of a Website´s navigation, especially for complex Websites. It improves usability, enhances user experience and it is better for SEO. Don´t take my word for it, Google recommends using Breadcrumbs in their SEO starter guide. Also Google is integrating breadcrumbs navigation within the Search Engine Results Pages.
Breadcrumbs are especially useful for complex Websites containing many pages and sub-pages, and organized into many categories. On the other hand, breadcrumbs for simple Websites are not really necessary.
The picture below shows examples of breadcrumb trails generated from this blog. This blog is using the breadcrumb code shown below, browse the various sections of this blog and see how it behaves.
Yes, there are plugins for WordPress breadcrumbs, such as BreadCrumb NavXT. But haven´t you read my previous post about the disadvantages of going crazy adding plugins to your theme? Also what would you do if you want to develop a theme with a built-in breadcrumb trail.
There is one disadvantage of using breadcrumbs, it increases the number of query requests to your database, and thus a slighter increase in load time. However, this could be neutralized with a caching mechanism implemented to your Website. Again, haven´t you read my previous post about the advantages of caching a dynamic Webiste? I believe that the benefits of breadcrumbs: better user experience, and making the Website friendlier for Search Engines, far outweighs its one disadvantage. Breadcrumb navigation is important for usability and for SEO, especially for complex Websites.
My Breadcrumbs Code: Supported Features
The code below display breadcrumb trail for:
- Single post listed in one category.
- Single post listed in multiple categories that are at the same level.
- Category and sub-category archives.
- Tag archive.
- Yearly archive.
- Monthly archive.
- Daily archive.
- Author archive.
- Search result page.
- Top-level pages (top-level menu).
- Multi-level sub-pages (multi-level sub-menus).
- 404 Not found Error page.
The code below also features:
- Complete or shortened post titles.
- Two custom delimiters. Same level categories use a different delimiter.
Also the code below works in both cases when:
- Your Website´s Front page displays your latest posts.
- Your Website´s Front page displays a static page and your posts are located somewhere else.
To better explain: the default WordPress settings is shown below. If you choose the other option: "Front page displays -> a static page (select below)", the breadcrumb code still works.
My Breadcrumbs Code: NOT Supported Features
The code below does not support:
- Adding a page number at the end of the trail.
- Attachments.
- Custom post types.
- Custom taxonomies.
- A single post listed in a top category AND in a subcategory (or subcategories). An unlikely case, where you get a mix up of delimiters.
WordPress Breadcrumbs Function Code
This is my version of the WordPress breadcrumbs code. Open the functions.php file located in your theme´s folder and add (copy and paste) the following function. Sorry for the long code, but I commented it so you understand better what´s going on.
Note: To scroll within the code: You can also click on the code window and use your keyboard´s arrow keys.
<?php /*********************************************************************** * @Author: Boutros AbiChedid * @Date: February 14, 2011 * @Copyright: Boutros AbiChedid (http://bacsoftwareconsulting.com/) * @Licence: Feel free to use it and modify it to your needs but keep the * Author's credit. This code is provided 'as is' without any warranties. * @Function Name: wp_bac_breadcrumb() * @Version: 1.0 -- Tested up to WordPress version 3.1.2 * @Description: WordPress Breadcrumb navigation function. Adding a * breadcrumb trail to the theme without a plugin. * This code does not support multi-page split numbering, attachments, * custom post types and custom taxonomies. ***********************************************************************/ function wp_bac_breadcrumb() { //Variable (symbol >> encoded) and can be styled separately. //Use >> for different level categories (parent >> child >> grandchild) $delimiter = '<span class="delimiter"> » </span>'; //Use bullets for same level categories ( parent . parent ) $delimiter1 = '<span class="delimiter1"> • </span>'; //text link for the 'Home' page $main = 'Home'; //Display only the first 30 characters of the post title. $maxLength= 30; //variable for archived year $arc_year = get_the_time('Y'); //variable for archived month $arc_month = get_the_time('F'); //variables for archived day number + full $arc_day = get_the_time('d'); $arc_day_full = get_the_time('l'); //variable for the URL for the Year $url_year = get_year_link($arc_year); //variable for the URL for the Month $url_month = get_month_link($arc_year,$arc_month); /*is_front_page(): If the front of the site is displayed, whether it is posts or a Page. This is true when the main blog page is being displayed and the 'Settings > Reading ->Front page displays' is set to "Your latest posts", or when 'Settings > Reading ->Front page displays' is set to "A static page" and the "Front Page" value is the current Page being displayed. In this case no need to add breadcrumb navigation. is_home() is a subset of is_front_page() */ //Check if NOT the front page (whether your latest posts or a static page) is displayed. Then add breadcrumb trail. if (!is_front_page()) { //If Breadcrump exists, wrap it up in a div container for styling. //You need to define the breadcrumb class in CSS file. echo '<div class="breadcrumb">'; //global WordPress variable $post. Needed to display multi-page navigations. global $post, $cat; //A safe way of getting values for a named option from the options database table. $homeLink = get_option('home'); //same as: $homeLink = get_bloginfo('url'); //If you don't like "You are here:", just remove it. echo 'You are here: <a href="' . $homeLink . '">' . $main . '</a>' . $delimiter; //Display breadcrumb for single post if (is_single()) { //check if any single post is being displayed. //Returns an array of objects, one object for each category assigned to the post. //This code does not work well (wrong delimiters) if a single post is listed //at the same time in a top category AND in a sub-category. But this is highly unlikely. $category = get_the_category(); $num_cat = count($category); //counts the number of categories the post is listed in. //If you have a single post assigned to one category. //If you don't set a post to a category, WordPress will assign it a default category. if ($num_cat <=1) //I put less or equal than 1 just in case the variable is not set (a catch all). { echo get_category_parents($category[0], true,' ' . $delimiter . ' '); //Display the full post title. echo ' ' . get_the_title(); } //then the post is listed in more than 1 category. else { //Put bullets between categories, since they are at the same level in the hierarchy. echo the_category( $delimiter1, multiple); //Display partial post title, in order to save space. if (strlen(get_the_title()) >= $maxLength) { //If the title is long, then don't display it all. echo ' ' . $delimiter . trim(substr(get_the_title(), 0, $maxLength)) . ' ...'; } else { //the title is short, display all post title. echo ' ' . $delimiter . get_the_title(); } } } //Display breadcrumb for category and sub-category archive elseif (is_category()) { //Check if Category archive page is being displayed. //returns the category title for the current page. //If it is a subcategory, it will display the full path to the subcategory. //Returns the parent categories of the current category with links separated by '»' echo 'Archive Category: "' . get_category_parents($cat, true,' ' . $delimiter . ' ') . '"' ; } //Display breadcrumb for tag archive elseif ( is_tag() ) { //Check if a Tag archive page is being displayed. //returns the current tag title for the current page. echo 'Posts Tagged: "' . single_tag_title("", false) . '"'; } //Display breadcrumb for calendar (day, month, year) archive elseif ( is_day()) { //Check if the page is a date (day) based archive page. echo '<a href="' . $url_year . '">' . $arc_year . '</a> ' . $delimiter . ' '; echo '<a href="' . $url_month . '">' . $arc_month . '</a> ' . $delimiter . $arc_day . ' (' . $arc_day_full . ')'; } elseif ( is_month() ) { //Check if the page is a date (month) based archive page. echo '<a href="' . $url_year . '">' . $arc_year . '</a> ' . $delimiter . $arc_month; } elseif ( is_year() ) { //Check if the page is a date (year) based archive page. echo $arc_year; } //Display breadcrumb for search result page elseif ( is_search() ) { //Check if search result page archive is being displayed. echo 'Search Results for: "' . get_search_query() . '"'; } //Display breadcrumb for top-level pages (top-level menu) elseif ( is_page() && !$post->post_parent ) { //Check if this is a top Level page being displayed. echo get_the_title(); } //Display breadcrumb trail for multi-level subpages (multi-level submenus) elseif ( is_page() && $post->post_parent ) { //Check if this is a subpage (submenu) being displayed. //get the ancestor of the current page/post_id, with the numeric ID //of the current post as the argument. //get_post_ancestors() returns an indexed array containing the list of all the parent categories. $post_array = get_post_ancestors($post); //Sorts in descending order by key, since the array is from top category to bottom. krsort($post_array); //Loop through every post id which we pass as an argument to the get_post() function. //$post_ids contains a lot of info about the post, but we only need the title. foreach($post_array as $key=>$postid){ //returns the object $post_ids $post_ids = get_post($postid); //returns the name of the currently created objects $title = $post_ids->post_title; //Create the permalink of $post_ids echo '<a href="' . get_permalink($post_ids) . '">' . $title . '</a>' . $delimiter; } the_title(); //returns the title of the current page. } //Display breadcrumb for author archive elseif ( is_author() ) {//Check if an Author archive page is being displayed. global $author; //returns the user's data, where it can be retrieved using member variables. $user_info = get_userdata($author); echo 'Archived Article(s) by Author: ' . $user_info->display_name ; } //Display breadcrumb for 404 Error elseif ( is_404() ) {//checks if 404 error is being displayed echo 'Error 404 - Not Found.'; } else { //All other cases that I missed. No Breadcrumb trail. } echo '</div>'; } } ?>
After adding the above function in your functions.php file, copy and paste the code below in the header.php file located in your theme´s folder. Place the following code where you want the breadcrumb trail to appear.
CODE-2:
<?php //function_exists() — Return TRUE if the given function has been defined. //code by BOUTROS ABICHEDID. Adding breadcrumb trail to the WordPress theme. if (function_exists('wp_bac_breadcrumb')) {wp_bac_breadcrumb();} ?>
The easiest way is to place the above code (CODE-2) in your theme´s header.php file. If you decide otherwise, then you need to place it in multiple files like: single.php, archive.php, search.php, page.php (custom-page.php if you have one) and probably in other files depending on your theme. Did you get the point that adding it to the header.php is simpler?
Styling the Breadcrumbs
Finally we need to style the breadcrumb trail with CSS. The following code is what I used to style the breadcrumb navigation for this blog. The code should be added to your theme´s CSS file (usually called style.css). Of course go ahead and change it to fit your design.
/* Styling Breacrumb Navigation by BOUTROS ABICHEDID */ .breadcrumb{ width:645px; float:left; padding:0 0 0 47px; margin:9px 0 0 0; font-size:90%; clear:both; } .delimiter{ color:#000; background-color:inherit; } .delimiter1{ color: #627FC3; background-color:inherit; }
Conclusion
You now have the breadcrumbs code that can be used on any WordPress Website. If you have any questions, or if you have other ideas on how to improve and add more functionality to the code, be sure to leave a comment!
Hi Boutros,
I’m really liking the code that you’ve provided and so good to not have to really on a chunky plugin to do the job.
One mod that I would like is the option to hide the breadcrumbs on certain pages. Are you able to let me know which part of the code to modify?
Many thanks :-)
Tim
Hi Tim,
If you want to hide breadcrumb Trail on certain pages. Then you need to modify CODE-2 to the following. I am assuming that you put CODE-2 in your header.php file.
First you need to find the page ID . If you don´t know how to find the page ID, read my previous tutorial on How To Find the Page ID.
Let’s assume that you want to exclude 1 page. Then CODE-2 above becomes:
If you want to exclude 2 pages, then CODE-2 above becomes (and you got the picture for more pages to exclude)
Remember that the number for page IDs are just an example and you need to replace them with your actual page IDs that you obtain from your WordPress Admin.
Let me know if this helps (or Not).
Boutros.
Boutros! Perfect!!! Exactly the mod I was needing. Now my site looks perfect!! Thanks so much for your help!
Tim
And another thing – in my case i had to remove the first and last line in the function code cause it was causing an error.
Hi,
great code, love doing stuff without a plugin!
However, I have only one problem – length of the post title, it doesn’t get cut off. There’s a function in your code to cut off the title after 30 characters, but it’s not applied. How come? Any ideas? I’ve done and copied everything exactly like here.
Hi,
I am not sure why? in my blog it cuts off the title at 30 characters (or whatever number i set it). You can check longer posts’ titles.
Great code – I really appreciate being able to manually add it in lieu of a plugin!
A tiny bug in the code:
if (!is_front_page()) {
echo ”;
/* The rest of the function …*/
}
echo ”;
Needs to become :
if (!is_front_page()) {
echo ”;
/* The rest of the function …*/
echo ”; /*DIV INSIDE FUNCTION*/
}
Or else it outputs a lonely ” on the frontpage..
Thank you Glenn for your Comment:
Are you talking about the:
echo ”; //on line 160?
You are right it should be inside the function, (i.e. It should be one line up before the closing bracket ‘}’ (on line 159. Which I updated the code).
But frankly it would not have made any difference. I can’t duplicate what you see (Or else it outputs a lonely ” on the frontpage..). The front page is fine in this blog and other blogs where I use the function.
Boutros.
Thank you! Great piece of code!
You have great points. That’s why I love checking out your blog.
That fixed it :) Thank you so much, this really helped me out. I will definitely be using this code on future sites too.
Jo
Hi, Thank you for providing this code. I have tried 3 or 4 different examples of wordpress breadcrumbs and yours has been the best!
Only one problem now – if I am viewing a subpage, the page ID of the parent page is being displayed to the left of the link for the parent page, e.g:
You are here: Home » 32About us » F.O.A Trust (UK) Policies
Any suggestions on how this could be fixed? Thank you in advance for any help you can give me.
Jo
Hi Jo,
Thank you for noticing that. I am pretty sure, when I tested the code for submenus and other things, that it was working fine in WP version2.9.
In any case, the fix is quite simple:
Replace line 128: $post_array = get_post_ancestors(the_ID());
With: $post_array = get_post_ancestors($post);
That should do the trick. I fixed the above code accordingly.
Let me know if it works for you now.
Boutros.
Many thanks your code works perfectly on my site.
You are Welcome Luishi.
Hi there,
I like the intent here – I am not a coder at all … I have a wordpress template with a plugin that came with it – I like it overall, except it does not show the full path like you do.
I tried to add in your code to the breadcrumb.php file that came with the widget – it works for the most part, but the delimiters all seem to show up at the end.
Could I trouble you to take a peek at the site / php file and steer me in the right direction?
Hi Tim,
What is your Website’s address? Also what theme you are using so that I could take a look at the source code.
Thanks,
Boutros.
Hey, first of all thanks for this fantastic work.
I Like the way you commented on every single line and explained properly what’s happening.
I’ve implemented your code to one of wordpress blogs but I didn’t get the exact result I wanted to achieve. Now the thing I want to achieve is that: let’s say there is a post listed under a first level category “Teknik” and two 2nd level categories of teknik “Foto & Video” and “Tester”. I want a breadcrumb in the following fashion:
Start > Teknik > Foto & Video • Tester > The post title
However, I couldn’t achieve this with your code. Instead, the breadcrumb generated looks like this – http://yfrog.com/gyffqup
So any idea on how to achieve this?
Regards and keep up good work.
Hi Metin,
Thank you for your comment. Your example is exactly what I was not able to do when I wrote the code (I tried and tested for several hours). The combinations are endless when you start categorizing a post in top level categories AND in subcategories. What about if a post is ONLY listed in a second level category (a sub-category), what the breadcrumb code will do? (I did not check for that).
One way to fix this is modify the code to just display the first category in the breadcrumb trail (and forget about the subcategories or any other top level categories). The other way maybe you think about categorizing differently your posts and get rid of the sub-categories all together. Just a thought…
If you find a solution, please share it here so everybody can learn. Thanks.
I wanted to do the same as Metin. I seem to have ended up with a situation now where my pages work in the hierarchy I want them to and when it comes to a single post with multiple categories I get them individually bullet pointed.
eg >> #parentcategory #parentcategory #childcategory #childcategory >> post
The original implementation of your code resulted in duplicates of the parent, and child categories.
Ultimately I’d prefer to be able to group parent categories and child categories in this way but my knowledge doesn’t stretch that far.
eg >> #parent #parent >> #child #child >> post
Getting to this point has seen me building on the efforts of about five or six of you:
http://diythemes.com/thesis/rtfm/breadcrumbs-without-plugins/
http://wordpressskins.org/wordpress-breadcrumbs-without-a-plugin/202/
http://lianko.com/2010/11/06/tutorial-wordpress-breadcrumbs-without-a-plugin/
http://thesisthemetools.com/tutorial-easy-breadcrumbs-without-a-plugin
http://dimox.net/wordpress-breadcrumbs-without-a-plugin
The code I’m currently using is this:
function my_breadcrumbs() {
$delimiter = ‘ » ‘;
$delimiter1 = ‘ • ‘;
$main = ‘Home’;
$maxLength= 30;
$arc_year = get_the_time(‘Y’);
$arc_month = get_the_time(‘F’);
$arc_day = get_the_time(‘d’);
$arc_day_full = get_the_time(‘l’);
$url_year = get_year_link($arc_year);
$url_month = get_month_link($arc_year,$arc_month);
echo ”;
global $post, $cat;
$homeLink = get_option(‘home’);
echo ‘‘ . $main . ‘‘ . $delimiter;
if (is_category() || is_single()) {
echo the_category ($delimiter1);
if (is_single()) {
echo ” $delimiter ” ;
the_title();
}
}
elseif (is_category()) {
echo ‘Archive Category: “‘ . get_category_parents($cat, true,’ ‘ . $delimiter . ‘ ‘) . ‘”‘ ;
}
elseif ( is_tag() ) {
echo ‘Posts Tagged: “‘ . single_tag_title(“”, false) . ‘”‘;
}
elseif ( is_day()) {
echo ‘‘ . $arc_year . ‘ ‘ . $delimiter . ‘ ‘;
echo ‘‘ . $arc_month . ‘ ‘ . $delimiter . $arc_day . ‘ (‘ . $arc_day_full . ‘)’;
}
elseif ( is_month() ) {
echo ‘‘ . $arc_year . ‘ ‘ . $delimiter . $arc_month;
}
elseif ( is_year() ) {
echo $arc_year;
}
elseif ( is_search() ) {
echo ‘Search Results for: “‘ . get_search_query() . ‘”‘;
}
elseif ( is_page() && !$post->post_parent ) {
echo get_the_title();
}
elseif ( is_page() && $post->post_parent ) {
$post_array = get_post_ancestors(the_ID());
krsort($post_array);
foreach($post_array as $key=>$postid){
$post_ids = get_post($postid);
$title = $post_ids->post_title;
echo ‘‘ . $title . ‘‘ . $delimiter;
}
the_title();
}
elseif ( is_author() ) {
global $author;
$user_info = get_userdata($author);
echo ‘Archived Article(s) by Author: ‘ . $user_info->display_name ;
}
elseif ( is_404() ) {
echo ‘Error 404 – Not Found.’;
}
else {
}
echo ”;
}
function breadcrumbs() {
if (is_front_page()) { } else {
?><?php
}
}
Thank you Roberto for your comment and sharing your code and all the wonderful additional resources for writing the breadcumb code. Obviously, my code has limitations and I don’t have the time to work on it and improve it.
Good Luck!
Boutros.