Search code examples
wordpresswoocommerceproducthook-woocommercecoupon

Add free product when a certain coupon is applied in WooCommerce


I can add a product to cart, when a certain coupon is used via the woocommerce_applied_coupon hook and the add_to_cart() function

add_action('woocommerce_applied_coupon', 'apply_product_on_coupon');
function apply_product_on_coupon( ) {
    global $woocommerce;
    $coupon_id = 'mybday';
    $free_product_id = 131468;

    if(in_array($coupon_id, $woocommerce->cart->get_applied_coupons())){
        $woocommerce->cart->add_to_cart($free_product_id, 1);
    }
}

My question: is there a way to also discount it to 0 in the same callback function?


Solution

  • Your current code contains some mistakes or could be optimized:

    • global $woocommerce can be replaced by WC()
    • $woocommerce->cart->get_applied_coupons() is not necessary, as the coupon that have been applied is passed to the callback function.

    Instead, use the last available argument in WC_Cart::add_to_cart() method, which will allow you to add any custom cart item data. Then you will be able to get that data easily from the cart object.

    So you get:

    function action_woocommerce_applied_coupon( $coupon_code ) {
        // Settings
        $product_id = 131468;
        $quantity = 1;
        $free_price = 0;
        $coupon_codes = array( 'coupon1', 'mybday' );
    
        // Compare
        if ( in_array( $coupon_code, $coupon_codes ) ) {
            // Add product to cart
            WC()->cart->add_to_cart( $product_id, $quantity, 0, array(), array( 'free_price' => $free_price ) );
        }
    }
    add_action( 'woocommerce_applied_coupon', 'action_woocommerce_applied_coupon', 10, 1 );
    
    // Set free price from custom cart item data
    function action_woocommerce_before_calculate_totals( $cart ) {
        if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return;
    
        if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 ) return;
    
        // Loop through cart contents
        foreach ( $cart->get_cart_contents() as $cart_item ) {       
            if ( isset( $cart_item['free_price'] ) ) {
                $cart_item['data']->set_price( $cart_item['free_price'] );
            }
        }
    }
    add_action( 'woocommerce_before_calculate_totals', 'action_woocommerce_before_calculate_totals', 10, 1 );
    

    Note: in addition to using woocommerce_applied_coupon, you must also use woocommerce_removed_coupon for when the coupon is removed, the product is removed as well

    function action_woocommerce_removed_coupon( $coupon_code ) {
        // Settings
        $product_id = 131468;
        $coupon_codes = array( 'coupon1', 'mybday' );
    
        // Compare
        if ( in_array( $coupon_code, $coupon_codes ) ) {
            // Loop through cart contents
            foreach ( WC()->cart->get_cart_contents() as $cart_item_key => $cart_item ) {
                // When product in cart
                if ( $cart_item['product_id'] == $product_id ) {
                    // Remove cart item
                    WC()->cart->remove_cart_item( $cart_item_key );
                    break;
                }
            }
        }
    }
    add_action( 'woocommerce_removed_coupon', 'action_woocommerce_removed_coupon', 10, 1 );