How to Add Variation Stock Status to Woocommerce Product Variation Dropdown

How to add variation stock status to Woocommerce product variation dropdown

Ok, first you'll need to get product variations like this:

$variations = $product->get_available_variations();

And inside options loop, you need to loop through the variations and find the current option stock status

foreach ($variations as $variation) {
if($variation['attributes'][$name] == $option) {
$stock = $variation['is_in_stock'];

}
}

Outside the variations loop you need to add the wording for in-stock and out-of-stock variations

if( $stock == 1) {
$stock_content = ' - In stock';
} else {
$stock_content = ' - Out of stock';
}

Then change the html to include an additional variable ($stock_content)

$html .= '<option value="' . esc_attr( $option ) . '" ' . $selected . '>' . esc_html( $option  .  $stock_content ) . '</option>'; 

So a complete function will look like this:

add_filter( 'woocommerce_dropdown_variation_attribute_options_html', 'show_stock_status_in_dropdown', 10, 2);
function show_stock_status_in_dropdown( $html, $args ) {
$options = $args['options'];
$product = $args['product'];
$attribute = $args['attribute'];
$name = $args['name'] ? $args['name'] : 'attribute_' . sanitize_title( $attribute );
$id = $args['id'] ? $args['id'] : sanitize_title( $attribute );
$class = $args['class'];
$show_option_none = $args['show_option_none'] ? true : false;
$show_option_none_text = $args['show_option_none'] ? $args['show_option_none'] : __( 'Choose an option', 'woocommerce' );

// Get all product variations
$variations = $product->get_available_variations();

if ( empty( $options ) && ! empty( $product ) && ! empty( $attribute ) ) {
$attributes = $product->get_variation_attributes();
$options = $attributes[ $attribute ];
}

$html = '<select id="' . esc_attr( $id ) . '" class="' . esc_attr( $class ) . '" name="' . esc_attr( $name ) . '" data-attribute_name="attribute_' . esc_attr( sanitize_title( $attribute ) ) . '" data-show_option_none="' . ( $show_option_none ? 'yes' : 'no' ) . '">';
$html .= '<option value="">' . esc_html( $show_option_none_text ) . '</option>';

if ( ! empty( $options ) ) {
if ( $product && taxonomy_exists( $attribute ) ) {
// Get terms if this is a taxonomy - ordered. We need the names too.
$terms = wc_get_product_terms( $product->get_id(), $attribute, array( 'fields' => 'all' ) );

foreach ( $terms as $term ) {
if ( in_array( $term->slug, $options ) ) {
$html .= '<option value="' . esc_attr( $term->slug ) . '" ' . selected( sanitize_title( $args['selected'] ), $term->slug, false ) . '>' . esc_html( apply_filters( 'woocommerce_variation_option_name', $term->name ) ) . '</option>';
}
}
} else {
foreach ( $options as $option ) {
foreach ($variations as $variation) {
if($variation['attributes'][$name] == $option) {
$stock = $variation['is_in_stock'];
}
}
if( $stock == 1) {
$stock_content = ' - (In Stock)';
} else {
$stock_content = ' - (Out of Stock)';
}
// This handles < 2.4.0 bw compatibility where text attributes were not sanitized.
$selected = sanitize_title( $args['selected'] ) === $args['selected'] ? selected( $args['selected'], sanitize_title( $option ), false ) : selected( $args['selected'], $option, false );

$html .= '<option value="' . esc_attr( $option ) . '" ' . $selected . '>' . esc_html( $option . $stock_content ) . '</option>';

}
}
}

$html .= '</select>';

return $html;
}

Add variation stock quantity and status to Woocommerce product variation dropdown

There are some mistakes in your code and a better way to shows stock quantity + stock status in product variation dropdown.

The first function is a custom function where you will define the stock text addition to be displayed in the product variation dropdown, which is handled by the second function.

In your last function, since Woocommerce 3, get_total_stock() is deprecated and replaced by the method get_stock_quantity(). Also you need to use the variation $product object that is included as an argument in the hooked function.

Note: This will only work for variable products with one dropdown (one defined product attribute for variations)

Here is the revisited code:

// Function that will check the stock status and display the corresponding additional text
function get_variation_stock_text( $product, $name, $term_slug ){
foreach ( $product->get_available_variations() as $variation ){
if($variation['attributes'][$name] == $term_slug ){
$is_in_stock = $variation['is_in_stock'];
$stock_qty = get_post_meta($variation['variation_id'], '_stock', true);
}
}
$in_stock = ' ('.$stock_qty.' ' .__("Skladem", "woocommerce").')';
$out_of_stock = ' ('.__("Vyprodáno", "woocommerce").')';

return $is_in_stock == 1 ? $in_stock : $out_of_stock;
}

// The hooked function that will add the stock text to the dropdown options elements.
add_filter( 'woocommerce_dropdown_variation_attribute_options_html', 'show_stock_status_in_dropdown', 10, 2);
function show_stock_status_in_dropdown( $html, $args ) {
// Only if there is a unique variation attribute (one dropdown)
if( sizeof($args['product']->get_variation_attributes()) == 1 ) :

$options = $args['options'];
$product = $args['product'];
$attribute = $args['attribute']; // The product attribute taxonomy
$name = $args['name'] ? $args['name'] : 'attribute_' . sanitize_title( $attribute );
$id = $args['id'] ? $args['id'] : sanitize_title( $attribute );
$class = $args['class'];
$show_option_none = $args['show_option_none'] ? true : false;
$show_option_none_text = $args['show_option_none'] ? $args['show_option_none'] : __( 'Choose an option', 'woocommerce' );

if ( empty( $options ) && ! empty( $product ) && ! empty( $attribute ) ) {
$attributes = $product->get_variation_attributes();
$options = $attributes[ $attribute ];
}

$html = '<select id="' . esc_attr( $id ) . '" class="' . esc_attr( $class ) . '" name="' . esc_attr( $name ) . '" data-attribute_name="attribute_' . esc_attr( sanitize_title( $attribute ) ) . '" data-show_option_none="' . ( $show_option_none ? 'yes' : 'no' ) . '">';
$html .= '<option value="">' . esc_html( $show_option_none_text ) . '</option>';

if ( ! empty( $options ) ) {
if ( $product && taxonomy_exists( $attribute ) ) {
$terms = wc_get_product_terms( $product->get_id(), $attribute, array( 'fields' => 'all' ) );

foreach ( $terms as $term ) {
if ( in_array( $term->slug, $options ) ) {
// HERE Added the function to get the stock text
$stock_text = get_variation_stock_text( $product, $name, $term->slug );

$html .= '<option value="' . esc_attr( $term->slug ) . '" ' . selected( sanitize_title( $args['selected'] ), $term->slug, false ) . '>' . esc_html( apply_filters( 'woocommerce_variation_option_name', $term->name ) . $stock_text ) . '</option>';
}
}
} else {
foreach ( $options as $option ) {
$selected = sanitize_title( $args['selected'] ) === $args['selected'] ? selected( $args['selected'], sanitize_title( $option ), false ) : selected( $args['selected'], $option, false );
// HERE Added the function to get the stock text
$stock_text = get_variation_stock_text( $product, $name, $option );

$html .= '<option value="' . esc_attr( $option ) . '" ' . $selected . '>' .
esc_html( apply_filters( 'woocommerce_variation_option_name', $option ) . $stock_text ) . '</option>';
}
}
}
$html .= '</select>';

endif;

return $html;
}

// Change product availability text
add_filter( 'woocommerce_get_availability_text', 'filter_product_availability_text', 10, 2);
function filter_product_availability_text( $availability, $product ) {
$stock = $product->get_stock_quantity();
return $product->is_in_stock() ? $stock . ' ' . __("Skladem", "woocommerce") : __("Vyprodáno", "woocommerce");
}

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

Based on "How to add variation stock status to Woocommerce product variation dropdown"

Display Woocommerce Variation Price and Stock Status in dropdown

i have modified your function by removing the custom sql query and use WooCommerce built in functions to achieve the target goal.

add_filter( 'woocommerce_variation_option_name','display_price_in_variation_option_name');

function display_price_in_variation_option_name( $term ) {
global $product;

if ( empty( $term ) ) {
return $term;
}
if ( empty( $product->id ) ) {
return $term;
}

$variation_id = $product->get_children();

foreach ( $variation_id as $id ) {
$_product = new WC_Product_Variation( $id );
$variation_data = $_product->get_variation_attributes();

foreach ( $variation_data as $key => $data ) {

if ( $data == $term ) {
$html = wp_kses( woocommerce_price( $_product->get_price() ), array() );
$html .= ' - ' . $term;
$html .= ( $_product->get_stock_quantity() ) ? ' - ' . $_product->get_stock_quantity() : '';
return $html;
}
}
}

return $term;

}

Note : this function will work correctly if each product have one attribute not combined one.

OutPut:

Sample Image

Showing Out of Stock text next to variation in Woocommerce product with multuiple variations

You can check the availability of a product variation only if all but one of the attributes have been selected, not before.

All the necessary data is present on the product page and therefore you can use a jQuery script to process it.

In the variation form there is the data-product_variations attribute which contains an array with all the details of the product variations (variation id, stock status, attributes it uses, etc ...).

You can then make a comparison between the selected attributes and possible product variations.

The idea is this:

  1. Check that there is more than one attribute (dropdown) on the product page
  2. If all attributes (dropdowns) have been selected except one, get the attribute slug and the attribute value of the selected options
  3. It compares them with the attributes that each single variation uses and, if the selected attributes are the same, gets the stock status of the last attribute to be selected
  4. Adds the text "Out of stock" to each option whose product variation is not in stock. To do this it will use the woocommerce_update_variation_values event which fires after updating the options via Ajax (otherwise the changes will be overwritten)

The following code will work for 2 or more attributes (dropdowns) in
the variable product page.

// add the text "Out of stock" to each option of the last unselected attribute dropdown
add_action( 'wp_footer', 'add_out_of_stock_text_to_the_last_unselected_attribute_dropdown' );
function add_out_of_stock_text_to_the_last_unselected_attribute_dropdown() {

?>
<script type="text/javascript">

// initializes a global variable that will contain the attribute values to be updated ("Out of stock")
let globalAttributesToUpdate;

jQuery(function($){

// check if only one attribute is missing to be selected
function isLastAttribute(){
// if there is only one dropdown it returns false
if ( $('form.variations_form select').length == 1 ) {
return false;
}
// counts all selected attributes (excluding "Choose an option")
let count = 0;
$('form.variations_form select').each(function(){
if ( $(this).find(':selected').val() ) {
count++;
}
});
// if an attribute has not yet been selected, it returns true
if ( $('form.variations_form select').length - count == 1 ) {
return true;
} else {
return false;
}
}

$('form.variations_form select').change(function() {
if ( isLastAttribute() ) {
// clear the global variable every time
globalAttributesToUpdate = [];
let attrToFind = {}; // contains an object with slug and value of the selected attributes
let attrToSet; // contains the slug of the attribute not yet selected
$('form.variations_form select').each(function(index,object){
if ( $(this).find(":selected").val() ) {
attrToFind[$(this).data('attribute_name')] = $(this).find(":selected").val();
} else {
attrToSet = $(this).data('attribute_name');
}
});
// gets the value of the "data-product_variations" attribute of the variations form
let variationData = $('form.variations_form').data("product_variations");
$(variationData).each(function(index,object) {
let attrVariation = object.attributes;
let attrVariationLenght = Object.keys(attrVariation).length;
let found = 0;
let toSet;
let valueToSet;
// check all possible combinations of attributes (for single variation)
// based on the selected attributes
$.each( attrVariation, function( attr, value ) {
if ( attr in attrToFind && attrToFind[attr] == value ) {
found++;
} else {
// if the variation is out of stock it gets slug and value to add the text "Out of stock"
if ( object.is_in_stock == false ) {
toSet = attr;
valueToSet = value;
}
}
});
// if only one attribute is missing
if ( attrVariationLenght - found == 1 ) {
if ( toSet == attrToSet ) {
let obj = {};
obj[toSet] = valueToSet;
globalAttributesToUpdate.push(obj);
}
}
});
}
});

// inserts the text "Out of stock" after updating the variations
// based on the "globalAttributesToUpdate" global variable
$('body').on('woocommerce_update_variation_values', function(){
if ( globalAttributesToUpdate !== undefined && globalAttributesToUpdate.length ) {
$.each( globalAttributesToUpdate, function( key, attribute ) {
$.each( attribute, function( attrName, attrValue ) {
$('select[name='+attrName+'] > option[value="'+attrValue+'"]').append( " (Out of stock)" );
});
});
}
});
});
</script>
<?php

}

The code has been tested and works. Add it to your active theme's functions.php.

RESULT

Sample Image

RELATED ANSWERS

  • How to add variation stock status to Woocommerce product variation dropdown
  • Show stock status next to each attribute value in WooCommerce variable products
  • Display variation stock status on single dropdown variable products in Wocommerce 3

Add a custom class to variation options displaying Out Of Stock in Woocommerce

The following code will add the class outofstock to <option> html tag when the variation is "Out of Stock":

// Function that will check the stock status and display the corresponding additional text
function get_stock_status_text( $product, $name, $term_slug ){
foreach ( $product->get_available_variations() as $variation ){
if($variation['attributes'][$name] == $term_slug )
$stock = $variation['is_in_stock'];
}

return $stock == 1 ? ' - (In Stock)' : ' - (Out of Stock)';
}

// The hooked function that will add the stock status to the dropdown options elements.
add_filter( 'woocommerce_dropdown_variation_attribute_options_html', 'show_stock_status_in_dropdown', 10, 2);
function show_stock_status_in_dropdown( $html, $args ) {
// Only if there is a unique variation attribute (one dropdown)
if( sizeof($args['product']->get_variation_attributes()) == 1 ) :

$options = $args['options'];
$product = $args['product'];
$attribute = $args['attribute']; // The product attribute taxonomy
$name = $args['name'] ? $args['name'] : 'attribute_' . sanitize_title( $attribute );
$id = $args['id'] ? $args['id'] : sanitize_title( $attribute );
$class = $args['class'];
$show_option_none = $args['show_option_none'] ? true : false;
$show_option_none_text = $args['show_option_none'] ? $args['show_option_none'] : __( 'Choose an option', 'woocommerce' );

if ( empty( $options ) && ! empty( $product ) && ! empty( $attribute ) ) {
$attributes = $product->get_variation_attributes();
$options = $attributes[ $attribute ];
}

$html = '<select id="' . esc_attr( $id ) . '" class="' . esc_attr( $class ) . '" name="' . esc_attr( $name ) . '" data-attribute_name="attribute_' . esc_attr( sanitize_title( $attribute ) ) . '" data-show_option_none="' . ( $show_option_none ? 'yes' : 'no' ) . '">';
$html .= '<option value="">' . esc_html( $show_option_none_text ) . '</option>';

if ( ! empty( $options ) ) {
if ( $product && taxonomy_exists( $attribute ) ) {
$terms = wc_get_product_terms( $product->get_id(), $attribute, array( 'fields' => 'all' ) );

foreach ( $terms as $term ) {
if ( in_array( $term->slug, $options ) ) {
// HERE Added the function to get the text status
$stock_status = get_stock_status_text( $product, $name, $term->slug );

// HERE we add a custom class to <option> that are "Out of stock"
$option_class = $stock_status === ' - (Out of Stock)' ? ' class="outofstock"' : '';

$html .= '<option value="' . esc_attr( $term->slug ) . '" ' . selected( sanitize_title( $args['selected'] ), $term->slug, false ) . $option_class . '>' . esc_html( apply_filters( 'woocommerce_variation_option_name', $term->name ) . $stock_status ) . '</option>';
}
}
} else {
foreach ( $options as $option ) {
$selected = sanitize_title( $args['selected'] ) === $args['selected'] ? selected( $args['selected'], sanitize_title( $option ), false ) : selected( $args['selected'], $option, false );
// HERE Added the function to get the text status
$stock_status = get_the_stock_status( $product, $name, $option );

// HERE we add a custom class to <option> that are "Out of stock"
$option_class = $stock_status === ' - (Out of Stock)' ? ' class="outofstock"' : '';

$html .= '<option value="' . esc_attr( $option ) . '" ' . $selected . $option_class . '>' .
esc_html( apply_filters( 'woocommerce_variation_option_name', $option ) . $stock_status ) . '</option>';
}
}
}
$html .= '</select>';

endif;

return $html;
}

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

Sample Image

WooCommerce Update Product Variation Stock Status based on Quantities of other Variation's Stock

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.

Add Stock Status boolean as custom attribute of WooCommerce variation selector

With a bit of playing around, it looks like I’ve come up with a solution. If there’s a more efficient or tidier way to achieve the result, I’d be very interested to know. This solution does at least have the desired output.

I have modified the code (from my question) to the following:

/******* ADD STOCK STATUS TO DROP DOWN SELECTOR ******/
// Function that will check the stock status and display the corresponding additional text
function get_stock_status_text( $product, $name, $term_slug ){
foreach ( $product->get_available_variations() as $variation ){
if($variation['attributes'][$name] == $term_slug ) {
$stock = $variation['is_in_stock'];
break;
}
}
return $stock == 1 ? ' - (In Stock)' : ' - (No Stock)';
}

function get_stock_status_bool( $product, $name, $term_slug ){
foreach ( $product->get_available_variations() as $variation ){
if($variation['attributes'][$name] == $term_slug ) {
$stock_bool = $variation['is_in_stock'];
break;
}
}
return $stock_bool == 1 ? 'true' : 'false';
}

// The hooked function that will add the stock status to the dropdown options elements.


Related Topics



Leave a reply



Submit