I am having a problem getting my price updates to stick. More or less this is a sample of what I am using to update the prices:
add_action( 'woocommerce_before_calculate_totals', 'cst_product_quantity_discounter', 10 );
function cst_product_quantity_discounter( $cart_object ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ){
return;
}
if( ! isset( WC()->session->reload_checkout ) ) {
// declare woocommerce global
global $woocommerce;
// array of ID's to match that represent each item
$special_ids_array = [
0 => array( "id" => 15372, "product" => "TAF", "single_bag_price" => 42.99, "3_multiplier" => 0.82181902768 ),
1 => array( "id" => 14285, "product" => "POW", "single_bag_price" => 29.99, "3_multiplier" => 0.8890741358 )
];
// gather cart object
$wc_cart = WC()->cart->get_cart();
foreach( $wc_cart as $cart_item ){
// gather relevant data for testing and comparisons
$product_id = $cart_item['product_id'];
$product_key = $cart_item['key'];
$pack_size_attribute = $cart_item['variation']['attribute_pa_sample-check']; // returns: "full-pack" || "sample" || null
$item_quantity = $cart_item['quantity'];
foreach ( $special_ids_array as $id_test_2 ) {
if ( $product_id === $id_test_2["id"] && $pack_size_attribute !== "sample" ){
foreach ( $cart_object->cart_contents as $key => $value ) {
// if the key matches we will set the price of the correct product
if ( $key === $product_key ){
$discounted_price = 10;
$value['data']->set_price($discounted_price);
}
}
}
}
}
}
}
There is some other stuff to get the values seen but that works. this will update on my test cart page and everything looks fine.
My issue is when I go to my test checkout page the prices update briefly, then they are overwritten by the original price. I am missing some update thats being run on checkout and woocommerce_before_calculate_totals
hook does not seem to be making a permanent change on the checkout page.
Where do I need to hook my function so the changes persist whatever loads are occurring on checkout that overwrite the initial successful price change?
There is some strange things in your code:
$cart_object
(that is the WC_Cart
object) is already an argument in the hooked function (it replaces WC()->cart
or outdated $woocommerce->cart
)…WC()->cart->get_cart()
and $cart_object->cart_contents
are exactly the same thing. The best is using $cart_object->get_cart()
in your foreach loops.global $woocommerce;
as it's already included in WC()
(the global Woocommerce object so already in $cart_object
)reload_checkout
doesn't exist in WC_Sessions
or WC_Session_Handler
classes (so your condition is always true) and anyway this is not useful for this hook.$cart_item['data']
is an instance of the WC_Product
object for this cart item.$cart_item['key']
and the $key
(in the cart loop) are always the same thing. You will not really need to use it in this case…So I have tried to add back a kind of dynamic price calculation in more real conditions, but in a different way based on your
$special_ids_array
array keys/values.The calculated dynamic price discount start with a quantity of 3 by item that match the conditions (Product Ids et "pack size" attribute).
So All this simplifies and compact a lot this revisited code:
add_action( 'woocommerce_before_calculate_totals', 'custom_product_quantity_discounter', 10, 1 );
function custom_product_quantity_discounter( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
// array of ID's to match that represent each item
$special_ids = array(
0 => array( "id" => 15372, "product" => "TAF", "single_bag_price" => 42.99, "3_multiplier" => 0.82181902768 ),
1 => array( "id" => 14285, "product" => "POW", "single_bag_price" => 29.99, "3_multiplier" => 0.8890741358 ),
);
// Loop through the cart items
foreach( $cart->get_cart() as $cart_item ){
$product_id = $cart_item['product_id'];
$quantity = $cart_item['quantity'];
$pack_size = $cart_item['variation']['attribute_pa_sample-check']; // returns "full-pack", "sample" or null
foreach ( $special_ids as $special_id ){
if( $special_id['id'] == $product_id && $pack_size !== 'sample' && $quantity >= 3 ){
$discounted_price = $special_id['single_bag_price'] * $special_id['3_multiplier']; // calculation (fake and custom)
$cart_item['data']->set_price($discounted_price); // set the calculated price
}
}
}
}
Code goes in function.php file of the active child theme (or active theme).
Tested and works.
The dynamic calculated pricing based on cart item quantities and custom calculation persist in checkout even when reloading the page multiple times.