Display Categories in the Woocommerce Product Loop

The eCommerce plugin Woocommerce is pretty standard for WordPress retail websites. Woocommerce by default does not display categories on the product loop (shop page), but I recently encountered an instance where we wanted to display all the categories that each product was in within the normal loop. In this case, we also had removed links to individual product pages since they were not offering any additional information so the product loop was the only place we could output the categories. We can do this very easily within the functions.php file. In the following example, we will use the hook for a product’s title within the loop, which is woocommerce_shop_loop_item_title, but some other hooks could be used as well.

Display Categories Code Example

So within your child theme’s functions.php file, paste in the following code snippet. This will simply output the normal product title as usual followed by a full list of all of the categories that the product is contained under. This accounts for formatting of a single category or multiple categories by adding commas if and when they are needed.

<?php
//Remove title hook and add in a new one with the product categories added
remove_action( 'woocommerce_shop_loop_item_title', 'woocommerce_template_loop_product_title', 10 );
add_action( 'woocommerce_shop_loop_item_title', 'VS_woo_loop_product_title', 10 );

function VS_woo_loop_product_title() {
    echo '<h3>' . get_the_title() . '</h3>';
    $terms = get_the_terms( $post->ID, 'product_cat' );
    if ( $terms && ! is_wp_error( $terms ) ) :
    //only displayed if the product has at least one category
        $cat_links = array();
        foreach ( $terms as $term ) {
            $cat_links[] = $term->name;
        }
        $on_cat = join( " ", $cat_links );
        ?>
        <div class="label-group">
            <?php echo 'Categories: ' . $on_cat; ?>
        </div>
    <?php endif;
}
?>

This is an example of what the loop would loop like. Note the formatting of the single category product versus the multiple category product.

Display Categories in the Woocommerce Product Loop Example

Display Categories that are Linked Code Example

Here is a modified version that will display categories for each woocommerce product as links that we output in the product loop, in case you want to give the user the option to hop to specific category pages. You will need to modify the link path for the categories if you modified it all from the default woocommerce path of /product-category/(category slug)/.

<?php 
//Remove title hook and add in a new one with the product categories added
remove_action( 'woocommerce_shop_loop_item_title', 'woocommerce_template_loop_product_title', 10 );
add_action( 'woocommerce_shop_loop_item_title', 'VS_woo_loop_product_title', 10 );

function VS_woo_loop_product_title() {
    echo '<h3>' . get_the_title() . '</h3>';
    $terms = get_the_terms( $post->ID, 'product_cat' );
    if ( $terms && ! is_wp_error( $terms ) ) :
    // only displayed if the product has at least one category
        $cat_links = array();
    foreach ( $terms as $term ) {
        $cat_links[] = '<a href="'.esc_url( home_url() ).'/product-category/'.$term->slug.'">'.$term->name.'</a>';
    }
    $on_cat = join( ", ", $cat_links );
    ?>
    <div class="label-group">
        <div class="categories-link"><?php echo $on_cat; ?></div>
    </div>
<?php endif;
}
?>

That’s all there is too it! Once you have that code in your functions.php file of your child theme, it should work as advertised. Of course, feel free to customize it as you like and to fit your wordpress site’s goals. Right below here are some simple customization options that you can do to the categories display.

Code Customization

This code will display “Categories: ” before the actual listed categories via the line:

You can easily remove the categories label by just using the following line instead:

You can also add a class to your category output for some custom styling by just throwing some extra html in that same line like this:
Category: ' . $on_cat . ''; ?>

Comments

  1. Thanks for the snippet looking for this for ages 🙂

    Could u also tell me how to change them from place if possible? first category then title

    Category
    Title

    • You’re welcome!

      To answer your question, you can swap the order by just moving this line:
      echo '<h3>' . get_the_title() . '</h3>';

      to after the end of the “if statement”, which is this line:
      <?php endif;

  2. This is super useful and suprisingly hard-to-find info, thanks!
    I’m wondering, is there a way to also link to the categories listed? Right now, the whole shebang links to the individual product, but I’d like the user to be able to click the categories and be taken to the respective category page instead. What do you think?

    • In the foreach loop the object returned also contains the category slug, so you could retrieve that with $catslug = $term->slug; within that loop. You’d need to then format the output to include the full link and make sure we don’t nest a link within a link. That may require using a different hook though or modifying the item itself to close the main link tag sooner.

    • Update: With a little back and forth, Kelsey and I came up with this adjusted snippet to link the listed categories:

      ‹?php
      //Remove title hook and add in a new one with the product categories added
      remove_action( 'woocommerce_shop_loop_item_title', 'woocommerce_template_loop_product_title', 10 );
      add_action( 'woocommerce_shop_loop_item_title', 'VS_woo_loop_product_title', 10 );
      function VS_woo_loop_product_title() {
      echo '‹h3›' . get_the_title() . '‹/h3›';
      $terms = get_the_terms( $post->ID, 'product_cat' );
      if ( $terms && ! is_wp_error( $terms ) ) :
      // only displayed if the product has at least one category
      $cat_links = array();
      foreach ( $terms as $term ) {
      $cat_links[] = '‹a href="'.esc_url( home_url() ).'/product-category/'.$term- rel="nofollow"›slug.'"›'.$term->name.'‹/a›';
      }
      $on_cat = join( ", ", $cat_links );
      ?›
      ‹div class="label-group"›
      ‹div class="categories-link"›‹?php echo $on_cat; ?›‹/div›
      ‹/div›
      ‹?php endif;
      }
      ?›

      (Also has been added to the main post)

      • Juan Carlos says

        Hello Vincent,
        Thank you very much for this code snippet!
        Could you please let me know if it is possible to display the Parent Category too? I have nested categories and I want to use your code into the order email template too to display the Parent Category.

        I will be waiting for your reply.
        Thank you.

        JC

        • Hey JC,
          Thanks for the question!
          If the parent categories are selected, then this will output them as well already, but if you only have the subcategories selected and want to grab the parent categories you should take a look at the get_ancestors() function. You can pass the $term->id in the get_ancestors() function and it will return and array of ID’s of that category’s parent categories. You can then use the item at the 0 index level to get the top level parent category ID and using that ID you can fetch the name and slug with the get_category() function, which will return an array with all the necessary information in it.

          • Hi Vincent! This was already so much help, thank you!

            Could you elaborate on this maybe… I want to show first the category name, then the subcategory name. Currently they are ordered alphabeticly.

          • You’re welcome! As for your question, the get_the_terms function returns details on the item’s parent category id’s as well. So within the foreach loop you could use $term->parent to grab the parent category’s ID if it has one. A quick thought to achieve what you are looking for might be that you will want to do the loop twice. The first time to get all the parent categories in an array. The second time to do the output. Now the second loop would have some steps. First checking that the item is not in the parent category array you made in the first loop. If it’s not, then grab it’s parent category and output that using the info you can get from get_category and then output the current category itself.
            That’s just the firs thing that came to mind, but there may be a better way. Just be aware that with this setup, any parent categories that don’t have subcategories chosen will not display and if you have multiple subcategories chosen under the same parent category, you will see that parent listed multiple times. That should be enough to get you started though and customizing it to your specific needs.

Speak Your Mind

*