3
votes

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:

  • if a customer add to cart 2 pcs of this product choosing a variation of XL Black, there should be a notice that the minimum quantity is 12 pcs.
  • When this customer add 10 pcs of a variation of the same product of L Red then he has fulfil the minimum order requirement and he should be able to place his order.

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' );
        }
    }
}
1

1 Answers

3
votes

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 );

custom_field


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 );

error