Search code examples
phpwordpresswoocommercecartproduct-variations

Auto add to cart a Gift product variation programmatically in WooCommerce?


I'm trying to create a buy one get one offer for woocommerce when someone adds a product to the cart. The code below works but only with simple products, I've tried adding the variation ID to the variable but it does not work. Any ideas? thanks to the community

add_action( 'template_redirect', 'bbloomer_add_gift_if_id_in_cart' );
 
function bbloomer_add_gift_if_id_in_cart() {
 
   if ( is_admin() ) return;
   if ( WC()->cart->is_empty() ) return;
 
   $product_bought_id = 421;
   $product_gifted_id = 1256;
 
   // see if product id in cart
   $product_bought_cart_id = WC()->cart->generate_cart_id( $product_bought_id );
   $product_bought_in_cart = WC()->cart->find_product_in_cart( $product_bought_cart_id );
 
   // see if gift id in cart
   $product_gifted_cart_id = WC()->cart->generate_cart_id( $product_gifted_id );
   $product_gifted_in_cart = WC()->cart->find_product_in_cart( $product_gifted_cart_id );
 
   // if not in cart remove gift, else add gift
   if ( ! $product_bought_in_cart ) {
      if ( $product_gifted_in_cart ) WC()->cart->remove_cart_item( $product_gifted_in_cart );
   } else {
      if ( ! $product_gifted_in_cart ) WC()->cart->add_to_cart( $product_gifted_id );
   }
}

Solution

  • To add a product variation to cart you need the parent variable product id and the product variation Id (both).

    Now the code that you are using is obsolete and will not work if customer update cart in cart page, removing the required product id. In this case, the Gift product will be removed after reloading the page or jumping to another page. So template_redirect is not the right hook to be used.

    Try the following instead, that handle simple products and product variations too:

    add_action( 'woocommerce_before_calculate_totals', 'wc_auto_add_gift_to_cart' );
    function wc_auto_add_gift_to_cart( $cart ) {
        if (is_admin() && !defined('DOING_AJAX'))
            return;
        
        $required_product_id = 37; // The required product Id (or variation Id)
        $parent_gift_id      = 40; // The parent variable product Id (gift) for a product variation (set to zero for simple products)
        $product_gift_id     = 41; // the variation Id or the product Id (gift)
        
        $has_required = $gift_key = false; // Initializing
        
        foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
            // Check if required product is in cart
            if( in_array( $required_product_id, array($cart_item['product_id'], $cart_item['variation_id']) ) ) {
               $has_required = true;
            }
            // Check if gifted product is already in cart
            if( $cart_item['data']->get_id() == $product_gift_id ) {
               $gift_key = $cart_item_key;
            }
        }
        
        // If gift is in cart, but not the required product: Remove gift from cart
        if ( ! $has_required && $gift_key ) {
            $cart->remove_cart_item( $gift_key );
        }
        // If gift is not in cart and the required product is in cart: Add gift to cart
        elseif ( $has_required && ! $gift_key ) {
            // For simple products
            if( $parent_gift_id == 0 ) {
                $cart->add_to_cart( $product_gift_id );
            } 
            // For product variations (of a variable product)
            else {
                $cart->add_to_cart( $parent_gift_id, 1, $product_gift_id );
            }
        }
    }
    

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