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.
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 );
Related Questions
- → "failed to open stream" error when executing "migrate:make"
- → October CMS Plugin Routes.php not registering
- → OctoberCMS Migrate Table
- → OctoberCMS Rain User plugin not working or redirecting
- → October CMS Custom Mail Layout
- → October CMS - How to correctly route
- → October CMS create a multi select Form field
- → October CMS - Conditionally Load a Different Page
- → How to disable assets combining on development in OctoberCMS
- → October CMS - Radio Button Ajax Click Twice in a Row Causes Content to disappear
- → OctoberCms component: How to display all ID(items) instead of sorting only one ID?
- → In OctoberCMS how do you find the hint path?
- → How to register middlewares in OctoberCMS plugin?