There are plenty of examples for how to add breadcrumbs to your WordPress site without needing a plugin, but all of them are normal functions. If you wanted two slightly different breadcrumbs, say, in different hooks, then you’d need two functions.
I decided to write a breadcrumb class that’s very easy to use, and I took my inspiration from the rockingwp.com’s Adding Detailed Breadcrumbs to the Thesis Theme (site appears dead) post as I also use the Thesis theme.
An alternative version of this class file that swaps a bit of user friendliness for lots of advantages is available at WordPress Breadcrumbs Class Alternative.
The Class File
First, add the following to a new file called GT_Breadcrumbs.php, and upload it to your theme. For Thesis theme users I recommend adding a classes folder inside the custom directory and saving the file there.
<?php
/**
* Allows breadcrumb trails to be added
*
* @package GT_Breadcrumbs
* @author Gary Jones
* @version 2010-06-06
* @since 2010-03-16
*/
class GT_Breadcrumbs {
/**
* @var string
*/
protected $_wrapperclass;
/**
* @var string
*/
protected $_roottext;
/**
* @var string
*/
protected $_tagtext;
/**
* @var string
*/
protected $_categorytext;
/**
* @var string
*/
protected $_archivetext;
/**
* @var string
*/
protected $_searchtext;
/**
* @var string
*/
protected $_404text;
/**
* @var string
*/
protected $_authortext;
/**
* @var string
*/
protected $_separator;
/**
* @var string
*/
protected $_showonhomepage;
/**
* PHP4 compatible constructor
*/
public function GT_Breadcrumbs() {
if(version_compare(PHP_VERSION,"5.0.0","__construct($arg);
register_shutdown_function(array($this,"__destruct"));
}
}
/**
* Set up our options
*
* @param string $wrapperclass Name of the class to use for the wrapper
*/
public function __construct() {
/* Set defaults */
$this->_wrapperclass = 'breadcrumbs';
$this->_roottext = 'Home';
$this->_tagtext = 'Tag';
$this->_categorytext = 'Category';
$this->_archivetext = 'Archive';
$this->_searchtext = 'Search';
$this->_404text = 'Not Found';
$this->_authortext = 'Author';
$this->_showonhomepage = false;
$this->setSeparator('»');
}
/**
* @param string $id
*/
public function setSeparator($id) {
$this->_separator = ' ' . $id . ' ';
return $this;
}
/**
* @param boolean $bool
*/
public function setShowOnHomePage($bool) {
$this->_showonhomepage = $bool;
return $this;
}
/**
* @param string $id
*/
public function setClassname($id) {
$this->_wrapperclass = $id;
return $this;
}
/**
* @param string $id
*/
public function setRootText($id) {
$this->_roottext = $id;
return $this;
}
/**
* @param string $id
*/
public function setTagText($id) {
$this->_tagtext = $id;
return $this;
}
/**
* @param string $id
*/
public function setCategoryText($id) {
$this->_categorytext = $id;
return $this;
}
/**
* @param string $id
*/
public function setArchiveText($id) {
$this->_archivetext = $id;
return $this;
}
/**
* @param string $id
*/
public function setSearchText($id) {
$this->_searchtext = $id;
return $this;
}
/**
* @param string $id
*/
public function set404Text($id) {
$this->_404text = $id;
return $this;
}
/**
* @param string $id
*/
public function setAuthorText($id) {
$this->_authortext = $id;
return $this;
}
/**
* Output the breadcrumbs by attaching it to the supplied action hook
*
* @param string $hook Name of the action hook to attach it to
* @param int $priority Determines the order of execution within the action hook (10 is default)
*/
public function hook($hook, $priority = 10) {
if ( !empty( $hook ) ) {
add_action( $hook, array( &$this, 'build' ), $priority );
} else {
throw new Exception('The "hook" method must contain the name of an action hook. e.g. $breadcrumbs->hook(\'hook_name_here\');');
}
return $this;
}
/**
* Ensures all crumbs are prefixed by the separator
* @param mixed $crumb
*/
private function _addCrumb($crumb) {
if (strlen($crumb) > 0) {
return $this->_separator . $crumb;
} else {
return '';
}
}
/**
* This does the main work to put the breadcrumbs together
*/
public function build() {
global $post;
$output = '<div>_wrapperclass . '">' . $this->_roottext . '';
if( is_single() ) {
$output .= $this->_addCrumb(' ');
foreach( get_the_category() as $category ) {
$output .= '<a>cat_ID) . '">' . $category->cat_name . '</a>, ';
}
$output = substr( $output, 0, strlen($output)-2 ); /* Strips comma and space from last category */
$output .= $this->_addCrumb( get_the_title() );
} elseif( is_page() ) {
$ancestors = $this->_get_ancestor_ids($post->ID, false);
foreach ($ancestors as $ancestor) {
if (0 != $ancestor) {
$page = get_page($ancestor);
$output .= $this->_addCrumb('' . $page->post_title . '');
}
}
$output .= $this->_addCrumb( get_the_title() );
} elseif( is_tag() ) {
$output .= $this->_addCrumb( $this->_tagtext ) . $this->_addCrumb( single_tag_title('', false) );
} elseif( is_category() ) {
$output .= $this->_addCrumb( $this->_categorytext ) . $this->_addCrumb( single_cat_title('', false) );
} elseif( is_month() ) {
$output .= $this->_addCrumb( $this->_archivetext ) . $this->_addCrumb( get_the_time('F Y') );
} elseif( is_year() ) {
$output .= $this->_addCrumb( $this->_archivetext ) . $this->_addCrumb( get_the_time('Y') );
} elseif( is_author() ) {
$output .= $this->_addCrumb( $this->_authortext ) . $this->_addCrumb( get_author_name(get_query_var('author')) );
} elseif( is_search() ) {
$output .= $this->_addCrumb( $this->_searchtext ) . $this->_addCrumb( get_search_query() );
} elseif( is_404() ) {
$output .= $this->_addCrumb( $this->_404text );
}
$output .= '</div>';
if( (is_home() || is_front_page()) && !$this->_showonhomepage ) {
/* Wipe output clean */
$output = '';
}
echo $output;
}
/** get_parent_id
* get the id of the parent of a given page
* @author http://ethancodes.com/2008/09/get-grandparent-pages-in-wordpress/
* @param int page id
* @return int the id of the page's parent page
*/
function _get_parent_id ( $child = 0 ) {
global $wpdb;
// Make sure there is a child ID to process
if ( $child > 0 ) {
$result = $wpdb->get_var("SELECT post_parent FROM $wpdb->posts WHERE ID = $child");
} else {
// ... or set a zero result.
$result = 0;
}
//
return $result;
}
/** get_ancestor_ids
* get an array of ancestor ids for a given page
* you get an array that looks something like
* [0] this page id
* [1] parent page id
* [2] grandparent page id
* @author http://ethancodes.com/2008/09/get-grandparent-pages-in-wordpress/
* @param int page you want the ancestry of
* @param boolean include this page in the tree (optional, default true)
* @param boolean results top down (optional, default true)
* @return an array of ancestor ids
*/
function _get_ancestor_ids ( $child = 0, $inclusive=true, $topdown=true ) {
if ( $child && $inclusive ) $ancestors[] = $child;
while ($parent = $this->_get_parent_id ( $child ) ) {
$ancestors[] = $parent;
$child = $parent;
}
// If there are ancestors, test for resorting, and apply
if ($ancestors && $topdown) krsort($ancestors);
if ( !$ancestors ) $ancestors[] = 0;
//
return $ancestors;
}
}
The really great thing about using classes is that you don’t need to understand any of the above (though in terms of PHP and WordPress development, it’s not that tricky), as within it are some easy-to-understand functions that you can use to customise everything.
Basic Usage
Within your functions.php (or custom_functions.php file if you’re using Thesis theme) the basic set up requires just three lines of code!
require_once 'classes/GT_Breadcrumbs.php';
$breadcrumbs = new GT_Breadcrumbs;
$breadcrumbs->hook('thesis_hook_before_content');
The first line is the path to class file – I’m using Thesis so mine is stored within the classes folder. You only need this line once, however many breadcrumbs sections you want to be displayed.
The second line creates a breadcrumb object. Nothing really to change here – so long as the variable on the left ($breadcrumbs in this example) is not already being used elsewhere, and that it’s the same as the start of the third line, then it’s all good.
The third line is where some of the fun starts. The basic usage is simply to call the hook method, along with the name of the hook you want to use (here, it’s thesis_hook_before_content).
Basic styling
I added the following styling to my custom.css – you may want something different.
.breadcrumbs {
font-size: 1.4em;
border-bottom: 1px double #ddd;
padding: 0.5em;
font-variant: small-caps;
}
Default Output
If the root text is shown, then it is always linked to the homepage.
Home Page
The breadcrumbs won’t show on the blog posts or static home page, unless you choose to show it.
Single Posts
Home » category name (linked) » post title
The category name is linked to the category page, where it would show all posts for that category. If a post is in more than one category, then a comma separated list is shown, with each category linked appropriately.
Single Page
Home » page title (linked)
Tag Page
Home » Tag » tag name
Category Page
Home » Category » category name
Archive Page
Home » Archive » archive date
The archive date may be a year (2010) or a month and year (March 2010).
Author Page
Home » Author » author name (linked)
Search Results Page
Home » Search » search term
404 / Page Not Found
Home » Not Found
Customisations
What if you want to customise the output in some way? Would you have to edit that big class file? Absolutely not! You just make your settings before calling the hook method.
Separator
The default separator is a » character, but you may prefer something else. Just use the setSeparator() method on the third line of code. If you wanted to use a / instead:
require_once 'classes/GT_Breadcrumbs.php';
$breadcrumbs = new GT_Breadcrumbs;
$breadcrumbs->setSeparator('/')->hook('thesis_hook_before_content');
Class Name
The default class name of the wrapper div is breadcrumbs. Use the setClassName() method on the third line of code to change it to something else:
require_once 'classes/GT_Breadcrumbs.php';
$breadcrumbs = new GT_Breadcrumbs;
$breadcrumbs->setClassName('where-am-i')->hook('thesis_hook_before_content');
Root Text
The default root text (leftmost crumb) is Home. Use the setRootText() method on the third line of code to change it to something else:
require_once 'classes/GT_Breadcrumbs.php';
$breadcrumbs = new GT_Breadcrumbs;
$breadcrumbs->setRootText('Start')->hook('thesis_hook_before_content');
Home Page Crumb
The root crumb Home is not shown when on the front page or homepage by default. Use the setShowOnHomePage() method on the third line of code to enable it:
require_once 'classes/GT_Breadcrumbs.php';
$breadcrumbs = new GT_Breadcrumbs;
$breadcrumbs->setShowOnHomePage(true)->hook('thesis_hook_before_content');
Static Crumb Text
When a category, tag, archive, author, search or 404 (page not found) page is shown, then the breadcrumbs include a word to indicate the context. Be default this is Category, Tag, Archive, Author, Search and Not Found respectively.
The methods to change these are setCategoryText(), setTagText(), setArchiveText(), setAuthorText(), setSearchText() and set404Text() respectively.
require_once 'classes/GT_Breadcrumbs.php';
$breadcrumbs = new GT_Breadcrumbs;
$breadcrumbs->setCategoryText('Topic')->setAuthorText('Writer')->hook('thesis_hook_before_content');
Putting it all together
All of these customisations could be combined in any order, so long as the hook section is last in the chain:
require_once 'classes/GT_Breadcrumbs.php';
$breadcrumbs = new GT_Breadcrumbs;
$breadcrumbs->setRootText('Homepage')
->setSeparator('|')
->setClassName('my-breadcrumbs')
->setTagText('Keyword')
->set404Text('Oops!')
->setArchiveText('Old Posts')
->hook('thesis_hook_before_content');
In this example, each setting is on it’s own line, as some may prefer that style of coding; it could equally have gone all on one continuous line like the previous example.
Two or more breadcrumb sections
Apart from the ease of customisation, one of the other benefits I mentioned is that you can include two different breadcrumb sections in different parts of the page. Say that you wanted one before the content to have the default root text and separator, but the one after the content to be different. Without these classes, you’d be writing a whole new function to then hook in place. With classes though, you write just two new lines:
require_once 'classes/GT_Breadcrumbs.php';
$breadcrumbs = new GT_Breadcrumbs;
$breadcrumbs->hook('thesis_hook_before_content');
$more_breadcrumbs = new GT_Breadcrumbs;
$more_breadcrumbs->setSeparator('|')->setRootText('Homepage')->hook('thesis_hook_after_content');
Now, how cool is that?
Conclusion
Using classes to add features to your Thesis theme-based site gives many advantages over procedural code that’s normally used within WordPress Themes. Once a class is written (something you can pay an expert to do), then the code you have to write is minimal yet very powerful. There’s far less code to potentially interact badly with any existing code in your file, and copying it to another WordPress site is as easy as copying the class file, and adding in those three lines of code. Simples!
Update 2010-04-20: Child pages now show the full linked hierarchy back to the top ancestor. Also added the setShowOnHomePage() option.
Update 2010-05-19: Small amendment so that top-level pages aren’t linked when on that top-level page.
Update 2010-06-06: Following on from Sean‘s comment, the addCrumb function was tweaked to allow the fixed text entries to be skipped altogether. Just set it to an empty string. e.g.:
$breadcrumbs->setCategoryText('')->hook('thesis_hook_before_content');
Shouldn’t the file under classes folder be named as GT_Breadcrumbs.php rather than GT_Sidebars.php ?
However, I changed the file name to GT_Breadcrumbs.php, but I’m getting this error:
I created classes folder within the custom directory.
Am I doing anything wrong?
You’re absolutely right – my fault for the typo, and now corrected.
You should now have
D:\xampp\htdocs\wordpress\wp-content\themes\thesis_16\custom\classes\GT_Breadcrumbs.phpwhich is a copy of the first large block of code in the article, and insideD:\xampp\htdocs\wordpress\wp-content\themes\thesis_16\custom\custom_functions.phpyou should have the line:require_once 'classes/GT_Breadcrumbs.php';
Oh, That was real quick, Much Thanks..
hi thanks for this nice class. All is working great however it seems it doesnt have the functionality i am looking for.
Let’s say I want to implement it on the site where most of the pages are Pages (not posts and categories) so I hve a lot of parent>child>child of the child Pages in wp. This class only shows home>child for example
home>blue even though the correct “blue” page structure is something like this:
home>widgets>blue. The “widgets” doesnt show as a parent Page. Do you think it’s possible to modify your class to work in this way?
thanks for your time mate!
That’s odd – I thought it should work like that! But you’re right, it doesn’t.
I’ve made an amendment to the code to add in your feature request.
hi Gary!
thanks for this quick update! It’s working but there is one little problem. My breacrumbs look like this now:
home>page1,>page2,>page3,>
As you can see after each child page there is a coma visible – “,”. I tired to look at the code and eliminate it but no success so far.
Thanks man!
Hi zdzich,
It’s now fixed to remove the commas – it was a typo from where I’d copied a line from the categories bit, which does have commas to separate posts in multiple categories.
hello again Garry!
Since you were so helpful so far i I’ll ask another question. Commas issue has been now fixed so thanks for that! however there is another small thing I would be happy to see in your class. Maybe it’s just me but it seems that when using your breadcrumbs script it doesnt show anything for the homepage = no breadcrumbs on the home page. If I go to other pages in my WP like home>whatever> its working great but for ONLY the homepage breadcrumbs don’t show. I would like to see home> for the homepage. Do you think it’s possible to implement?
thanks & have a sunny day
Hi zdzich,
All the “breadcrumbs best practices” will say that you shouldn’t have breadcrumbs on the home page – it’s really not necessary. Breadcrumbs are for when users are deeper within the site, and maybe want to move a level or two up, without going back to the homepage and starting again.
If you want to enable breadcrumbs on the homepage, then feel free to add a new line just after line 218 in the class file, and let $output = whatever you want it to say (including any surrounding div structure).
I’ll look to add it in as a future option.
I’ve now added the setShowOnHomePage() option.
I’ve also created a complete alternative version of this class that offers a few advantages: WordPress Breadcrumbs Class Alternative.
How would I go about removing >>category>> from the category pages…
for example on my category pages (I use thesis) I have created custom category text, so it’s basically a page. Anyway the crumb shows up like:
Business Loans » Category » SBA Loans
How would I make that just:
Business Loans » SBA Loans
I looked to see if I could do it with a conditional tag or something but it seemed like there was way to much going on for me. Any help would be awesome. Thanks a lot.
Hi Sean,
That’s a valid point, so I’ve amended the code in the post to add in what you’re after. As per the update notice at the bottom of the post, with the latest version of the class file you can now simply set the string to empty, and it will skip straight over the fixed text and divider part.
Excellent. I don’t know why I didn’t think of just doing that
Now, is there a way to just stop the double » on category pages?
For example:
http://www.startuploans.org/small-business/
that page ends up with this in the breadcrumbs- “Business Loans » » Small Business”
Which is probably fine for everyone, but I am OCD’d out and that will drive me insane…haha
Anyway, thanks for the code for this- it’s much better than the other Thesis related breadcrumb methods- Hands down. Thanks for the hard work. Where’s the donate button?
Hmmm, can you post exactly what you’ve got for the breadcrumbs in your custom_functions.php file? I purposely made the above code tweak so that it didn’t show the extra divider. You can see this working on http://code.garyjones.co.uk/category/thesis/ for instance.
Make sure that the setCategoryText(”) has no spaces between the apostrophes. Try typing it in manually, in case any copy and paste added some invisible character from the apostrophes or something daft.
Yea, here it is:
require_once 'classes/GT_Breadcrumbs.php';
$breadcrumbs = new GT_Breadcrumbs;
$breadcrumbs->setCategoryText('')->hook('thesis_hook_before_content');
I typed it manually and nothing.
Thanks again for the help!
PS: This is my exciting Saturday night
Work on my network sites and hope someday I can retire from client work. Hahaha!
Have to assume and check the obvious then – did you update your GT_Breadcrumbs.php class file to be the version edited today (2010-06-06), as opposed to the previous version (2010-05-19), as that’s the only thing I can see that would be causing it. See the post above for the most recent version.
Donate button is now in the sidebar btw
I just donated
Anyway, I did replace the old class with the new. Now, the problem is when you click a post inside of the category the breadcrumb ends up like this:
HomeCategory>Then post
Such as: http://www.startuploans.org/working-capital/business-capital-the-importance-of-business-credit/
So it doesn’t insert the break between the home and catty when you look at a post…
Donation received – thank you
Right – I’ve updated the post again, but you may as well make the change manually.
Line 205 of the class file, for you, reads as:
$output .= $this->_addCrumb('');Add a space between that pair of single apostrophes near the end:
$output .= $this->_addCrumb(' ');That will then mean the divider before the list of categories, on a Post, will appear.
Works like a charm! Thanks. Only a couple more things and this theme will be done. Does your social sharing bar (digg, retweet, etc) have all those units in iframes or something? I looked at your source code and I don’t see the javascript for them in the head…I’m big on page load speed and hate dumping different scripts on every page. I’m just curious how you constructed yours. Thanks again for the help with the breadcrumbs…I appreciate it.
Hi Gary
I need your help please!
I tried using your script on my thesis theme at http://www.homepowerpick.com and I can’t see the site or access the admin panel.
Here’s what I get
Parse error: syntax error, unexpected $end in /home/homepo6/public_html/wp-content/themes/thesis_17/thesis_17/custom/classes/GT_Breadcrumbs.php on line 1
aargh!
Regards
Ciaran
Hi
Panic over, lucky I had backed up the custom_function.php last week. Thanks.
Regards
Ciaran