Search code examples
phpwordpresswoocommercehook-woocommercewoocommerce-theming

How do I show sold/out of stock items in a certain Woocommerce category archive page, but not display them in others?


I want to display 'Out of Stock' items on one category archive page: 'Sold Items'.

All other categories need to hide its Out of Stock items.

'Hide out of stock items from the catalog', within the WC settings is not ticked.

I have the below code, which successfully hides out of stock items, but I cannot get the has_term() function to work correctly and filter out the 'Sold Items' page.

I believe it may be because I'm hooking into 'pre_get_posts' and perhaps this fires before the 'Sold Items' term has been added.

Which is the best action to hook into? Or do I need to split this over two hooks?

add_action( 'pre_get_posts', 'VG_hide_out_of_stock_products' ); 
function VG_hide_out_of_stock_products( $q ) {

    if ( ! $q->is_main_query() || is_admin() ) {
         return;
    }

    global $post;
    if ( !has_term( 'Sold Items', 'product_cat', $post->ID ) ) {
        if ( $outofstock_term = get_term_by( 'name', 'outofstock', 'product_visibility' ) ) {
            $tax_query = (array) $q->get('tax_query');
            $tax_query[] = array(
                'taxonomy' => 'product_visibility',
                'field' => 'term_taxonomy_id',
                'terms' => array( $outofstock_term->term_taxonomy_id ),
                'operator' => 'NOT IN'
            );
            $q->set( 'tax_query', $tax_query );
        }
    } 
}

Solution

  • It's better to use a high level WooCommerce specific filter hook, instead of low level WordPress hooks which could cause headache and trouble. (e.g. pre_get_posts) For your scenario I suggest woocommerce_product_query_tax_query filter hook. Assuming you have a category with all out of stock products in it, with slug sold-items, the final code could be something like this:

    add_filter( 'woocommerce_product_query_tax_query', 'vg_hide_out_of_stock_products' );
    
    function vg_hide_out_of_stock_products( $tax_query ) {
    
        if( !is_shop() && !is_product_category() && !is_product_tag() ) {
            return $tax_query;
        }
        if( is_product_category('sold-items') ) {
            $tax_query[] = array(
                'taxonomy' => 'product_visibility',
                'field'    => 'slug',
                'terms'    => ['outofstock'],
                'operator' => 'IN',
            );
        } else {
            $tax_query[] = array(
                'taxonomy' => 'product_visibility',
                'field'    => 'slug',
                'terms'    => ['outofstock'],
                'operator' => 'NOT IN',
            );
        }
        return $tax_query;
    }
    

    P.S: Function names are not case sensitive in PHP :)