4

I'm trying to create code that automatically adds an item to the customer's cart once they reach a particular price point in the cart. AND I'm trying to exclude that from happening if they are only ordering virtual products, as the "free gift" is only meant for products that are being shipped out. The code I'm using is adding the free gift at the right dollar amount, but it's not excluding any virtual product. Can anyone id what I'm doing wrong?

Here's the code:

/**
 * Add another product depending on the cart total
 */

add_action( 'template_redirect', 'add_product_to_cart' );
function add_product_to_cart() {
  if ( ! is_admin() ) {
        global $woocommerce;
        $product_id = 85942; //replace with your product id
        $found = false;
        $cart_total = 15; //replace with your cart total needed to add above item

        if( $woocommerce->cart->total >= $cart_total ) {
            //check if product already in cart
            if ( sizeof( $woocommerce->cart->get_cart() ) > 0 ) {

                $isVirtualOnly = false;
                foreach ( $woocommerce->cart->get_cart() as $cart_item_key => $values) {
                    $_product = $values[‘data’];
                    if ($_product != null)
                        if ($_product->get_type() != $_virtual)
                                $isVirtualOnly = false;
                }

                if ($isVirtualOnly != true) {
                    foreach ( $woocommerce->cart->get_cart() as $cart_item_key => $values ) {
                        $_product = $values['data'];
                        if ( $_product->get_id() == $product_id )
                            $found = true;
                    }
                    // if product not found, add it
                    if ( ! $found )
                        $woocommerce->cart->add_to_cart( $product_id );
                }
            } else {
                    // if no products in cart, add it
                    $woocommerce->cart->add_to_cart( $product_id );
            }
        }
    }
}

/**
 * END Add another product depending on the cart total
 */
LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399
BrettBrooks
  • 43
  • 1
  • 4

1 Answers1

6

Updated: The following will auto add to cart a free product:

  • if there is at least a shippable item in cart,
  • if the free product is not in cart yet,
  • and if the cart subtotal is not below a specific amount.

Or will remove the fee product from cart:

  • if the cart subtotal is not below a specific amount,
  • and if there is only virtual products.

The code:

add_action( 'woocommerce_before_calculate_totals', 'add_free_product_to_cart' );
function add_free_product_to_cart( $cart ) {
    if ( is_admin() && ! defined( 'DOING_AJAX' ) )
        return;

    $free_product_id = 38; // <= Set the free product id to add
    $min_subtotal    = 80; // <= Set the minimum cart subtotal required

    $has_shippable   = $free_key = false; // Initializing
    $cart_subtotal   = 0;

    // Loop through cart items (first loop)
    foreach ( $cart->get_cart() as $cart_item_key => $cart_item ){
        // Check if free product is in cart
        if ( $free_product_id == $cart_item['product_id'] ) {
            $free_key = $cart_item_key;
            $free_qty = $cart_item['quantity'];
            $cart_item['data']->set_price(0); // Optional: Set free product price to zero
        }

        // Check for non virtual products
        if ( $cart_item['data']->is_virtual() !== true ) {
            $has_shippable = true;
        }
        // Calculate items subtotal: Add discounted Line total with taxes
        $cart_subtotal += $cart_item['line_total'] + $cart_item['line_tax'];
    }

    // Add Free product
    if ( $cart_subtotal >= $min_subtotal && $has_shippable && $free_key === false ) {
        $cart->add_to_cart( $free_product_id, 1 );
    }
    // Remove free product
    elseif ( ( $cart_subtotal < $min_subtotal  ) && $free_key !== false ) {
        $cart->remove_cart_item( $free_key );
    }
    // Adjust free product quantity to 1
    elseif ( $free_key !== false && $free_qty > 1 ) {
        $cart->set_quantity( $free_key, 1 );
    }
}

// Optional: Display free product price to zero on minicart
add_filter( 'woocommerce_cart_item_price', 'change_minicart_free_gifted_item_price', 10, 3 );
function change_minicart_free_gifted_item_price( $price_html, $cart_item, $cart_item_key ) {
    $free_product_id   = 38;

    if( $cart_item['product_id'] == $free_product_id ) {
        return wc_price( 0 );
    }
    return $price_html;
}

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

Related:

LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399
  • Thanks for the answer. Unfortunately, when I add it I'm getting the following error on the page: ParseError thrown syntax error, unexpected '->' (T_OBJECT_OPERATOR), expecting identifier (T_STRING) or variable (T_VARIABLE) or '{' or '$' Any suggestions? – BrettBrooks Feb 05 '21 at 21:23
  • That works perfectly! Thank you so much! :D – BrettBrooks Feb 24 '21 at 23:56
  • On ajax requests `line_total` and `line_tax` contain the values of the last request, not the current, however the `quantity` is correct. I replaced the line with `$cart_subtotal += $cart_item['quantity'] * wc_get_price_including_tax( $cart_item['data'] );` and now this works like charm. – Martin Braun Nov 24 '21 at 22:06
  • @LoicTheAztec Hi, The code works fine. But if a user wants to purchase only the product which is being given free, the user can not purchase it individually. When the user clicks on add to cart button, the product does not show in the cart. –  Feb 01 '22 at 11:33
  • @user6391799 and anyone else here looking for this solution --- it works best if you create the free product as it's own product rather than trying to use an existing product. Then you can set it as hidden and only available individually. – MsMaryMak Feb 24 '23 at 21:04