Ad

Issue With Buy One, Discount Another Product In WooCommerce Cart

So I have almost achieved my goal - to create a new discounted price on a specific product, should another specific product be in the customer's cart.

I am using ACF to select the core product and the discounted one, which is all being pulled fine. The issue lies in the order in which the products are added to the cart.

If I add the discounted product BEFORE the core product, the discounted product correctly adjusts to $9.99 (the ACF determined new price). However, if I add the core product first, and THEN add the product that should be discounted, the price remains the same - with no discount applied.

I used this code for reference: https://stackoverflow.com/a/47500323/16291715

My code:

add_action( 'woocommerce_before_calculate_totals', 'boga_discount', 20, 1 );
function boga_discount( $cart ) {

if (is_admin() && !defined('DOING_AJAX'))
    return;

if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
    return;

// First loop to check if CORE product is in cart
foreach ( $cart->get_cart() as $cart_item ){
    $is_in_cart = $cart_item['product_id'] == 1249 ? true : false;
}

// Second loop change prices
foreach ( $cart->get_cart() as $cart_item ) {

    // Get an instance of the WC_Product object (or the variation product object)
    $product = $cart_item['data'];

    // Here we target DISCOUNT ID 17
    if( $product->get_id() == 1361 ) {

        // GET THE NEW PRICE
        $new_price = 9.99; // <== Add your code HERE

        // When product CORE product is in cart
        if( $is_in_cart ){
            $product->set_price( $new_price );
        }
    }
}
}

I can't understand why this would happen for the life of me, but I am sure there is some minor detail I am missing.

Ad

Answer

In the first loop you have

$is_in_cart = $cart_item['product_id'] == 813 ? true : false;

Suppose there are 2 products in the cart 813 & 815.

While going through the cart items (first loop), suppose product 813 is first found, so $is_in_cart is true. Then in the same loop, however, $cart_item['product_id'] is now equal to 815. The condition says again, it is equal to 813? this does not match, so $is_in_cart will be false. That's the issue


So you don't need to use 2 foreach loops, this should suffice:

function action_woocommerce_before_calculate_totals( $cart ) {
    if ( is_admin() && ! defined( 'DOING_AJAX' ) )
        return;

    if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
        return;

    // Settings
    $core_product = 813;
    $discounted_product = 815;
    $new_price = 9.99; 
    
    // Initialize
    $flag_core_product = false;
    $flag_discounted_product = false;

    // Loop through cart items
    foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
        // Compare
        if ( $cart_item['product_id'] == $core_product ) {
            $flag_core_product = true;
        } elseif ( $cart_item['product_id'] == $discounted_product ) {
            $flag_discounted_product = true;
            
            // Store data (discounted product)
            $cart_item_data = $cart_item['data'];            
        }
    }
    
    // Both are true
    if ( $flag_core_product && $flag_discounted_product ) {
        // Set new price
        $cart_item_data->set_price( $new_price );
    }
}
add_action( 'woocommerce_before_calculate_totals', 'action_woocommerce_before_calculate_totals', 10, 1 );
Ad
source: stackoverflow.com
Ad