I've been trying to implement a discount in my store with the following code:
add_action('woocommerce_before_calculate_totals', 'set_discount', 10 );
function set_discount( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
// Loop Through cart items
foreach ( $cart->get_cart() as $cart_item ) {
// 50% items discount
$cart_item['data']->set_price( $cart_item['data']->get_price() / 2 );
}
}
It seems the set price is overwritten in the checkout by some standard AJAX request which reuses the original price, or something. I have tried using add_fee() with the same result, I have also tried deactivating all plugins (except woocommerce, of course) and I have tried switching to another theme - nothing works!
Using Wordpress 5.0.3, Woocommerce 3.5.4, Child theme of Storefront 2.4.2
1) This is what should be shown on checkout, and is being shown for around 1-2 seconds:
2) This is what is shown once the loading spinner is finalized - the original prices:
The correct code to be used since Woocommerce 3.2+ avoiding problems and errors is:
add_action('woocommerce_before_calculate_totals', 'cart_item_discount', 10, 1 );
function cart_item_discount( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
// Avoiding hook repetition (when using price calculations for example)
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
// Loop Through cart items
foreach ( $cart->get_cart() as $cart_item ) {
$original_price = $cart_item['data']->get_price(); // Get original product price
$discounted_price = $original_price / 2; // 50 % of discount
$cart_item['data']->set_price( $discounted_price );
}
}
Code goes in function.php file of your active child theme (or active theme). Tested and works (Tested on last versions: Wordpress 5.0.x | Woocommerce 3.5.x | Storefront 2.4.x)
If it doesn't work, it's because some other things or customizations are interacting with it. You need first to check Woocommerce > Status for red items (where all overridden templates, at the end, need to be up to date).