Search code examples
phpwordpresswoocommercecoupondiscount

Auto apply coupons based on Woocommerce cart subtotal thresholds


Trying to apply a coupon automatically to WooCommerce checkout. Have tried a number of snippets, but can't seem to get it to work.

It either throws critical errors, or does not apply the coupon reliably.

I've created the following coupons in WooCommerce:

  • black10: If customer spends > £100 && < £199.99, 10% off cart
  • black20: If customer spends > £200, 20% off cart

This is my related code:

add_action( 'woocommerce_checkout_before_order_review' , 'add_coupon_notice' );
function add_coupon_notice() { 
    $cart_total = WC()->cart->get_subtotal();

    $currency_code = get_woocommerce_currency();
    wc_clear_notices();

    if ( $cart_total > 200 ) {
        WC()->cart->remove_coupon( 'black10' );
        WC()->cart->apply_coupon( 'black20' );
        wc_print_notice( '20% off £200 or more - Discount Applied!', 'notice' );
    } elseif ( $cart_total > 100 ) { 
        WC()->cart->remove_coupon( 'black20' );
        WC()->cart->apply_coupon( 'black10' );
        wc_print_notice( '10% off £100 or more - Discount Applied!', 'notice' );
    }
    

    wc_clear_notices();
}

But it doesn't work reliably.


Solution

  • You can use the following replacement code, that will apply/remove coupons reliably, based on defined cart items subtotal including taxes thresholds amount, displaying a custom notice:

    add_action( 'woocommerce_before_calculate_totals' , 'discount_based_on_cart_items_subtotal' );
    function discount_based_on_cart_items_subtotal( $cart ) { 
        if ( is_admin() && !defined('DOING_AJAX') )
            return;
        
        $subtotal = 0; // Initializing
    
        // Loop through cart items to get the subtotal excluding taxes
        foreach ( $cart->get_cart() as $item ) {
            $subtotal += $item['line_subtotal'] + $item['line_subtotal_tax'];
        }
        
        if ( $subtotal >= 100 && $subtotal < 200 ) { 
            if ( ! $cart->has_discount('black10') ) {
                $cart->apply_coupon( 'black10' );
                $notice = __('10% OFF for '.wc_price(100).' or more - Discount Applied!');
            }
            if ( $cart->has_discount('black20') ) {
                $cart->remove_coupon( 'black20' );
            }
        } elseif ( $subtotal >= 200 ) {
            if ( ! $cart->has_discount('black20') ) {
                $cart->apply_coupon( 'black20' );
                $notice = __('20% OFF for '.wc_price(200).' or more - Discount Applied!');
            }
            if ( $cart->has_discount('black10') ) {
                $cart->remove_coupon( 'black10' );
            }
        } else {
            if ( $cart->has_discount('black20') ) {
                $cart->remove_coupon( 'black20' );
            }
            if ( $cart->has_discount('black10') ) {
                $cart->remove_coupon( 'black10' );
            }
            wc_clear_notices();
        }
        
        if ( isset($notice) ) {
            wc_clear_notices();
            wc_add_notice( $notice, 'notice' );
        }
    }
    

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


    For Subtotal excluding taxes, replace:

    $subtotal += $item['line_subtotal'] + $item['line_subtotal_tax'];
    

    with:

    $subtotal += $item['line_subtotal'];
    

    Note:

    Does not set a minimal amount in the coupon settings, as the code is handle that.