简体   繁体   中英

Hide WooCommerce variable product from catalog if all variations are out of stock

Within my WooCommerce shop, there are products with variations in color. The update on the stock is on variations level because the external feed sees every color as a different product.

Now I've got a issue where all the variations of a variable product are out of stock , but the product itself still show up in the catalog of the Webshop. Even tho I turn on the setting "Hide out of stock items from the catalog". But this setting only works for products without variations.

When you click on a product with variations that are all out of stock it shows: "This product is currently out of stock and unavailable.".

Is there a setting in WooCommerce that can also hide those products in my catalog? Or do I've to make an extra script that will check every variable product and put it out of stock at its highest level?

The code that I tried on a variable product with no effect:

$out_of_stock_staus = 'outofstock';

// 1. Updating the stock quantity
update_post_meta($product_id, '_stock', 0);

// 2. Updating the stock status
update_post_meta( $product_id, '_stock_status', wc_clean( $out_of_stock_staus ) );

// 3. Updating post term product visibility
wp_set_post_terms( $product_id, $out_of_stock_staus, 'product_visibility', true ); 

How can I hide WooCommerce variable product from catalog if all variations are out of stock?

Note: Since WooCommerce 3 and 4, it's better to use WC_Product available methods as there are new custom tables and cached data to update.

There is a way to show or hide variable products from product catalog (a bit complex) .

1). A lightweight conditional function to check if a variable product has all it's product variations "out of stock":

// Conditional function to check if a variable product has at least a variation in stock
function is_wc_variable_product_in_stock( $product_id ){
    global $wpdb;

    $count = $wpdb->get_var( $wpdb->prepare( "
        SELECT COUNT(ID)
        FROM {$wpdb->posts} p
        INNER JOIN {$wpdb->postmeta} pm
            ON p.ID           =  pm.post_id
        WHERE p.post_type     =  'product_variation'
            AND p.post_status =  'publish'
            AND p.post_parent =  %d
            AND pm.meta_key   =  '_stock_status'
            AND pm.meta_value != 'outofstock'
    ", $product_id ) );

    return $count > 0 ? true : false;
}

Code goes in function.php file of your active child theme (or active theme). This function is needed for the following, so keep it.


2). A custom function that will check for all your variable products (and all their variations stock) adding custom meta data (This function will be used just once and then removed).

// Function that will check the variations stock for each variable products adding custom meta data
function check_and_update_all_variable_products(){
    // Only for admins
    if( ! current_user_can('edit_products')) return;

    // get all variable product Ids
    $variable_products_ids = wc_get_products( array(
        'limit'  => -1,
        'status' => 'publish',
        'type'   => 'variable',
        'return' => 'ids',
    ));

    // Loop through variable products
    foreach( $variable_products_ids as $variable_id ) {
        // Check if all the product variations are "out of stock" or not
        $value      = is_wc_variable_product_in_stock( $variable_id ) ? '0' : '1';

        $meta_value = (string) get_post_meta( $variable_id, '_all_variations_outofstock', true );

        if ( $value !== $meta_value ) {
            // Create/Udpate custom meta data
            update_post_meta( $variable_id, '_all_variations_outofstock', $value );
        }
    }
}
// Run the function: browse any page of your web site
check_and_update_all_variable_products();

Code goes in function.php file of your active child theme (or active theme). Once saved, brownse any page of your we site, to run this function. Then remove it afterwards.


3). Now a hooked function that will hide your variable products which variations are all "out of stock", from WooCommerce catalog and from single product pages:

// Hide product variations which variations are all "out of stock"
add_action( 'woocommerce_product_query', 'hide_variable_products_with_all_outofstock_variations', 10, 2 );
function hide_variable_products_with_all_outofstock_variations( $q, $query ) {
    // Get any existing meta query
    $meta_query = $q->get( 'meta_query');

    // Define an additional meta query
    $meta_query['relation'] = 'OR';
    $meta_query[] = array(
        'key'     => '_all_variations_outofstock',
        'value'   => '1',
        'compare' => '!=',
    );
    $meta_query[] = array(
        'key'     => '_all_variations_outofstock',
        'compare' => 'NOT EXISTS',
    );

    // Set the new merged meta query
    $q->set( 'meta_query', $meta_query );
}

// Hide "Out of stock" variable product single pages
add_action( 'template_redirect', 'hide_out_of_stock_variable_product_single_pages' );
function hide_out_of_stock_variable_product_single_pages(){
    if( get_post_meta( get_the_id(), '_all_variations_outofstock', true ) ) {
        // Redirect to Shop page
        wp_redirect( wc_get_page_permalink( 'shop' ) );
        exit();
    }
}

Code goes in function.php file of your active child theme (or active theme). tested and works.


4). Add / Update product variation stock custom meta: On admin single product pages, check variable product stock status and update custom meta data (and also when a paid order update the product stock) :

// Custom function that update the parent variable product stock custom meta data
function update_parent_variable_product_stock_custom_meta( $product_var ) {
    if( ! is_a($product_var, 'WC_Product') ) {
        $product = wc_get_product( $product_var );
    } else { $product = $product_var; }

    if ( $product->is_type('variation') ) {
        // Get the parent product id from product variation
        $product_id = (int) $product->get_parent_id();
    } elseif ( $product->is_type('variable') ) {
        $product_id = (int) $product->get_id();
    } else {
        return; // Exit
    }

    // Check if all the product variations are "out of stock" or not
    $value = is_wc_variable_product_in_stock( $product_id ) ? '0' : '1';

    // add/Udpate custom meta data
    update_post_meta( $variable_id, '_all_variations_outofstock', $value );
}

// Update variable product stock custom meta data on admin single product pages
add_action( 'woocommerce_process_product_meta_variable', 'update_variable_product_stock_custom_meta_data' );
function update_product_variable_stock_custom_meta_data ( $product_id ) {
    update_parent_variable_product_stock_custom_meta( $product_id );
}

// On processed update product stock event (Like on orders)
add_action( 'woocommerce_updated_product_stock', 'wc_updated_product_stock_callback' );
function wc_updated_product_stock_callback ( $product_id ) {
    update_parent_variable_product_stock_custom_meta( $product_id );
}

Code goes in function.php file of your active child theme (or active theme). tested and works.


5). Change a product stock status programmatically and add/update product variation stock custom meta (your revisited code, but for product variations or even simple products) :

$stock_status = 'outofstock';

// Get an instance of WC_Product Object from the product ID (product variation)
$product = wc_get_product( $product_id );

// 1. Updating the stock quantity
$product->set_stock_quantity(0);

// 2. Updating the stock status (and "product_visibility" related term )
$product->set_stock_status($stock_status);

// 3. Save product data and refresh cached data
$product->save();

// Update parent variable product stock custom meta data
update_parent_variable_product_stock_custom_meta( $product );

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM