i am trying to achive the following in WooCommerce. I want to set minimum order quantity for specific product.
The problem is that this product for example is a variable product, and i want to set a minimum quantity of 12 pcs but this minimum i want to be on entire product not on every variation.
For example:
The code I have so far works for simple products, but it counts variations as different products.
How can I adjust this so that variants quantities in the cart are counted as 1 product?
// Set minimum quantity per product before checking out
add_action( 'woocommerce_check_cart_items', 'spyr_set_min_qty_per_product' );
function spyr_set_min_qty_per_product() {
// Only run in the Cart or Checkout pages
if( is_cart() || is_checkout() ) {
global $woocommerce;
// Product Id and Min. Quantities per Product
$product_min_qty = array(
array( 'id' => 9059, 'min' => 12 ),
);
// Will increment
$i = 0;
// Will hold information about products that have not
// met the minimum order quantity
$bad_products = array();
// Loop through the products in the Cart
foreach( $woocommerce->cart->cart_contents as $product_in_cart ) {
// Loop through our minimum order quantities per product
foreach( $product_min_qty as $product_to_test ) {
// If we can match the product ID to the ID set on the minimum required array
if( $product_to_test['id'] == $product_in_cart['product_id'] ) {
// If the quantity required is less than than the quantity in the cart now
if( $product_in_cart['quantity'] < $product_to_test['min'] ) {
// Get the product ID
$bad_products[$i]['id'] = $product_in_cart['product_id'];
// Get the Product quantity already in the cart for this product
$bad_products[$i]['in_cart'] = $product_in_cart['quantity'];
// Get the minimum required for this product
$bad_products[$i]['min_req'] = $product_to_test['min'];
}
}
}
// Increment $i
$i++;
}
// Time to build our error message to inform the customer
// About the minimum quantity per order.
if( is_array( $bad_products) && count( $bad_products ) > 0 ) {
// Lets begin building our message
$message = '<strong>A minimum quantity per product has not been met.</strong><br />';
foreach( $bad_products as $bad_product ) {
// Append to the current message
$message .= get_the_title( $bad_product['id'] ) .' requires a minimum quantity of '
. $bad_product['min_req']
.'. You currently have: '. $bad_product['in_cart'] .'.<br />';
}
wc_add_notice( $message, 'error' );
}
}
}
To keep it dynamic you can use the following code to add a custom field to the inventory tab in the product data meta box (simple & variable products).
This way you don't have to hardcode the product IDs
// Add custom field to the inventory tab in the product data meta box
function action_woocommerce_product_options_stock_status() {
woocommerce_wp_text_input(
array(
'id' => '_min_qty',
'placeholder' => __( 'My placeholder', 'woocommerce' ),
'label' => __( 'My label', 'woocommerce' ),
'desc_tip' => true,
'description' => __( 'My description', 'woocommerce' ),
'type' => 'number',
'custom_attributes' => array(
'step' => 'any',
),
)
);
}
add_action( 'woocommerce_product_options_stock_status', 'action_woocommerce_product_options_stock_status', 10, 0 );
// Save custom field
function action_woocommerce_admin_process_product_object( $product ) {
// Isset
if ( isset( $_POST['_min_qty'] ) ) {
// Update
$product->update_meta_data( '_min_qty', sanitize_text_field( $_POST['_min_qty'] ) );
}
}
add_action( 'woocommerce_admin_process_product_object', 'action_woocommerce_admin_process_product_object', 10, 1 );
To set a minimum quantity, you can use the following code, which works for both simple products and products with variants
function get_cart_quantity_variable_product( $child_ids ) {
// Get cart items quantities
$cart_item_quantities = WC()->cart->get_cart_item_quantities();
// Counter
$qty = 0;
// Loop through the childIDs
foreach ( $child_ids as $child_id ) {
// Checks if the given key or index exists in the array
if ( array_key_exists( $child_id, $cart_item_quantities ) ) {
// Addition
$qty += $cart_item_quantities[$child_id];
}
}
return $qty;
}
function action_woocommerce_check_cart_items() {
// Will increment
$i = 0;
// Will hold information about products that have not met the minimum order quantity
$bad_products = array();
// Will hold information about which product ID has already been checked so that this does not happen twice (especially applies to products with variants)
$already_checked = array();
// Loop through cart items
foreach( WC()->cart->get_cart() as $cart_item ) {
// Get IDs
$product_id = $cart_item['product_id'];
$variation_id = $cart_item['variation_id'];
// NOT in array, already checked? Continue
if ( ! in_array( $product_id, $already_checked ) ) {
// Push to array
$already_checked[] = $product_id;
// Get the parent variable product for product variation items
$product = $variation_id > 0 ? wc_get_product( $product_id ) : $cart_item['data'];
// Get meta
$min_qty = $product->get_meta( '_min_qty', true );
// NOT empty & minimum quantity is greater than or equal to 2 (1 never needs to be checked)
if ( ! empty( $min_qty ) && $min_qty >= 2 ) {
// Get current quantity in cart
$cart_qty = $cart_item['quantity'];
// Product type = variable & cart quantity is less than the minimum quantity
if ( $product->get_type() == 'variable' && ( $cart_qty < $min_qty ) ) {
// Get childIDs in an array
$child_ids = $product->get_children();
// Call function, get total quantity in cart for a variable product
$cart_qty = get_cart_quantity_variable_product( $child_ids );
}
// Cart quantity is less than the minimum quantity
if ( $cart_qty < $min_qty ) {
// The product ID
$bad_products[$i]['product_id'] = $product_id;
// The variation ID (optional)
//$bad_products[$i]['variation_id'] = $variation_id;
// The Product quantity already in the cart for this product
$bad_products[$i]['in_cart'] = $cart_qty;
// Get the minimum required for this product
$bad_products[$i]['min_req'] = $min_qty;
// Increment $i
$i++;
}
}
}
}
// Time to build our error message to inform the customer, about the minimum quantity per order.
if ( is_array( $bad_products) && count( $bad_products ) > 0 ) {
// Clear all other notices
wc_clear_notices();
foreach( $bad_products as $bad_product ) {
// Displaying an error notice
wc_add_notice( sprintf(
__( '%s requires a minimum quantity of %d. You currently have %d in cart', 'woocommerce' ),
get_the_title( $bad_product['product_id'] ),
$bad_product['min_req'],
$bad_product['in_cart'],
), 'error' );
}
// Optional: remove proceed to checkout button
remove_action( 'woocommerce_proceed_to_checkout', 'woocommerce_button_proceed_to_checkout', 20 );
}
}
add_action( 'woocommerce_check_cart_items' , 'action_woocommerce_check_cart_items', 10, 0 );