Skip to content

Instantly share code, notes, and snippets.

@DarkAllMan
Last active April 21, 2022 09:46
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DarkAllMan/cffb114eb97c6f26882e54793e023587 to your computer and use it in GitHub Desktop.
Save DarkAllMan/cffb114eb97c6f26882e54793e023587 to your computer and use it in GitHub Desktop.
Woocommerce Hide Empty Categories in Shop (compatible with hidden products and Woocommerce Groups)
<?php
/**
Plugin Name: WooCommerce - Hide categories where no products are visible to user
Plugin URI: https://www.randall.nl
Description: Excludes categories with no visible products from the WooCommerce category overview in shop
Version: 1.2
Author: Randall Kam
Author URI: https://www.randall.nl
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( !class_exists( 'ExcludeCats' ) ) :
class ExcludeCats {
public $version = '1.2',
$do = false,
$exclude = array();
protected static $_instance = null;
/**
* Main Plugin Instance
*
* Ensures only one instance of plugin is loaded or can be loaded.
*/
public static function instance() {
if ( is_null( self::$_instance ) ) {
self::$_instance = new self();
}
return self::$_instance;
}
/**
* Constructor
*/
public function __construct() {
add_action('wp action', array( $this, 'checkShopSearch' ), 10, 1 );
// CHECK CATEGORIES FOR VISIBLE PRODUCTS
add_action('wp_head', array( $this, 'get_excluded_cats' ), 10, 3 );
// ADD THE SHOP FILTER
add_filter( 'woocommerce_product_subcategories_args', array( $this, 'filter_woocommerce_product_subcategories_args'), 10, 1 );
// ADD THE WIDGET SIDEBAR FILTER
add_filter( 'woocommerce_product_categories_widget_args', array( $this, 'kfg_exclude_categories_from_widget'), 10, 1 );
}
// CHECK IF WE NEED TO RUN EVERYTHING
public function checkShopSearch($query){
if(is_shop() || is_search()){
$this->do = true;
}
}
// GET CATEGORIES WITH NO VISIBLE PRODUCTS AND PUT IN GLOBAL IF GLOBAL FALSE
public function get_excluded_cats( $terms, $taxonomies = NULL, $args = NULL ) {
if(!$terms){
return;
}
$current_tax = get_query_var( 'product_cat' );
$term =get_term_by( 'slug', $current_tax, 'product_cat');
$term_id = $term->term_id;
$args = array(
'parent' => $term_id,
'hide_empty' => false,
'hierarchical' => false,
);
$product_categories = get_terms( 'product_cat', $args );
// if a product category and on the shop page
//if ( in_array( 'product_cat', $taxonomies ) && ! is_admin() && is_shop() ) {
if ( ! is_admin() && is_shop() ) {
foreach ( $product_categories as $key => $term ) {
unset($this->exclude);
if($term->taxonomy=='product_cat'){
$posts = get_posts( array( 'post_type' => 'product', 'posts_per_page' => -1, 'product_cat' => $term->slug, 'fields' => 'ids' ) );
$show_category = false;
foreach ( $posts as $post ) {
$product = new WC_Product( $post );
$visible_product = $product->is_visible();
if ( true === $visible_product ) {
$show_category = true;
break;
}
}
}
if ( false === $show_category ) {
$this->exclude[] = $term->term_id;
}
}
}
}
public function get_parent_cats ($cat_termid, $found = array()) {
array_push ($found, $cat_termid);
$term = get_term_by( 'term_id', $cat_termid, 'product_cat');
if( !is_object($term) ) {
return $found;
}
if($term->parent > 0){
return $this->get_parent_cats($term->parent, $found);
}
return $found;
}
// ADD FILTERS FOR CATEGORIES AND EXCLUDE EMPTY
public function filter_woocommerce_product_subcategories_args( $temp_args = array() ) {
$current_tax = get_query_var( 'product_cat' );
$term =get_term_by( 'slug', $current_tax, 'product_cat');
if( !is_object($term) ) {
return $temp_args;
}
$term_id = $term->term_id;
$temp_args = array(
'parent' => $term_id,
'menu_order' => 'ASC',
'hide_empty' => 1,
'hierarchical' => 1,
'taxonomy' => 'product_cat',
'pad_counts' => 1,
'include' => NULl,
'exclude' => $this->exclude,
);
return $temp_args;
}
public function kfg_exclude_categories_from_widget( $category_list_args ) {
$current_tax = get_query_var( 'product_cat' );
$term = get_term_by( 'slug', $current_tax, 'product_cat');
if( !is_object($term) ) {
return $category_list_args;
}
$term_id = $term->term_id;
$parents = $this->get_parent_cats($term_id);
$args = array(
'hide_empty' => false,
'hierarchical' => true,
);
$product_categories = get_terms( 'product_cat', $args );
$wexclude = array();
foreach ( $product_categories as $category ) {
$posts = get_posts( array( 'post_type' => 'product', 'posts_per_page' => -1, 'product_cat' => $category->slug, 'fields' => 'ids' ) );
$show_category = false;
foreach ( $posts as $post ) {
$product = new wC_Product( $post );
$visible_product = $product->is_visible();
if ( true === $visible_product ) {
$show_category = true;
break;
}
}
if ( false === $show_category || ( $category->parent > 0 && !in_array($category->parent,$parents) ) ) {
$wexclude[] = $category->term_id;
}
}
if ( ! empty( $wexclude ) ) {
$category_list_args['exclude'] = implode( ',', $wexclude );
unset( $category_list_args['include'] );
}
return $category_list_args;
}
} // class ExcludeCats
endif; // class_exists
/**
* Returns the main instance of the plugin class to prevent the need to use globals.
*
* @since 2.0
* @return WooCommerce_PostcodeAPInu
*/
function ExcludeCats() {
return ExcludeCats::instance();
}
ExcludeCats(); // load plugin
@Akaaal
Copy link

Akaaal commented Oct 4, 2020

Should be really usefull, but not working anymore... Tested on Woocommerce 4.5.2 with this fatal error =

Fatal error: Uncaught ArgumentCountError: Too few arguments to function ExcludeCats::get_excluded_cats(), 1 passed in ./wp-includes/class-wp-hook.php on line 287 and exactly 3 expected in ./wp-content/plugins/woocommerce-hide-category/woocommerce-hide-category.php:51 Stack trace: #0 ./wp-includes/class-wp-hook.php(287): ExcludeCats->get_excluded_cats('') #1 ./wp-includes/class-wp-hook.php(311): WP_Hook->apply_filters(NULL, Array) #2 ./wp-includes/plugin.php(478): WP_Hook->do_action(Array) #3 ./wp-includes/gene in ./wp-content/plugins/woocommerce-hide-category/woocommerce-hide-category.php on line 51

@DarkAllMan
Copy link
Author

I'm still using this snippet. Without issues. Which php version are you running?

@Akaaal
Copy link

Akaaal commented Oct 6, 2020

PHP v7.3.22

@DarkAllMan
Copy link
Author

Very strange... I really do not have anny issues running this....

@Punica-zz
Copy link

same here, fatal error means it definitly not working anymore

@JapeNZ
Copy link

JapeNZ commented Apr 21, 2022

Is there an update for this please?

I think this may well be exactly what I'm looking for, but I'm getting a fatal error when I try to add it as a plugin.

I'm assuming this will resolve the issue (if fixed) that I've asked about here: https://stackoverflow.com/questions/71878350/hide-product-categories-and-or-subcategories-if-the-products-in-them-are-out-o

Appreciate any help you can provide!

Kind regards,
JP

@DarkAllMan
Copy link
Author

I'm still using this one on my live site. Can you please give me the fatal error information from your logs?

@JapeNZ
Copy link

JapeNZ commented Apr 21, 2022

Hi @DarkAllMan
Thank you for taking a look at this :)

Here's the fatal error from the log:

2022-04-21T02:13:42+00:00 CRITICAL Uncaught ArgumentCountError: Too few arguments to function ExcludeCats::get_excluded_cats(), 1 passed in /app/data/public/wp-includes/class-wp-hook.php on line 307 and exactly 3 expected in /app/data/public/wp-content/plugins/woocommerce-hide-empty-categories-shop/woocommerce-hide-empty-categories-shop.php:51
Stack trace:
#0 /app/data/public/wp-includes/class-wp-hook.php(307): ExcludeCats->get_excluded_cats()
#1 /app/data/public/wp-includes/class-wp-hook.php(331): WP_Hook->apply_filters()
#2 /app/data/public/wp-includes/plugin.php(474): WP_Hook->do_action()
#3 /app/data/public/wp-includes/general-template.php(3042): do_action()
#4 /app/data/public/wp-content/themes/responsive/header.php(29): wp_head()
#5 /app/data/public/wp-includes/template.php(770): require_once('/app/data/publi...')
#6 /app/data/public/wp-includes/template.php(716): load_template()
#7 /app/data/public/wp-includes/general-template.php(48): locate_template()
#8 /app/data/public/wp-content/themes/responsive/full-width-page.php(28): get_header in /app/data/public/wp-content/plugins/woocommerce-hide-empty-categories-shop/woocommerce-hide-empty-categories-shop.php on line 51

Let me know if you need any other details :)

@DarkAllMan
Copy link
Author

ok, I made some updates. Can you try this version please?

@JapeNZ
Copy link

JapeNZ commented Apr 21, 2022

It's no longer causing a fatal error :)
However it doesn't seem to be be hiding categories with no products in stock though.
Do I perhaps have it set up wrong, or have I misunderstood the plugin? Sorry!

If you look here: https://comicbookshop.co.nz/product-category/comic-supplies/comic-book-boards/
You'll see 'Comic Book Boards - Silver' as a subcategory option, however this doesn't have any in stock items in it.

@DarkAllMan
Copy link
Author

It does not hide categories that have items with no stock.
It only hides categories where the visitor has no visible items.
On my site, some products are only visible to a certain group of customers, so the category is only visible to them.
Other users have no visible items in that category and so they do not see it listed anywhere :)

@JapeNZ
Copy link

JapeNZ commented Apr 21, 2022

Ah right okay, so not what I was after at all... I'm sorry to have put you to work for no reason! Haha!
Hopefully the updates you made will help others though.

I wonder if I might be able to adapt your plugin for my needs?
Do you think if I were able to change the 'visibility' check to a stock level check it might work?

Regardless of whether your plugin can be adapted, thank you for taking the time to respond to my call for help :)

@DarkAllMan
Copy link
Author

It probably can be implemented in there, but it will be stressfull on categories with a lot of products, as it will need to check each product for stock.

@JapeNZ
Copy link

JapeNZ commented Apr 21, 2022

Ah right, so it could potentially slow the site to a grinding halt trying to check a large number of products... I might need to rethink my requirements.
I was hoping for something that would automatically hide a category when stock ran out... then have it magically reappear if we get more stock in for the category.
Guess I'll need to be a more pro-active with manually monitoring them instead... damn it, more work for me haha!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment