Hide Certain WooCommerce Sub-Categories in Catalog
WooCommerce provides some coarse control over displaying sub categories in your shop/category pages with the “Show subcategories on category pages” and “Show subcategories on the shop page” options on the WooCommerce > Settings > Catalog > Catalog Options section. These controls are all-or-nothing though: show all subcategories on the category pages, or show all subcategories on the shop page. If you want finer-grained control, for instance displaying only certain subcategories on the shop or particular subcategories on a given category catalog page, you’ll need to write a little custom code, and there are a couple of approaches you can take.
The existing limited controls, found in WooCommerce > Settings > Catalog, which allow you to hide all or none of the subcategories:

WooCommerce > Settings > Catalog
To clarify what we’re talking about doing here, the goal is to hide for instance only one highlighted subcategory ‘WordPress Plugins’, leaving ‘Magento Extensions’ in the example below:

Some example subcategories on the shop page
get_terms Filter
Perhaps the easiest and most upgrade-friendly is to hook onto the core ‘get_terms‘ filter. This filter is ultimately applied by a call to get_categories() which is called by the woocommerce_product_subcategories() template function, which is responsible for returning the product subcategories to be displayed on the shop/category pages. The approach is to hook into that filter, test for the taxonomy/page we are interested in, and alter the returned categories:
add_filter( 'get_terms', 'get_subcategory_terms', 10, 3 );
function get_subcategory_terms( $terms, $taxonomies, $args ) {
$new_terms = array();
// if a product category and on the shop page
if ( in_array( 'product_cat', $taxonomies ) && ! is_admin() && is_shop() ) {
foreach ( $terms as $key => $term ) {
if ( ! in_array( $term->slug, array( 'donation' ) ) ) {
$new_terms[] = $term;
}
}
$terms = $new_terms;
}
return $terms;
}
The above code will exclude the ‘donation’ category from the shop page. Excluding other categories is as simple as adding to that array. Excluding subcategories from a category page should be as easy as replacing the is_shop() call with one to is_product_category(), for all categories, or is_product_category( id|name|slug ) supplying the desired category id or name or slug.
You can put this code as always, in your theme’s functions.php or a custom site plugin, whichever you prefer.
Some Other Approaches
The nice thing about the above solution is that it does not require overriding any functions or templates. The only real potential drawback to that approach that I can see is that it will indiscriminately apply to any and all calls to get_categories() which are made for product categories when those is_shop(), is_product_category() conditional query tags are active. A more selective solution could be to override one of: woocommerce_product_subcategories() template function, or the content-product_cat.php template.
Template Function
The woocommerce_product_subcategories() template function can be found in woocommerce/woocommerce-template.php, and could be overridden by copying the function to your theme’s functions.php and modifying to include a snippet like the following:
...
$args = array(
'child_of' => $product_category_parent,
'menu_order' => 'ASC',
'hide_empty' => 1,
'hierarchical' => 1,
'taxonomy' => 'product_cat',
'pad_counts' => 1
);
// start of modification
if ( is_shop() ) {
$args['exclude'] = "95,96";
}
// end of modification
$product_categories = get_categories( $args );
...
Where $args['exclude'] is set to a comma-delimited list of category ids to exclude.
Template
Another approach would be to override the woocommerce template file woocommerce/templates/content-product_cat.php by copying it to your-theme/woocommerce/content-product_cat.php and adding something like the following to the top:
if ( is_shop() && in_array( $category->slug, array( 'donation' ) ) ) {
return;
}
Obviously substituting in whichever subcategories you want excluded, and using the appropriate conditional tags to apply to the particular pages you want.
Hi Justin,
Just wondering if there is the ability to limit what state the user can pickup their order from by their billing address.
Currently running a store here in Australia, and customers often select the “Local Pickup” option by accident when they’re in a different state. I’m looking for a way to stop this from happening.
George.
Hey George, thanks for the question. I don’t have a perfect answer for you, not without some custom code at this point anyways. I do have an admittedly self-serving suggestion of something that perhaps might help with the confusion, and cut down on people incorrectly selecting “Local Pickup”, and that is to give my paid WooCommerce Local Pickup Plus shipping extension a try. It allows you to specify one or more local pickup location addresses for your customers to choose from when checking out. Perhaps seeing, or having to select a pickup address would make the checkout process more clear for your customers? Additionally the selected pickup location will appear on their receipt, and on your order page, so there are additional benefits for merchants offering a pickup option. Sorry I don’t have an exact answer for you at this point, but hopefully this helps for now.
Thanks for the prompt feedback mate, I was thinking that plugin might help – and I think i’ll give it a try!
Warm Regards,
George.
You got it
Feel free to post back here if the plugin works out for you. Or even if it doesn’t, and how it could be improved. I’ve added the billing address check to my list of feature requests, so that’ll get in there at some point as time allows. All the best
It would be great if local pickup was only offered as an option to customers in certain zip codes and if a handling fee could be added. (much like local delivery is handled)
BTW – thanks for posting code snippets – very helpful
PS on my last comment – I just realized all I need to do is change the title the customer sees for local delivery to “local pickup” and use that. Duh!
Thank you
Hey Kathy, thanks for the feedback. Your right, a good way to handle this is to alter the title; but still what you describe would be a nice feature to have, so I’ve added it to my internal feature request tracker, I’ll do my best to get it into a future release. Thanks again!
Hi thanks for your workarnoud. But it only works on a full shop view. When you put a shortcode: [product_categories number=""] on a random page your solution doesn’t work anymore.
Is there a way to exclude sub-categories for this shortcode?
Not sure off the top of my head what the best solution would be, I think it’s difficult to detect when you’re being called from within a shortcode. Perhaps trying out my template approach that I describe at the end of the article, and just removing the
is_shop()check to have it apply everywhere?I know this is extremely old, but I’m just confirming that getting rid of is_shop() worked.
Hi! Do you know how to exclude products in some categories from main shop page?
Hey romapad, I couldn’t find any configuration options within the WooCommerce settings to accomplish this, so I bet you could follow an approach similar to what I’ve outlined above, only working with products rather than categories. It looks like it will take some custom coding in any event.
Hey Justin,
I just spent about 20 minutes reading through your articles. Good work!
Question hoping for solution.
When I set up categories, woocommerce shows them 1 category per row on the category listing page.
Do you know of a way to set this up to show 4 categories per row instead of just 1?
Hey Robert, glad you found the articles useful. Categories should be 4 per row, or the same as products. Perhaps it’s the theme you’re using?
Thank you, worked perfectly
You’re welcome, glad it worked!
First of all, thanks for sharing your knowledge with us all.
I tried your solution but i noticed that the category name also disappeared from the products categories widget on the shop page. I had a solution working that only removed the products from a said category to show up on the shop page but it still listed the category on the widget (im using collapsing categories plugin to have the toggle effect) inside the shop page. The problem was, it also removed the products from showing up on the admin.
But reading your article made me realize the last piece of my solution: creating a if condition !is_admin to prevent excluding the category from showing up on the administration panel. Anyway, heres the code:
http://pastebin.com/R6h6VT0t
Hey Pedro, yeah that was one of my fears with my solution, is that the categories could disappear from unexpected places. Glad to hear you were able to take something useful from the article though and get your solution working
hi
thanks for a wonderful tutorial
I am wondering how to exclude the categories from just appearing on the main static front home page?
thanks mark
Hey Mark, you can try the above code examples, but using the
is_front_page()checkyou can instead exclude all categories except “example, example 2, example 3″ by modifying the file content-product_cat.php?
Yup Mario, you can definitely do that with the right conditional check
you might have about the instructions?
Well, if you’re doing it by category name rather than slug, you could do:
if ( ! in_array( $category->name, array( 'example', 'example 2', 'example 3' ) ) ) {return;
}
Assuming those are your category names names, put that at the top of the your overridden
content-product_cat.phpfile as described in the last section of the post above, to exclude all but those categories.thanks for the reply! actually I’m confused. I would ecludere all product categories except for certain: namely 11. Could you be more clear about it?
Right, so list out the names of the 11 categories you want to include, replacing ‘example’, ‘example 2′, ‘example 3′ in my previous code snippet
if ( is_home() && if ( ! in_array( $category->name, array( ‘elettronica-2′, ‘modding’, ‘gaming’ ) ) ) {
return;
}
right?
those look more like slugs, so try:
if ( ! in_array( $category->slug, array( 'elettronica-2', 'modding', 'gaming' ) ) ) { return; }thank you very much indeed. I’ve been a big help. thank you!
Thanks for the write up but I’ve exhausted Method 2 (with slug) and 3 (with ID) without any changes to the Product Category sidebar, nor the Product itself – nothing to the SHOP.
Everything is as per identical to previous. Anything I am missing here? In fact, I have tried to load my site without these 2 files:
content-product_cat.php
woocommerce-template.php
Once I click on SteveJobs.com/shop > All Product Categories + Product (supposed to be excluded) are still showing.
As for Method 1, can you be more precise on how to change the Taxonomy? I re-read the whole paragraph for more than 10 times now, and I am still unsure on the insertion of the code …. at which file? Via FTP, .CSS?
WP 3.4.1 Woocommerce 1.6.1
Hey, sorry if the article wasn’t particularly clear in some of the details, my bad. I’ve since updated it to include some images of exactly what we’re trying to do here, and made it more clear where certain code goes.
If you take a look at the images, you’ll see it wasn’t actually the product category sidebar that I was trying to alter.
For method 1, putting that code in your theme’s functions.php would work just fine, and you could do that via FTP. Hope this helps
Hi Justin,
I have a slightly different problem but I think the function you described above maybe could help me if adjusted a little.
I would like to have the woocommerce page navigation only shown on my main shop page and not on the category pages. Any idea how I can remove the pagination from my category pages?
Thanks!
Hi, I tried all 3 methods and NONE of them worked … !
I juste need to remove my special deals category from the shop page, which seems pretty simple but strangely none of the solution I tried seem to have the slightest effect.
Hey David, sorry to hear that, are you certain you used the correct category id or slug?
I needed to hide subcategories within a particular subcategory based on a user meta field I added to each profile. The user meta field lists all the subcategories under a particular parent and a checkbox controls access to each of them.
To decide which to show and which to hide I tried using the get_terms filter approach but had some issues. I ended up using the woocommerce filter ‘woocommerce_product_subcategories_args’. Within that I checked to see if the user was logged in and then based on that either remove all but a sample subcategory or just the ones the currently logged in user didn’t have access to.
It works great and is another method I’d suggest for handling the hiding of certain subcategories that doesn’t require hacking woocommerce templates.
That’s a great tip Scott and a very handy filter. Looks like that got added in WC 2.0, cool!
This is maybe little off topic, but I have question. I did a function which change product visibility.
add_filter( ‘woocommerce_product_is_visible’, ‘myWoocommerce_product_is_visible’, 10, 3 );
function myWoocommerce_product_is_visible( $visible,$prod_id) {
……
return $visible;
}
My problem is that now the pagination does not match the real product numbers. How can i regenerate pagination?
Hey Gorazd, well for what you’re talking about you’ll need to hook in and modify the main page query, which can be sort of a challenge. If you get it working, you won’t even need to use the
woocommerce_product_is_visiblefilter thoughHello,
I was wondering if there is a way to hide certain categories from certain users/roles? For example:
I have six categories…
1. Desert Dips
2. Dessert Dips Wholesale
3. Olive Oil
4. Olive Oil Wholesale
5. Salsa
6. Salsa Wholesale
I want to only show the Wholesale categories to a “Wholesale” user role and hide the “Wholesale” category from all other users and/or roles.
Any information will be much appreciated.
Cheers,
~D
Hey Dan, well there is the Groups for WooCommerce plugin http://www.woothemes.com/products/groups-woocommerce/ which should get you pretty close, but I’m not 100% sure about the categories thing. Unfortunately I don’t think there’s any “easy” option for what you’re asking, even though it’s definitely a pretty common use-case. Best of luck
Great write up, thanks for the info. Ive decided to take the “override the woocommerce template file” approach and it works great. I modified my template file even more to remove the images as well. What I cant figure out though is how to have the categories in a list above or beside the product loop. Right now my categories display at titles but they are in the product loop and are all spaced out through out the product grid. I just want a nice tight organized list. Any ideas?
I was able to get categories to show outside of the loop by adding the code below to my functions.php file however it only works when the “Show subcategories on the shop page” box is checked in the catalog settings page. I feel like im in the right direction.
add_action( ‘woocommerce_before_shop_loop’, ‘woocommerce_product_subcategories’, 10 );
function woocommerce_show_categories($cat_args){
$cat_args['hide_empty']=0;
return $cat_args;
}
Hey David, sounds like you’re on the right track. You could also look into perhaps using the “WooCommerce Product Categories” widget, whether directly or as a reference. Or if you need total control, you could implement your own thing with the WordPress Walker class