Search code examples
phpwordpresswoocommercecheckoutcoupon

Prevent WooCommerce coupon stacking on cart and checkout page


I need to prevent two specific coupons from being used together. I successfully implemented this code, which prevents stacking these coupons on the cart page:

add_action( 'woocommerce_before_cart', 'check_coupon_stack' );
function check_coupon_stack() {
    $coupon_code_1 = 'mycode1';
    $coupon_code_2 = 'mycode2';
    if ( WC()->cart->has_discount( $coupon_code1 ) && WC()->cart->has_discount( $coupon_code2) ) {
        WC()->cart->remove_coupon( $coupon_code2 );
        $notice_text = 'Discount code '.$coupon_code1.' cannot be combined with code '.$coupon_code2.'. Code '.$coupon_code2.' removed.';
        wc_print_notice( $notice_text, 'error' );
        wc_clear_notices();
    }
}

However, this does not prevent stacking on the checkout page, which follows the cart page.

I have tried simply adding:

add_action( 'woocommerce_before_checkout_form', 'check_coupon_stack' );

But that doesn't make this work on the checkout page. What more is needed?


Solution

  • WooCommerce contains multiple hooks that apply to coupons, woocommerce_applied_coupon is one of them, which is very suitable for your question.

    Furthermore, your current code only works in one direction, which is when $coupon_code_1 is used, $coupon_code_2 is removed. However, this is not applied in the reverse direction while you indicate in your question that you want to prevent two specific coupons from being used together.

    This is taken into account in my answer, so you get:

    function action_woocommerce_applied_coupon( $coupon_code ) {
        // Settings
        $coupon_code_1 = 'coupon1';
        $coupon_code_2 = 'coupon2';
    
        // Initialize
        $combined = array( $coupon_code_1, $coupon_code_2 );
    
        // Checks if coupon code exists in an array
        if ( in_array( $coupon_code, $combined ) ) {
            // Get applied coupons
            $applied_coupons = WC()->cart->get_applied_coupons();
    
            // Computes the difference of arrays
            $difference = array_diff( $combined, $applied_coupons );
    
            // When empty
            if ( empty( $difference ) ) {
                // Shorthand if/else - Get correct coupon to remove
                $remove_coupon = $coupon_code == $coupon_code_1 ? $remove_coupon = $coupon_code_2 : $remove_coupon = $coupon_code_1;
    
                // Remove coupon
                WC()->cart->remove_coupon( $remove_coupon );
    
                // Clear Notices
                wc_clear_notices();
    
                // Error message
                $error = sprintf( __( 'Discount code "%1$s" cannot be combined with code "%2$s". Code "%2$s" removed.', 'woocommerce' ), $coupon_code, $remove_coupon );
    
                // Show error
                wc_print_notice( $error, 'error' );
            }
        }
    }
    add_action( 'woocommerce_applied_coupon', 'action_woocommerce_applied_coupon', 10, 1 );