WooCommerce breadcrumbs will show the first category it finds that a product is in, no matter how you got to it. This makes sense, as breadcrumbs should more be about categories than browser history.
Unfortunately if that category is alphabetically earlier, it will display that – no matter how many levels of categories it is deep.
It makes more sense to me to show the shortest path of categories to the product, which is what this tutorial is about.
I’m going to assume you’re using a child theme for this. If you’re not, sorry – you’ll need to go and set that up first. Take a look at this tutorial for a good introduction on how to do that.
There are two main steps here, and the first one seems scary, but isn’t.
Step 1: Customise the WooCommerce breadcrumbs class
Don’t panic. Everything will be fine.
We’re going to extend the WooCommerce Breadcrumbs class so that we can edit one of its functions without having to modify the WooCommerce core.
First, make a copy of plugins/woocommerce/includes/class-wc-breadcrumb.php . Let’s copy it to themes/[child-theme]/includes/class-custom-breadcrumb.php . It could be anywhere, but I think creating the includes directory is a good idea, just to keep it separate from the rest of your code.
Edit your new file, and change the line near the top from:
class WC_Breadcrumb {
to:
class Custom_Breadcrumb extends WC_Breadcrumb {
Next we want to modify the add_crumbs_single() function so that instead of returning the category that is several layer deep but come first alphabetically, we return the shortest path.
Use a text search to find the function:
private function add_crumbs_single( $post_id = 0, $permalink = '' ) { if ( ! $post_id ) { global $post; } else { $post = get_post( $post_id ); } if ( 'product' === get_post_type( $post ) ) { $this->prepend_shop_page(); if ( $terms = wc_get_product_terms( $post->ID, 'product_cat', array( 'orderby' => 'parent', 'order' => 'DESC' ) ) ) { $main_term = apply_filters( 'woocommerce_breadcrumb_main_term', $terms[0], $terms ); $this->term_ancestors( $main_term->term_id, 'product_cat' ); $this->add_crumb( $main_term->name, get_term_link( $main_term ) ); }
Just below this first if statement, we’re going to add the following:
//instead of showing the first term returned, we only show categories that are closest to the top $better_terms = array(); foreach( $terms as $t ) { if($t->parent == 0 ) $better_terms[] = $t; } $terms = $better_terms; //terms could now be empty, just want to show this page title and return if( count($terms) == 0 ) { $this->add_crumb( get_the_title( $post ), $permalink ); return; }
The lines that you should see after this are:
$main_term = apply_filters( 'woocommerce_breadcrumb_main_term', $terms[0], $terms ); $this->term_ancestors( $main_term->term_id, 'product_cat' ); $this->add_crumb( $main_term->name, get_term_link( $main_term ) ); }
Save your file. That’s it for Step 1.
Step 2: Override the WooCommerce breadcrumbs function
Hopefully this is more familiar territory for you. Edit the functions.php file in your child theme directory. Add this:
include('includes/class-custom-breadcrumb.php'); function woocommerce_breadcrumb( $args = array() ) { $args = wp_parse_args( $args, apply_filters( 'woocommerce_breadcrumb_defaults', array( 'delimiter' => ' / ', 'wrap_before' => '<nav class="woocommerce-breadcrumb" ' . ( is_single() ? 'itemprop="breadcrumb"' : '' ) . '>', 'wrap_after' => '</nav>', 'before' => '', 'after' => '', 'home' => _x( 'Home', 'breadcrumb', 'woocommerce' ) ) ) ); $breadcrumbs = new Custom_Breadcrumb(); //use our customised class if ( $args['home'] ) { $breadcrumbs->add_crumb( $args['home'], apply_filters( 'woocommerce_breadcrumb_home_url', home_url() ) ); } $args['breadcrumb'] = $breadcrumbs->generate(); wc_get_template( 'global/breadcrumb.php', $args ); }
This is almost identical to the code in plugins/woocommerce/includes/wc-template-functions.php . First, all we’re doing is including the extended class we wrote in Step 1. The only other change is that instead of creating a WC_Breadcrumb object, we’re creating a Custom_Breadcrumb object.
Save the file and have a look at your site. Aw yiss! Slightly saner WooCommerce breadcrumbs!
Woocommerce version 2.3.0.
Image used without permission from Hark, a vagrant by the genius comic artist Kate Beaton.
Comments 7
Hello David,
I want to try this solution to see if it helps but I don’t understand where exactly to copy the code (Step 1). I get this part: “Just below this first if statement, we’re going to add the following” but not this one: “The lines that you should see after this are:” Could you post the whole code with the modifications?.
Thanks,
C.
awseome article thanks for sharing. We just started using woocommerce and it works great for our biz
I am trying to use this in the current version of WooCommerce. I get to the point where the instructions read “The lines that you should see after this are:”
In my “plugins/woocommerce/includes/class-wc-breadcrumb.php” file, the following code does not match and the edits break the site.
Either I have done something wrong, or the WC files have changed since your tutorial. Can you provide any guidance on this front?
Hi Susan
Sorry, my description isn’t very clear. Here’s a gist with the lines inserted at the correct point: https://gist.github.com/davidnash/c5d4ae743ef5fe0c3be40032e52219b4#file-class-custom-breadcrumb-php-L149
Also please make sure you’re not editing the file in the plugin, because if that file gets changed in a WooCommerce update, you’ll lose the changes – see the link about creating a child theme.
Hi,
i did as you mencioned but get no results. I´m using Kallyas theme with woocommerce integrated. What should i do to fix this. Thanks
Hey David!
You say (in the very beginning) that we’re supposed to:
“Edit your new file, and change the line near the top from:
class WC_Breadcrumb {
to:
class Custom_Breadcrumb extends WC_Breadcrumb {”
But you haven’t done that in your gist…. ?
I’m only getting a “Class ‘Custom_Breadcrumb’ not found” blank screen :/
Hello David!
Amazing post. I have a similar problem, but I want to change the woo default breadcramb, in a diferent way.
For me, the correct path to the product (or post) is the way to the main (principal) category.
How can I do this? Can you help me?