Aw Yiss! WooCommerce Breadcrumbs

WooCommerce Breadcrumbs – Control Product Categories

David Nash woocommerce, wordpress 7 Comments

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 {


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 ) ) {
    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 );

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:


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

  1. 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?.

  2. 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?

  3. 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 {


    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 :/

  4. 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?

Leave a Reply