Search code examples
phpwordpresswoocommercecartshipping-method

Minimum order amount depending on postcode and shipping method on WooCommerce


How can I set a minimum order amount only for Delivery/Shipments (but not for local pickup) and depending on specific post codes?

Use Case: A Restaurant delivers in the local village without minimum amount. But the neighbor villages should have an order amount. Pickup is always without any minimum amount.

Based on Minimum order amount except for specific shipping method in WooCommerce answer code, this is my attempt:

add_action( 'woocommerce_check_cart_items', 'wc_minimum_required_order_amount' );
function wc_minimum_required_order_amount() {

// HERE Your settings
$minimum_amount     = 50; // The minimum cart total amount
$shipping_method_id = 'local_pickup'; // The targeted shipping method Id (exception)
$postcodes = array('82065', '82057', '82067'); // Define your targeted postcodes in the array
$postcode  = '82069'; // Initializing

// Get some variables
$cart_total     = (float) WC()->cart->total; // Total cart amount
$chosen_methods = (array) WC()->session->get( 'chosen_shipping_methods' ); // Chosen shipping method rate Ids (array)

// Only when a shipping method has been chosen
if ( ! empty($chosen_methods) ) {
    $chosen_method  = explode(':', reset($chosen_methods)); // Get the chosen shipping method Id (array)
    $chosen_method_id = reset($chosen_method); // Get the chosen shipping method Id
}

// If "Local pickup" shipping method is chosen, exit (no minimun is required)
if ( isset($chosen_method_id) && $chosen_method_id === $shipping_method_id ) {
    return; // exit
}

if ( isset($_POST['shipping_postcode']) && ! empty($_POST['shipping_postcode']) ) {
    $postcode = $_POST['shipping_postcode'];
    if ( empty($postcode) && isset($_POST['billing_postcode']) && ! empty($_POST['billing_postcode']) ) {
        $postcode = $_POST['billing_postcode'];
    }
} elseif ( $postcode = WC()->customer->get_shipping_postcode() ) {
    if ( empty($postcode) ) {
        $postcode = WC()->customer->get_billing_postcode();
    }
}

// Add an error notice is cart total is less than the minimum required
if ( $cart_total < $minimum_amount && ! empty($postcode) && in_array( $postcode, $postcodes ) ) {
    wc_add_notice( sprintf(
        __("The minimum required order amount is %s (your current order amount is %s).", "woocommerce"), // Text message
        wc_price( $minimum_amount ),
        wc_price( $cart_total )
    ), 'error' );
}
}

Solution

  • You are close with your solution, what is missing, however, is the use of in_array(), with which you can check the postcode

    So you get:

    function action_woocommerce_check_cart_items() {
        // HERE Your settings
        $minimum_amount = 50; // The minimum cart total amount
        $shipping_method_id = 'local_pickup'; // The targeted shipping method Id (exception)
        $postcodes = array( 82065, 82057, 82067, 9800 ); // Define your targeted postcodes in the array
    
        // Get some variables
        $cart_total     = (float) WC()->cart->total; // Total cart amount
        $chosen_methods = (array) WC()->session->get( 'chosen_shipping_methods' ); // Chosen shipping method rate Ids (array)
        
        // Initialize
        $postcode = '';
    
        // Only when a shipping method has been chosen
        if ( ! empty($chosen_methods) ) {
            $chosen_method  = explode( ':', reset( $chosen_methods ) ); // Get the chosen shipping method Id (array)
            $chosen_method_id = reset( $chosen_method ); // Get the chosen shipping method Id
        }
    
        // If "Local pickup" shipping method is chosen, exit (no minimun is required)
        if ( isset($chosen_method_id) && $chosen_method_id === $shipping_method_id ) {
            return; // exit
        }
        
        // Get shipping postode
        $postcode = WC()->customer->get_shipping_postcode();
        
        // When empty
        if ( empty ( $postcode ) ) {
            if ( isset( $_POST['shipping_postcode'] ) ) {
                $postcode = $_POST['shipping_postcode'];
            } else {
                if ( isset( $_POST['billing_postcode'] ) ) {
                    $postcode = $_POST['billing_postcode'];
                } else {
                    $postcode = WC()->customer->get_billing_postcode();
                }
            }
        }
        
        // Still empty, exit
        if ( empty ( $postcode ) ) return;
    
        // Add an error notice is cart total is less than the minimum required and postcode occurs in the array
        if ( $cart_total < $minimum_amount && in_array( $postcode, $postcodes ) ) {
            // Your error message
            wc_add_notice( sprintf(
                __( 'The minimum required order amount is %s (your current order amount is %s).', 'woocommerce' ), // Text message
                wc_price( $minimum_amount ),
                wc_price( $cart_total )
            ), '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 );