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.