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 \woocommerce\includes\wc-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 \woocommerce\templates\single-product\meta.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!