skip to Main Content

Good day,

I have a product with 4 variations (variations made from the ‘size’ attribute): Small, Medium, Large and Full Set (all 3 sizes). People can choose to buy only a single size or buy a set that has all 3 sizes (prices differ for all 4 variations).

I only have stock management (with backorders allowed) selected for the 3 size variations (small, medium, large) and for the Set variation I have only selected the stock status to be ‘in stock’. I need to automatically change the Set variation stock status based on the stock quantities of the size variations.

When I have 1 Small, 1 Medium and 1 Large, I obviously also have a Set in stock. But, for instance, when someone buys the small one, then I do not have a full Set anymore. I would like to automatically update the stock status of the Set variation to ‘on backorder’. Also, the other way around would be, when someone buys a full Set to automatically update the stock quantities of Small, Medium & Large with -1.

SMALL - 1x in stock
MEDIUM - 1x in stock
LARGE - 1x in stock
FULL SET - stock status: 'in stock' (only 'in-stock' when there is at least 1 of each; small, medium, large)

When someone buys a full set:

SMALL - 1x in stock -1 = 0x in stock
MEDIUM - 1x in stock -1 = 0x in stock
LARGE - 1x in stock -1 = 0x in stock
FULL SET - stock status: 'on backorder' (only 'in-stock' when there is at least 1 of each; small, medium, large)

All of the products make use of these variations and they will not change.

Dummy code will probably be something like (this will in no way work, I was just trying to put something together from a lot of internet searches):

To set the Full Set stock status:

function fullset_custom_stockstatus (){
    global $product;
    // Get the available variations
    $available_variations = $product->get_available_variations();

    // Get the term slugs
    $attribute_slug = $values['attributes']['attribute_pa_headcover-size'];
    $wp_term = get_term_by( 'slug', $attribute_slug, 'pa_headcover-size' );
    $term_slug = $wp_term->slug; // Headcover Size Slug 

    // Get the variation quantity
    $variation_obj = wc_get_product( $values['variation_id'] );
    $stock_qty = $variation_obj->get_stock_quantity(); // Stock qty

    //Seperate variation stock data
    $var_small = $term_slug['small'].$stock_qty;
    $var_medium = $term_slug['medium'].$stock_qty;
    $var_large = $term_slug['large'].$stock_qty;

    $var_fullset = $term_name['full-set'].$stock_status;
    
    //Check if each variation stock is 1 or more
    if ($var_small == 0 || $var_medium == 0 || $var_large == 0){
        $var_fullset = 'on-backorder';
    }
    else{
        $var_fullset = 'in-stock';
    }
}
add_action( 'woocommerce_order_item_quantity', 'fullset_custom_stockstatus');

To update the variation quantities when a full set was bought:

function update_stockqty_after_fullset_order (){

    //Get the order information
    $order = wc_get_order( $order_id );
    foreach( $order->get_items() as $item ){
        $order_product_id = $item->get_product_id();
        $order_variation_id = $item->get_variation_id();

        //Get the order variation information
        $order_variation = wc_get_product($order_variation_id);
        $order_variation_attribs = $order_variation->get_variation_attributes();
        
        //Check if order variation is 'full-set'
        if ($order_variation_attribs !== 'full-set' ){

            //Get the order product variation information
            $product = wc_get_product( $order_product_id );
            $variations = $product->get_available_variations();

            // Get the term slugs
            $attribute_slug = $values['attributes']['attribute_pa_headcover-size'];
            $wp_term = get_term_by( 'slug', $attribute_slug, 'pa_headcover-size' );
            $term_slug = $wp_term->slug; // Headcover Size Slug 

            // Get the variation quantity
            $variation_obj = wc_get_product( $values['variation_id'] );
            $stock_qty = $variation_obj->get_stock_quantity(); // Stock qty

            //Seperate variation stock data
            $var_small = $term_slug['small'].$stock_qty;
            $var_medium = $term_slug['medium'].$stock_qty;
            $var_large = $term_slug['large'].$stock_qty;

            //Update the stock quanities
            wc_update_product_stock( $var_small, 'decrease' ); 
            wc_update_product_stock( $var_medium, 'decrease' ); 
            wc_update_product_stock( $var_large, 'decrease' ); 

            // Clear/refresh the variation cache (optionally if needed)
            wc_delete_product_transients($variation['variation_id']);

        } else {
         return;
        }
    }
}
add_action( 'woocommerce_order_status_processing', 'update_stockqty_after_fullset_order');

Any help would be highly appreciated.

2

Answers


  1. Chosen as BEST ANSWER

    Thanks to @Vdgaetano's code I could have get the code to fit my needs. Thank you again @Vdgaetano - you are awesome! :-)

    add_action( 'woocommerce_order_status_processing', 'update_stock_quantity_product', 999999, 2 );
    function update_stock_quantity_product( $order_id, $order ) {
    
        foreach ( $order->get_items() as $item_id => $item_data ) {
    
            $product = $item_data->get_product();
    
            // only if the product is a variation
            if ( ! $product->is_type( 'variation' ) ) {
                continue;
            }
    
            $variation_attributes = $product->get_variation_attributes(); // get the variation attributes
            foreach ( $variation_attributes as $attribute_value ) {
                // check attribute value
                switch ( $attribute_value ) {
                    case 'small':
                    case 'medium':
                    case 'large':
                        $qty = $item_data->get_quantity(); // get ordered quantity
                        $variable = wc_get_product( $product->get_parent_id() ); // get variable product
                        $variation_ids = $variable->get_children();
                        foreach ( $variation_ids as $variation_id ) {
                            $variation = wc_get_product( $variation_id );
                            $attributes = $variation->get_variation_attributes();
                            foreach ( $attributes as $value ) {
                                if ( $value == 'small' ) {
                                    $smallstock = $variation->get_stock_quantity();
                                }
                                if ( $value == 'medium' ) {
                                    $mediumstock = $variation->get_stock_quantity();
                                }
                                if ( $value == 'large' ) {
                                    $largestock = $variation->get_stock_quantity();
                                }
                                if ( $value == 'full-set' ) {
                                    if ( $smallstock == 0 || $mediumstock == 0 || $largestock == 0) {                                    
                                        $variation->set_stock_status( 'onbackorder' ); 
                                        $variation->save(); // save the data and refresh caches
                                    } else {                                    
                                        $variation->set_stock_status( 'instock' );
                                        $variation->save(); // save the data and refresh caches
                                    }
                                    break;
                                }
                            }
                        }
                        break;
                        case 'full-set':
                            $qty = $item_data->get_quantity(); // get ordered quantity
                            $variable = wc_get_product( $product->get_parent_id() ); // get variable product
                            $variation_ids = $variable->get_children();
                            foreach ( $variation_ids as $variation_id ) {
                                $variation = wc_get_product( $variation_id );
                                $attributes = $variation->get_variation_attributes();
                                foreach ( $attributes as $value ) {
                                    switch ( $value ) {
                                        case 'small':
                                        case 'medium':
                                        case 'large':
                                            $stock = $variation->get_stock_quantity();
                                            $new_stock = $stock - $qty;
                                            if ( $new_stock > 0 ) {
                                                $variation->set_stock_quantity( $new_stock );
                                                $variation->set_stock_status( 'instock' ); 
                                                $variation->save(); // save the data and refresh caches
                                            } else {
                                                $variation->set_stock_quantity( 0 );
                                                $variation->set_stock_status( 'outofstock' );
                                                $variation->save(); // save the data and refresh caches
                                            }
                                            break;
                                    }
                                }
                            }
                            break;
                    default:
                        break;
                }
            }
            
        }
    }
    

  2. You can use the woocommerce_order_status_processing hook which is activated when the order status is changed to wc-processing.

    UPDATED

    The "full-set" variation is updated only if:

    1. at least one "small", "medium" or "large" variation was purchased
    2. the smallest stock quantity of the "small", "medium" and "large" variations is less than the stock quantity of the "full-set" variation

    In this way the stock quantity of the "full-set" variation will be equal to the minimum salable quantity based on the stock quantities of the "small", "medium" and "large" variations.

    When the stock quantity of the "full-set" variation is less than or equal to zero, it enables back orders.

    add_action( 'woocommerce_order_status_processing', 'update_stock_quantity_product', 999, 2 );
    function update_stock_quantity_product( $order_id, $order ) {
    
        foreach ( $order->get_items() as $item_id => $item_data ) {
    
            $product = $item_data->get_product();
    
            // only if the product is a variation
            if ( ! $product->is_type( 'variation' ) ) {
                continue;
            }
    
            // initializes the array that will contain the quantity stocks of "small", "medium" and "large" products
            $min_stock = array();
    
            $variation_attributes = $product->get_variation_attributes(); // get the variation attributes
            foreach ( $variation_attributes as $attribute_value ) {
                switch ( $attribute_value ) {
                    case 'small':
                        $min_stock[] = $product->get_stock_quantity();
                        break;
                    case 'medium':
                        $min_stock[] = $product->get_stock_quantity();
                        break;
                    case 'large':
                        $min_stock[] = $product->get_stock_quantity();
                        break;
                }
            }
    
            $variation_attributes = $product->get_variation_attributes(); // get the variation attributes
            foreach ( $variation_attributes as $attribute_value ) {
                // check attribute value
                switch ( $attribute_value ) {
                    case 'small':
                    case 'medium':
                    case 'large':
                        $qty = $item_data->get_quantity(); // get ordered quantity
                        $variable = wc_get_product( $product->get_parent_id() ); // get variable product
                        $variation_ids = $variable->get_children();
                        foreach ( $variation_ids as $variation_id ) {
                            $variation = wc_get_product( $variation_id );
                            $attributes = $variation->get_variation_attributes();
                            foreach ( $attributes as $value ) {
                                if ( $value == 'full-set' ) {
                                    if ( ! empty( $min_stock ) ) { // if is not empty
                                        // get the minimum value of the array
                                        $new_stock = min( $min_stock );
                                        // get the stock quantity of the "full-set" variation
                                        $stock = $variation->get_stock_quantity();
                                        // updates the stock quantity only if the minimum availability of the "small", "medium" and "large" variations
                                        // is less than the availability of the "full-set" variation
                                        if ( $new_stock < $stock ) {
                                            if ( $new_stock > 0 ) {
                                                $variation->set_stock_quantity( $new_stock );
                                                $variation->set_stock_status( 'instock' ); 
                                                $variation->save(); // save the data and refresh caches
                                            } else {
                                                $variation->set_stock_quantity( 0 );
                                                $variation->set_stock_status( 'outofstock' );
                                                $variation->set_backorders( 'yes' );
                                                $variation->save(); // save the data and refresh caches
                                            }
                                        }
                                    }
                                    break;
                                }
                            }
                        }
                        break;
                        case 'full-set':
                            $qty = $item_data->get_quantity(); // get ordered quantity
                            $variable = wc_get_product( $product->get_parent_id() ); // get variable product
                            $variation_ids = $variable->get_children();
                            foreach ( $variation_ids as $variation_id ) {
                                $variation = wc_get_product( $variation_id );
                                $attributes = $variation->get_variation_attributes();
                                foreach ( $attributes as $value ) {
                                    switch ( $value ) {
                                        case 'small':
                                        case 'medium':
                                        case 'large':
                                            $stock = $variation->get_stock_quantity();
                                            $new_stock = $stock - $qty;
                                            if ( $new_stock > 0 ) {
                                                $variation->set_stock_quantity( $new_stock );
                                                $variation->set_stock_status( 'instock' ); 
                                                $variation->save(); // save the data and refresh caches
                                            } else {
                                                $variation->set_stock_quantity( 0 );
                                                $variation->set_stock_status( 'outofstock' );
                                                $variation->save(); // save the data and refresh caches
                                            }
                                            break;
                                        case 'full-set':
                                            $stock = $variation->get_stock_quantity();
                                            $new_stock = $stock - $qty;
                                            if ( $new_stock <= 0 ) {
                                                // enables backorders for the "full-set" product if the stock quantity is less than or equal to zero
                                                $variation->set_backorders( 'yes' );
                                                $variation->save(); // save the data and refresh caches
                                            }
                                            break;
                                    }
                                }
                            }
                            break;
                    default:
                        break;
                }
            }
        }
    }
    

    I have tested the code and it works. The code goes into your theme’s functions.php.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search