Set Quantity Minimum, Maximum and Step at Product Level in Woocommerce

Set quantity minimum, maximum and step at product level in Woocommerce

Updated December 2020

The following revisited code will allow in addition to handle quantity steps.

I have changed quantity fields settings location to "General" settings tab.

I have added a checkbox that enables or disables those additional quantity settings at product level (showing or hiding the setting fields dynamically):

When checkbox unchecked (fields are not visible and quantity settings are disabled):

Sample Image

When checkbox is checked (fields are visible and quantity settings are enabled):

Sample Image

I have merged all settings in a unique custom field as an indexed array of values, to improve performance.

Since WooCommerce version 3, things have changed a lot, so I have made some changes enhancing and updating code to something more newer.

Also works nicely on Ajax add to cart for simple products, for product variations from variable products and also on the cart quantity input field.

All the code:

// Displaying quantity setting fields on admin product pages
add_action( 'woocommerce_product_options_pricing', 'wc_qty_add_product_field' );
function wc_qty_add_product_field() {
global $product_object;

$values = $product_object->get_meta('_qty_args');

echo '</div><div class="options_group quantity hide_if_grouped">
<style>div.qty-args.hidden { display:none; }</style>';

woocommerce_wp_checkbox( array( // Checkbox.
'id' => 'qty_args',
'label' => __( 'Quantity settings', 'woocommerce' ),
'value' => empty($values) ? 'no' : 'yes',
'description' => __( 'Enable this to show and enable the additional quantity setting fields.', 'woocommerce' ),
) );

echo '<div class="qty-args hidden">';

woocommerce_wp_text_input( array(
'id' => 'qty_min',
'type' => 'number',
'label' => __( 'Minimum Quantity', 'woocommerce-max-quantity' ),
'placeholder' => '',
'desc_tip' => 'true',
'description' => __( 'Set a minimum allowed quantity limit (a number greater than 0).', 'woocommerce' ),
'custom_attributes' => array( 'step' => 'any', 'min' => '0'),
'value' => isset($values['qty_min']) && $values['qty_min'] > 0 ? (int) $values['qty_min'] : 0,
) );

woocommerce_wp_text_input( array(
'id' => 'qty_max',
'type' => 'number',
'label' => __( 'Maximum Quantity', 'woocommerce-max-quantity' ),
'placeholder' => '',
'desc_tip' => 'true',
'description' => __( 'Set the maximum allowed quantity limit (a number greater than 0). Value "-1" is unlimited', 'woocommerce' ),
'custom_attributes' => array( 'step' => 'any', 'min' => '-1'),
'value' => isset($values['qty_max']) && $values['qty_max'] > 0 ? (int) $values['qty_max'] : -1,
) );

woocommerce_wp_text_input( array(
'id' => 'qty_step',
'type' => 'number',
'label' => __( 'Quantity step', 'woocommerce-quantity-step' ),
'placeholder' => '',
'desc_tip' => 'true',
'description' => __( 'Optional. Set quantity step (a number greater than 0)', 'woocommerce' ),
'custom_attributes' => array( 'step' => 'any', 'min' => '1'),
'value' => isset($values['qty_step']) && $values['qty_step'] > 1 ? (int) $values['qty_step'] : 1,
) );

echo '</div>';
}

// Show/hide setting fields (admin product pages)
add_action( 'admin_footer', 'product_type_selector_filter_callback' );
function product_type_selector_filter_callback() {
global $pagenow, $post_type;

if( in_array($pagenow, array('post-new.php', 'post.php') ) && $post_type === 'product' ) :
?>
<script>
jQuery(function($){
if( $('input#qty_args').is(':checked') && $('div.qty-args').hasClass('hidden') ) {
$('div.qty-args').removeClass('hidden')
}
$('input#qty_args').click(function(){
if( $(this).is(':checked') && $('div.qty-args').hasClass('hidden')) {
$('div.qty-args').removeClass('hidden');
} else if( ! $(this).is(':checked') && ! $('div.qty-args').hasClass('hidden')) {
$('div.qty-args').addClass('hidden');
}
});
});
</script>
<?php
endif;
}

// Save quantity setting fields values
add_action( 'woocommerce_admin_process_product_object', 'wc_save_product_quantity_settings' );
function wc_save_product_quantity_settings( $product ) {
if ( isset($_POST['qty_args']) ) {
$values = $product->get_meta('_qty_args');

$product->update_meta_data( '_qty_args', array(
'qty_min' => isset($_POST['qty_min']) && $_POST['qty_min'] > 0 ? (int) wc_clean($_POST['qty_min']) : 0,
'qty_max' => isset($_POST['qty_max']) && $_POST['qty_max'] > 0 ? (int) wc_clean($_POST['qty_max']) : -1,
'qty_step' => isset($_POST['qty_step']) && $_POST['qty_step'] > 1 ? (int) wc_clean($_POST['qty_step']) : 1,
) );
} else {
$product->update_meta_data( '_qty_args', array() );
}
}

// The quantity settings in action on front end
add_filter( 'woocommerce_quantity_input_args', 'filter_wc_quantity_input_args', 99, 2 );
function filter_wc_quantity_input_args( $args, $product ) {
if ( $product->is_type('variation') ) {
$parent_product = wc_get_product( $product->get_parent_id() );
$values = $parent_product->get_meta( '_qty_args' );
} else {
$values = $product->get_meta( '_qty_args' );
}

if ( ! empty( $values ) ) {
// Min value
if ( isset( $values['qty_min'] ) && $values['qty_min'] > 1 ) {
$args['min_value'] = $values['qty_min'];

if( ! is_cart() ) {
$args['input_value'] = $values['qty_min']; // Starting value
}
}

// Max value
if ( isset( $values['qty_max'] ) && $values['qty_max'] > 0 ) {
$args['max_value'] = $values['qty_max'];

if ( $product->managing_stock() && ! $product->backorders_allowed() ) {
$args['max_value'] = min( $product->get_stock_quantity(), $args['max_value'] );
}
}

// Step value
if ( isset( $values['qty_step'] ) && $values['qty_step'] > 1 ) {
$args['step'] = $values['qty_step'];
}
}
return $args;
}

// Ajax add to cart, set "min quantity" as quantity on shop and archives pages
add_filter( 'woocommerce_loop_add_to_cart_args', 'filter_loop_add_to_cart_quantity_arg', 10, 2 );
function filter_loop_add_to_cart_quantity_arg( $args, $product ) {
$values = $product->get_meta( '_qty_args' );

if ( ! empty( $values ) ) {
// Min value
if ( isset( $values['qty_min'] ) && $values['qty_min'] > 1 ) {
$args['quantity'] = $values['qty_min'];
}
}
return $args;
}

// The quantity settings in action on front end (For variable productsand their variations)
add_filter( 'woocommerce_available_variation', 'filter_wc_available_variation_price_html', 10, 3);
function filter_wc_available_variation_price_html( $data, $product, $variation ) {
$values = $product->get_meta( '_qty_args' );

if ( ! empty( $values ) ) {
if ( isset( $values['qty_min'] ) && $values['qty_min'] > 1 ) {
$data['min_qty'] = $values['qty_min'];
}

if ( isset( $values['qty_max'] ) && $values['qty_max'] > 0 ) {
$data['max_qty'] = $values['qty_max'];

if ( $variation->managing_stock() && ! $variation->backorders_allowed() ) {
$data['max_qty'] = min( $variation->get_stock_quantity(), $data['max_qty'] );
}
}
}

return $data;
}

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

Set minimum, maximum and step quantity programmatically for specific variable products in WooCommerce

The woocommerce_available_variation hook has the WC_Product_Variation product object as its third parameter and not the variable product.

With the woocommerce_available_variation hook you cannot set the
product step
.

The available arguments are the following (source code of the WooCommerce /includes/class-wc-product-variable.php file @version 3.0.0):

return apply_filters(
'woocommerce_available_variation',
array(
'attributes' => $variation->get_variation_attributes(),
'availability_html' => wc_get_stock_html( $variation ),
'backorders_allowed' => $variation->backorders_allowed(),
'dimensions' => $variation->get_dimensions( false ),
'dimensions_html' => wc_format_dimensions( $variation->get_dimensions( false ) ),
'display_price' => wc_get_price_to_display( $variation ),
'display_regular_price' => wc_get_price_to_display( $variation, array( 'price' => $variation->get_regular_price() ) ),
'image' => wc_get_product_attachment_props( $variation->get_image_id() ),
'image_id' => $variation->get_image_id(),
'is_downloadable' => $variation->is_downloadable(),
'is_in_stock' => $variation->is_in_stock(),
'is_purchasable' => $variation->is_purchasable(),
'is_sold_individually' => $variation->is_sold_individually() ? 'yes' : 'no',
'is_virtual' => $variation->is_virtual(),
'max_qty' => 0 < $variation->get_max_purchase_quantity() ? $variation->get_max_purchase_quantity() : '',
'min_qty' => $variation->get_min_purchase_quantity(),
'price_html' => $show_variation_price ? '<span class="price">' . $variation->get_price_html() . '</span>' : '',
'sku' => $variation->get_sku(),
'variation_description' => wc_format_content( $variation->get_description() ),
'variation_id' => $variation->get_id(),
'variation_is_active' => $variation->variation_is_active(),
'variation_is_visible' => $variation->variation_is_visible(),
'weight' => $variation->get_weight(),
'weight_html' => wc_format_weight( $variation->get_weight() ),
),
$this,
$variation
);

To set the step to product variations you will need to use the woocommerce_quantity_input_args hook.

If you want to set the same step to all product variations you can use this hook.

The available arguments are the following (source code of the WooCommerce /includes/wc-template-functions.php file @version 2.5.0):

$defaults = array(
'input_id' => uniqid( 'quantity_' ),
'input_name' => 'quantity',
'input_value' => '1',
'classes' => apply_filters( 'woocommerce_quantity_input_classes', array( 'input-text', 'qty', 'text' ), $product ),
'max_value' => apply_filters( 'woocommerce_quantity_input_max', -1, $product ),
'min_value' => apply_filters( 'woocommerce_quantity_input_min', 0, $product ),
'step' => apply_filters( 'woocommerce_quantity_input_step', 1, $product ),
'pattern' => apply_filters( 'woocommerce_quantity_input_pattern', has_filter( 'woocommerce_stock_amount', 'intval' ) ? '[0-9]*' : '' ),
'inputmode' => apply_filters( 'woocommerce_quantity_input_inputmode', has_filter( 'woocommerce_stock_amount', 'intval' ) ? 'numeric' : '' ),
'product_name' => $product ? $product->get_title() : '',
'placeholder' => apply_filters( 'woocommerce_quantity_input_placeholder', '', $product ),
);

If you want to manage the product step, the minimum quantity and the maximum quantity as a custom meta of the product, see @LoicTheAztec's answer:

  • Set quantity minimum, maximum and step at product level in Woocommerce

ANSWER

To answer your question, if you want all product variations that have the parent variable product id equal to 27525 to have the following values:

  • Min quantity: 1
  • Max quantity: 24
  • Step: 1

You can use the following functions:

It works in the product page, in the cart and in the loop.

// set the min and max quantity for each product variation (based on the variable product id)
add_filter( 'woocommerce_available_variation', 'variation_quantity_input_args', 10, 3 );
function variation_quantity_input_args( $args, $product, $variation ) {
// set variable product ids
$sample_product_id = array( 27525 );
// if the selected variation belongs to one of the variable product ids
// set the min and max quantity
if ( in_array( $variation->get_parent_id(), $sample_product_id ) ) {
$args['min_qty'] = 1;
$args['max_qty'] = 24;
return $args;
}
return $args;
}

// set the step for specific variable products (and for each product variation)
add_filter( 'woocommerce_quantity_input_args', 'set_step_for_specific_variable_products', 10, 2 );
function set_step_for_specific_variable_products( $args, $product ) {
// set variable product ids
$sample_product_id = array( 27525 );

// on the product page
if ( ! is_cart() ) {
// if the id of the variable product is in the array
if ( in_array( $product->get_id(), $sample_product_id ) ) {
$args['input_value'] = 1;
$args['min_value'] = 1;
$args['max_value'] = 24;
$args['step'] = 1;
}
// in the cart
} else {
// if the id of the product variation belongs to a variable product present in the array
if ( in_array( $product->get_parent_id(), $sample_product_id ) ) {
$args['min_value'] = 1;
$args['step'] = 1;
}
}
return $args;
}

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

Woocommerce: Minimum Quantity for Overall Product Category, not variations

Try out this code:

    // Set minimum quantity per product before checking out
add_action( 'woocommerce_check_cart_items', 'rohil_set_min_total' );
function rohil_set_min_total() {
// Only run in the Cart or Checkout pages
if( is_cart() || is_checkout() ) {

global $woocommerce, $product;
$i=0;
//loop through all cart products
foreach ( $woocommerce->cart->cart_contents as $product ) :

// Set minimum product cart total
$minimum_cart_product_total = 12;

// See if any product is from the bagel category or not
if ( has_term( 'bagels', 'product_cat', $product['product_id'] ) ) :

$total_quantity += $product['quantity'];

endif;

endforeach;

if( $total_quantity < $minimum_cart_product_total ) {
// Display our error message
wc_add_notice( sprintf( '<strong>A Minimum of %s products is required from bagel category before checking out.</strong>'
. '<br />Current number of items in the cart: %s.',
$minimum_cart_product_total,
$total_quantity ),
'error' );
}

}

}

EDITED:

    // Set minimum quantity per product before checking out
add_action( 'woocommerce_check_cart_items', 'rohil_set_min_total' );
function rohil_set_min_total() {
// Only run in the Cart or Checkout pages
if( is_cart() || is_checkout() ) {

global $woocommerce, $product;
$i=0;
//loop through all cart products
foreach ( $woocommerce->cart->cart_contents as $product ) :

// Set minimum product cart total
$minimum_cart_product_total = 12;

// See if any product is from the bagel category or not
if ( has_term( 'bagels', 'product_cat', $product['product_id'] ) ) :

$total_quantity += $product['quantity'];

endif;

endforeach;

if ( has_term( 'bagels', 'product_cat', $product['product_id'] ) ) :
if( $total_quantity < $minimum_cart_product_total ) {
// Display our error message
wc_add_notice( sprintf( '<strong>A Minimum of %s products is required from bagel category before checking out.</strong>'
. '<br />Current number of items in the cart: %s.',
$minimum_cart_product_total,
$total_quantity ),
'error' );
}
endif;

}

}

New EDITED

    // Set minimum quantity per product before checking out
add_action( 'woocommerce_check_cart_items', 'rohil_set_min_total' );
function rohil_set_min_total() {
// Only run in the Cart or Checkout pages
if( is_cart() || is_checkout() ) {

global $woocommerce, $product;
$i=0;
//$prod_id_array = array();
//loop through all cart products
foreach ( $woocommerce->cart->cart_contents as $product ) :

// Set minimum product cart total
$minimum_cart_product_total = 12;

// See if any product is from the bagel category or not
if ( has_term( 'bagels', 'product_cat', $product['product_id'] ) ) :

$total_quantity += $product['quantity'];
//array_push($prod_id_array, $product['product_id']);
endif;

endforeach;

foreach ( $woocommerce->cart->cart_contents as $product ) :
if ( has_term( 'bagels', 'product_cat', $product['product_id'] ) ) :
if( $total_quantity < $minimum_cart_product_total && $i == 0 ) {
// Display our error message
wc_add_notice( sprintf( '<strong>A Minimum of %s products is required from bagel category before checking out.</strong>'
. '<br />Current number of items in the cart: %s.',
$minimum_cart_product_total,
$total_quantity ),
'error' );
}
$i++;
endif;
endforeach;
}

}

Decimal quantity step for specific product categories in WooCommerce

To make it work for specific product categories for decimal quantity step you don't need settings at product level… In following code you will have to set on the first function your product categories (can be terms ids, slugs or names):

// custom conditional function (check for product categories)
function enabled_decimal_quantities( $product ){
$targeted_terms = array(12, 16); // Here define your product category terms (names, slugs ord Ids)

return has_term( $targeted_terms, 'product_cat', $product->get_id() );
}

// Defined quantity arguments
add_filter( 'woocommerce_quantity_input_args', 'custom_quantity_input_args', 9000, 2 );
function custom_quantity_input_args( $args, $product ) {
if( enabled_decimal_quantities( $product ) ) {
if( ! is_cart() ) {
$args['input_value'] = 0.5; // Starting value
}
$args['min_value'] = 0.5; // Minimum value
$args['step'] = 0.5; // Quantity steps
}
return $args;
}

// For Ajax add to cart button (define the min value)
add_filter( 'woocommerce_loop_add_to_cart_args', 'custom_loop_add_to_cart_quantity_arg', 10, 2 );
function custom_loop_add_to_cart_quantity_arg( $args, $product ) {
if( enabled_decimal_quantities( $product ) ) {
$args['quantity'] = 0.5; // Min value
}
return $args;
}

// For product variations (define the min value)
add_filter( 'woocommerce_available_variation', 'filter_wc_available_variation_price_html', 10, 3);
function filter_wc_available_variation_price_html( $data, $product, $variation ) {
if( enabled_decimal_quantities( $product ) ) {
$data['min_qty'] = 0.5;
}
return $data;
}

// Enable decimal quantities for stock (in frontend and backend)
remove_filter('woocommerce_stock_amount', 'intval');
add_filter('woocommerce_stock_amount', 'floatval');

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

Set custom quantity arguments to products from specific category in WooCommerce

Try the following instead (that will not requires any check):

// General quantity settings
add_filter( 'woocommerce_quantity_input_args', 'custom_quantity_input_args', 10, 2 );
function custom_quantity_input_args( $args, $product ){
if ( has_term( array('nettoyage'), 'product_cat', $product->get_id() ) ) {
if( ! is_cart() ) {
$args['input_value'] = 3; // Starting value
}
$args['min_value'] = 3; // Minimum value
$args['max_value'] = 10; // Maximum value
}
return $args;
}

// For Ajax add to cart button (define the min value)
add_filter( 'woocommerce_loop_add_to_cart_args', 'custom_loop_add_to_cart_quantity_arg', 10, 2 );
function custom_loop_add_to_cart_quantity_arg( $args, $product ) {
if ( has_term( array('nettoyage'), 'product_cat', $product->get_id() ) ) {
$args['quantity'] = 3; // Min value
}
return $args;
}

// For product variations (define the min value)
add_filter( 'woocommerce_available_variation', 'custom_available_variation_min_qty', 10, 3);
function custom_available_variation_min_qty( $data, $product, $variation ) {
if ( has_term( array('nettoyage'), 'product_cat', $product->get_id() ) ) {
$args['min_qty'] = 3; // Min value
}

return $data;
}

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

Note: The category "nettoyage" need to be set up for each desired product. If not it will not work.

How to change minimum quantity in administration panel of order

I have found a solution, the issue was the step from the order in administration view was 1 instead of 0.1.

The solution:

add_filter( 'woocommerce_quantity_input_step', 'filter_woocommerce_quantity_input_step', 10, 2 );
function filter_woocommerce_quantity_input_step($arg, $product) {
$arg = 0.1;
return $arg;
};

Restrict total cart quantity to specific multiples in WooCommerce

As 12 is already a multiple of 4 or 6, you need only to check for items multiples of 4 or 6 using the following code (commented):

add_action( 'woocommerce_check_cart_items', 'check_cart_items_quantities_conditionally' );
function check_cart_items_quantities_conditionally() {
$multiples = array(4, 6); // Your defined multiples in an array
$items_count = WC()->cart->get_cart_contents_count(); // Get total items cumulated quantity
$is_multiple = false; // initializing

// Loop through defined multiples
foreach ( $multiples as $multiple ) {
if ( ( $items_count % $multiple ) == 0 ) {
$is_multiple = true; // When a multiple is found, flag it as true
break; // Stop the loop
}
}

// If total items cumulated quantity doesn't match with any multiple
if ( ! $is_multiple ) {
// Display a notice avoiding checkout
wc_add_notice( sprintf( __('You need to buy in quantities of %s products', 'woocommerce'), implode(' or ', $multiples) ), 'error' );
}
}


Related Topics



Leave a reply



Submit