WooCommerce Function of the Week: wc_get_product_category_list

Here’s yet another time-saving WooCommerce function. No need to reinvent the wheel — with a single line of code and no custom queries, you can get all the categories a product belongs to.

This week’s function is wc_get_product_category_list, and there’s no need to explain what it does as its name is self-explanatory.

As usual, we’ll study the WooCommerce core function code, see where and why it’s used, and finally we’ll cover a quick case study. Enjoy!

Function code

The function wc_get_product_category_list can be found under woocommerceincludeswc-product-functions.php:

/**
 * Returns the product categories in a list.
 *
 * @param int    $product_id Product ID.
 * @param string $sep (default: ', ').
 * @param string $before (default: '').
 * @param string $after (default: '').
 * @return string
 */
function wc_get_product_category_list( $product_id, $sep = ', ', $before = '', $after = '' ) {
	return get_the_term_list( $product_id, 'product_cat', $before, $sep, $after );
}

First of all, let’s look at the function parameters:

  • $product_id, which is of course the product we want to get the categories for.
  • $sep, by default a comma, which defines the list separator.
  • $before and $after, by default empty strings, which define what shows before and after the list of categories. (prefix / suffix)

Now to the function statements — actually, statement, as there is only one:

return get_the_term_list( $product_id, 'product_cat', $before, $sep, $after );

That really sounds like a WordPress function as there is no mention of “woo,” “wc,” or any other WooCommerce prefixes. Let’s look it up in the WordPress developer code reference documentation. (https://developer.wordpress.org/reference/functions/get_the_term_list/)

Here we go:

function get_the_term_list( $post_id, $taxonomy, $before = '', $sep = '', $after = '' ) {
    $terms = get_the_terms( $post_id, $taxonomy );
 
    if ( is_wp_error( $terms ) ) {
        return $terms;
    }
 
    if ( empty( $terms ) ) {
        return false;
    }
 
    $links = array();
 
    foreach ( $terms as $term ) {
        $link = get_term_link( $term, $taxonomy );
        if ( is_wp_error( $link ) ) {
            return $link;
        }
        $links[] = '<a href="' . esc_url( $link ) . '" rel="tag">' . $term->name . '</a>';
    }
 
    /**
     * Filters the term links for a given taxonomy.
     *
     * The dynamic portion of the hook name, `$taxonomy`, refers
     * to the taxonomy slug.
     *
     * Possible hook names include:
     *
     *  - `term_links-category`
     *  - `term_links-post_tag`
     *  - `term_links-post_format`
     *
     * @since 2.5.0
     *
     * @param string[] $links An array of term links.
     */
    $term_links = apply_filters( "term_links-{$taxonomy}", $links );  // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
 
    return $before . implode( $sep, $term_links ) . $after;
}

Simple enough — get_the_term_list accepts basically the same parameters we covered above, plus the $taxonomy parameter, which in our case is passed as product_cat to tell WordPress we’re retrieving WooCommerce product categories.

Here’s how it works:

  • get_the_terms( $post_id, $taxonomy ) gets the product ID category objects.
  • $links array gets filled with the list of categories, each with its own link.
  • return $before . implode( $sep, $term_links ) . $after gives us the content we need: “prefix + $links separated with $sep + suffix”

Function usage

Define a product ID (e.g., 57) — and that’s all you need to do!

Call the function:

echo wc_get_product_category_list( 57 );

And see the magic happen:

cat1 link, cat2 link, cat3 link, ...

Of course, if you have access to the $product global, you can call the function dynamically. For example, if you want to call the function on every single product pages, you could do this:

echo wc_get_product_category_list( $product->get_id() );

Now I want to see where and when the function is called, so we give it a bit of context. With a quick search through the WooCommerce plugin, I find a single result in woocommercetemplatessingle-productmeta.php, line 34:

<?php echo wc_get_product_category_list( $product->get_id(), ', ', '<span class="posted_in">' . _n( 'Category:', 'Categories:', count( $product->get_category_ids() ), 'woocommerce' ) . ' ', '</span>' ); ?>

Which generates this output on my single product page:

Now we know wc_get_product_category_list is responsible for showing the list of categories in the single product page where it comes with a prefix (‘Category:’ or ‘Categories:’ based on category count) plus the default comma separator and no suffix.

Let’s use wc_get_product_category_list for our custom development example now and consider a quick case study.

Case study

Where could wc_get_product_category_list come in handy? Surely, in the shop page.

By default, WooCommerce shows the list of products with image, title, price and button. There is no mention of product categories there, so let’s add them ourselves.

Before:

The custom snippet:

/**
 * @snippet       Show Categories | WooCommerce Shop
 * @how-to        Get CustomizeWoo.com FREE
 * @author        Rodolfo Melogli
 * @testedwith    WooCommerce 6
 * @donate $9     https://businessbloomer.com/bloomer-armada/
 */

add_action( 'woocommerce_after_shop_loop_item', 'bbloomer_show_product_categories', 9 );

function bbloomer_show_product_categories() {
	global $product;	
	echo wc_get_product_category_list( $product->get_id(), ' - ', '<p>In: ', ' ' . _n( 'category', 'categories', count( $product->get_category_ids() ), 'woocommerce' ) . '</p>' );
}

After:

A few notes:

  • I used the woocommerce_after_shop_loop_item hook with priority 9, which is just before priority 10 (the add-to-cart button). TLDR: I’m outputting the category list above the add to cart button.
  • I declare the global $product so that I can access the product ID.
  • I then call the wc_get_product_category_list function, with the following parameters:
    • $product->get_id() -> the product ID
    • ' - ' -> the separator
    • '<p>In: ' -> the prefix
    • ' ' . _n( 'category', 'categories', count( $product->get_category_ids() ), 'woocommerce' ) . '</p> ' -> the suffix

It’s interesting how I reused this line from the single product page, as I mentioned above:

_n( 'category', 'categories', count( $product->get_category_ids() ), 'woocommerce' )

Basically, if count = 1 the first string is returned (singular “category”), while if count > 1 you get the plural “categories.” You can see the difference in the last screenshot above.

Any other use cases you have in mind? Let me know in the comments!

Leave a Reply

Your email address will not be published. Required fields are marked *

Leave a comment

Your email address will not be published. Required fields are marked *