Woocommerce: add free product if cart has 3 items

What I’m trying to do is to add free product if user have 3 product in cart.
I choosed woocommerce_add_cart_item hook for this.
Here is my code :

add_filter('woocommerce_add_cart_item', 'set_item_as_free', 99, 1);

function set_item_as_free($cart_item) {

    global $woocommerce;
    $products_with_price = 0;

    foreach ( $woocommerce->cart->get_cart() as $cart_item_key => $values ) {
        if($values['data']->price == 0) {
            continue; 
        } else {
            $products_with_price++;
        }
    }

    if( $products_with_price > 1 && $products_with_price % 3 == 1) {
        $cart_item['data']->set_price(0);
        return $cart_item;
    }
    return $cart_item;

}

I also tried $cart_item['data']->price = 0; but it doesn’t work out either 🙁
Is there is something I do wrong or maybe there is some other way to get this done?
Thanks.

Related posts

Leave a Reply

2 comments

  1. Try this modified code: (Have changed the condition.)

    add_filter('woocommerce_add_cart_item', 'set_item_as_free', 99, 1);
    
    function set_item_as_free($cart_item) {
    
        global $woocommerce;
        $products_with_price = 0;
    
        foreach ( $woocommerce->cart->get_cart() as $cart_item_key => $values ) {
            if($values['data']->price == 0) {
                continue; 
            } else {
                $products_with_price++;
            }
        }
    
        if( $products_with_price >= 3 && $products_with_price % 3 == 1) {
            $cart_item['data']->set_price(0);
            return $cart_item;
        }
        return $cart_item;
    
    }
    

    If you don’t want to add a free product again after a user purchases another 3 products above the existing cart then remove ” && $products_with_price % 3 == 1” from the last condition.

  2. Do not use the woocommerce_add_cart_item hook to set the price of the product, a lot of plugin like to refetch the price of the product in the database in the hook woocommerce_before_calculate_totals (that’s the case of WPML/WCML)

    So instead use this hook

    add_action( 'woocommerce_before_calculate_totals', function ( $cart_obj ) {
    
        // This is necessary for WC 3.0+
        if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
            return;
        }
    
        // Avoiding hook repetition (when using price calculations for example)
        if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 ) {
            return;
        }
    
    
        // Loop through cart items
        foreach ( $cart_obj->get_cart() as $cart_item ) {
            if ( isset( $cart_item['free_item'] ) ) {
                $cart_item['data']->set_price( 0 );
            }
        }
    } );