Aelia - News badge

WooCommerce Tips & Tricks – Get all the categories to which a product belongs

As active contributors of several communities, such as the Advanced WooCommerce and WooCommerce Help & Share groups on Facebook, we came across a question that seem to be quite frequent.

How to get all of a product’s categories

This operation is simple, it just requires a bit more work than one would expect. It’s very easy to fetch the categories to which a product is assigned directly, but a product may also belong to parent categories (a parent category is a category to which a subcategory belongs). The screenshot below explains the concept.

Product category hierarchy

In this example, the product belongs directly to “Subcategory A1” and “Some other category”. It also belongs indirectly to “Category A”, as “Subcategory A1” is a child of that category.

In the above example, the product belongs to the following categories:

  • Directly to Subcategory A1 and Some other category, as it’s assigned directly to them.
  • Indirectly to Category A, which is the parent of Subcategory A1.

Now that the concepts are clear, let’s get coding.

Step 1 – Get the direct categories of a product

This is the easiest part. It’s just a matter to find all the “category” terms associated to a product. Our function will look like this:

function aelia_get_product_categories($product, $return_raw_categories = false) {
  $result = array();
  // Get all the categories to which a product is assigned
  $categories = wp_get_post_terms($product->id, 'product_cat');
  
  // The $categories array contains a list of objects. Most likely, we would 
  // like to have categorys slug as a keys, and their names as values. The#
  // wp_list_pluck() function is perfect for this
  $categories = wp_list_pluck($categories, 'name', 'slug');
  return $categories;
}

The result of this function, once applied to our example product, will be the following:

array(
  'subcategory-a1' => 'Subcategory A1',
  'some-other-category' => 'Some other category',
)

All good, we have the categories to which the product is assigned directly. Now we need to get all the parent categories.

Step 2 – Get the parent category (or categories) of a given category

To keep things tidy, we will create a second function to get the parent categories of a category. This requires a similar approach to the one used for the products.

function aelia_get_parent_categories($category_id) {
  $parent_categories = array();
  // This will retrieve the IDs of all the parent categories 
  // of a category, all the way to the top level
  $parent_categories_ids = get_ancestors($category_id, 'product_cat');
  
  foreach($parent_categories_ids as $category_id) {
    // Now we retrieve the details of each category, using its
    // ID, and extract its name
    $category = get_term_by('id', $category_id, 'product_cat');
    $parent_categories[$category->slug] = $category->name;
  }
  return $parent_categories;
}

The above will return the following result for Subcategory A1:

array(
  'category-a' => 'Category A'
)

As before, we have a list with category slugs as keys, and category names as values. Time to finish the job.

Step 3 – Putting the pieces together

Now that we can get both the direct categories of a product and their parent categories, we can alter the first function to call the second and give us a result that includes all the categories. The modified function will look as follows:

function aelia_get_product_categories($product, $return_raw_categories = false) {
  $result = array();
  $categories = wp_get_post_terms($product->id, 'product_cat');

  if(is_array($categories) && !$return_raw_categories) {
    $parent_categories = array();
    // Retrieve the parent categories of each category to which
    // the product is assigned directly
    foreach($categories as $category) {
      // Using array_merge(), we keep a list of parent categories
      // that doesn't include duplicates
      $parent_categories = array_merge($parent_categories, aelia_get_parent_categories($category->term_id));
    }
    // When we have the full list of parent categories, we can merge it with
    // the list of the product's direct categories, producing a single list
    $categories = array_merge($parent_categories, wp_list_pluck($categories, 'name', 'slug'));
  }
  return $categories;
}

As you will probably have guessed, the new function will return the following result:

array(
  'subcategory-a1' => 'Subcategory A1',
  'some-other-category' => 'Some other category',
  'category-a' => 'Category A',
)

That is, a list of all the direct and indirect categories to which a product belongs. Mission accomplished!

For your convenience, you can find the complete code here: WooCommerce – WooCommerce – Get product categories, including parent categories (Pastebin).

Need help?

Should you need help implementing the solution, or if you would need to have the category search functions implemented as part of a more complex custom project, please feel free to contact us. We will review your specifications and give you a quote for your customisation.

The Aelia Team

12 replies
  1. Leon says:

    Hey, cant seem to recieve any but an empty array with that function.
    I do call this function from the product page.

    Reply
  2. Jason says:

    I tried out your code, but it appears the parent category (not ticked) cannot be found when the child category is ticked for the product. The categories selection is identical to the above example.

    [ ] Add-Ons
    [x] Wine & Liquor

    The “Wine & Liquor” category indirectly belongs to the “Add-Ons” category.
    Unfortunately, I see “Categories: Wine & Liquor” on the product page, and not “Categories: Add-Ons, Wine & Liquor”

    What is amiss?
    Please advise. Thank you.

    Reply
    • diego says:

      Hi Jason,
      We reviewed the code, and it still works fine. You will have to ensure that “Wine and Liquor” is a child category of “Add-Ons” (see example: https://prnt.sc/i8oken). If they are at the same level, then they will be considered independent from each other.

      Reply
          • Jason says:

            I left this alone for a long time, and I decided to return to it. Anyway, I’m curious if your custom snippet goes into “/woocommerce/templates/single-product/meta.php”. And what other line(s) of code need to be altered to make it work.

            Please advise. Thank you.

          • diego says:

            The code could go anywhere you like and it should just work, by passing it a product object. Please just keep in mind that we wrote it in 2016, therefore we recommend to test it thoroughly.
            If you need assistance implementing your customisation, you can contact us and we can prepare an estimate for it, after reviewing your specifications.

  3. panjianom says:

    Thanks for your code.
    Now, how to get objects (all of products) from spesific category?

    Reply
  4. Caroline says:

    Why couldn’t you just use something like:

    $terms = wp_get_post_terms( $product->id, ‘product_cat’ );
    $categories[] = wp_list_pluck( $terms, ‘name’, ‘slug’ );

    This would give all categories (including parent categories) in one go, maybe?

    Reply
    • diego says:

      Thanks for your suggestion. We wrote the code quite a while ago, and I don’t remember why we didn’t use function `wp_get_post_terms()`. If that returns all categories, including parent ones, then it could indeed make sense to use it. It would make the code simpler, too.

      Reply

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply

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

 

This site uses Akismet to reduce spam. Learn how your comment data is processed.