I have the following code, it loops trougth woocommerce cart and selects the most expensive item and deducts it from the total of the cart updating the total price in the process.
add_filter( 'woocommerce_cart_total', 'wc_modify_cart_price' );
add_filter( 'woocommerce_order_amount_total', 'wc_modify_cart_price' );
function wc_modify_cart_price( $price ) {
$cart_ct = WC()->cart->get_cart_contents_count();
$tax = WC()->cart->get_taxes();
if($cart_ct > 1 ){
$product_prices = [];
$fee = 0;
$prices = array();
// Loop Through cart items - Collect product prices
foreach ( WC()->cart->get_cart() as $cart_item ) {
$_product = wc_get_product( $cart_item['product_id'] );
$terms = get_the_terms( $cart_item['product_id'], 'product_cat' );
#var_dump($terms[0]->name);
if($terms[0]->name == "pizza"){
$prices[] = $cart_item['data']->get_price();
}
}
$sort_price = max($prices);
$max_price = $sort_price;
$cart_total = WC()->cart->cart_contents_total;
$addition = $cart_total - $max_price;
WC()->cart->total = $addition;
$addition = $cart_total - $max_price + $tax[2];
}else{
echo $tax;
$addition = WC()->cart->cart_contents_total + $tax[2];
}
return $addition;
}
add_filter( 'woocommerce_calculated_total', 'wc_modify_cart_price', 10, 2 );
My issue is when i continue and go to checkout the total price order reverts back and i can't find out why, maybe im just calculating and not actually setting said price? how can i not only calculate but actually set that price as the order price?
I would use a different approach here because the numbers won't add up. If you just change the final amount you'll have something like this:
Pizza 1 $50
Pizza 2 $30
subtotal: $80
Total: $30
There are $50 missing without any explanation.
You can use the hook woocommerce_before_calculate_totals
to change the cart items.
For example, this code will change the price of the most expensive item to 0. But there is one problem with this. The customer can increase the quantity of these items and you will give away more than you wanted.
add_action( 'woocommerce_before_calculate_totals', 'set_most_expensive_product_to_zero' );
function set_most_expensive_product_to_zero( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
return;
}
// Set the initial maximum price to 0
$max_price = 0;
// Set the initial product ID to 0
$max_price_product_id = 0;
// Iterate through each item in the cart
foreach ( $cart->get_cart() as $cart_item ) {
// Get the product price
$product_price = $cart_item['data']->get_price();
// Check if the product price is greater than the current maximum price
if ( $product_price > $max_price ) {
// Update the maximum price
$max_price = $product_price;
// Update the product ID of the most expensive product
$max_price_product_id = $cart_item['product_id'];
}
}
// Iterate through each item in the cart again
foreach ( $cart->get_cart() as $cart_item ) {
// Check if the product ID matches the ID of the most expensive product
if ( $cart_item['product_id'] == $max_price_product_id ) {
// Set the price of the most expensive product to 0
$cart_item['data']->set_price( 0 );
}
}
}
Another approach, the one I would use, is creating a one time coupon code with the amount of the free pizza. Let's say a customer buys 2 pizzas for $20 each and one $16 pizza. You create a $20 coupon and you are done. All the numbers will match and customers will see their discount on the cart/checkout pages. Here is the code to do just that:
add_action( 'woocommerce_before_calculate_totals', 'generate_coupon_for_most_expensive_product' );
function generate_coupon_for_most_expensive_product( $cart ) {
if(WC()->cart->get_cart_contents_count() < 2){
remove_coupon_from_cart('pizza_');
return;
}
if ( has_coupon_code_with_prefix( 'pizza_' ) ) {
return;
}
// Set the initial maximum price to 0
$max_price = 0;
// Set the initial product ID to 0
$max_price_product_id = 0;
// Iterate through each item in the cart
foreach ( $cart->get_cart() as $cart_item ) {
// Get the product price
$product_price = $cart_item['data']->get_price();
// Check if the product price is greater than the current maximum price
if ( $product_price > $max_price ) {
// Update the maximum price
$max_price = $product_price;
// Update the product ID of the most expensive product
$max_price_product_id = $cart_item['product_id'];
}
}
// Check if the maximum price is greater than 0
if ( $max_price > 0 ) {
// Generate a coupon code
$coupon_code = uniqid( 'pizza_' );
$coupon = new WC_Coupon();
$coupon->set_code($coupon_code);
$coupon->set_amount( $max_price );
$coupon->set_individual_use(true);
$coupon->set_usage_limit(1);
$coupon->set_product_ids(array($max_price_product_id));
$coupon->save();
// Apply the coupon to the cart
$cart->add_discount( $coupon_code );
}
}
function has_coupon_code_with_prefix( $prefix ) {
// Get the applied coupons
$applied_coupons = WC()->cart->get_applied_coupons();
// Check if there are any applied coupons
if ( ! empty( $applied_coupons ) ) {
// Iterate through the applied coupons
foreach ( $applied_coupons as $coupon_code ) {
// Check if the coupon code starts with the specified prefix
if ( strpos( $coupon_code, $prefix ) === 0 ) {
// There is a coupon code applied that starts with the specified prefix
return true;
}
}
}
// No coupon code was found that starts with the specified prefix
return false;
}
function remove_coupon_from_cart($prefix) {
global $woocommerce;
// Get the cart object
$cart = $woocommerce->cart;
// Get the coupon codes applied to the cart
$coupon_codes = $cart->get_coupons();
// Loop through the coupon codes and remove any that start with the specified prefix
foreach ($coupon_codes as $code => $coupon) {
if (strpos($code, $prefix) === 0) {
$cart->remove_coupon($code);
// Save the updated cart
$cart->calculate_totals();
}
}
}