How to use cart total to change cart items prices in WooCommerce - php

I am trying to pass the total amount of the cart ($GetTotalPrice) from function cart_prices_GetPrice() to function cart_prices_ApplyPrice(), using a woocommerce_after_calculate_totals and woocommerce_before_calculate_totals hooks, but I get an empty value.
//Trying to get cart amount
add_action('woocommerce_after_calculate_totals', 'cart_prices_GetPrice');
function cart_prices_GetPrice() {
//Getting the cart amount
$GetTotalPrice = WC()->cart->get_cart_total();
return $GetTotalPrice;
}
//Applying custom price
add_action('woocommerce_before_calculate_totals', 'cart_prices_ApplyPrice');
function cart_prices_ApplyPrice( $cart_object ) {
//Getting the cart amount from first function
$totalprice = cart_prices_GetPrice(); // doesn't work and returns 0 :(
//price change to cost2
if( $totalprice != 0 && $totalprice >= 2000 ) {
foreach ( $cart_object->get_cart() as $cart_id => $cart_item ) {
// get products id
$product_id = $cart_item['product_id'];
if( $cart_item['product_id'] == $product_id ) {
// price change to cost2
$new_price1 = 0.20;
$cart_item['data']->set_price( $new_price1 );
}
}
}
}
At the same time, each of the functions separately works perfectly.
What am I doing wrong? Is it possible to somehow link two hook data so that the first one doesn't return an empty value?
Update:
I will not be able to refuse the hook woocommerce_before_calculate_totals, because I need to apply a separate price reduction for each product in the cart.

You can simply not use cart total in woocommerce_before_calculate_totals when you want to alter cart item price for many reasons…
Instead you will get cart item subtotal inside woocommerce_before_calculate_totals hook. On the code below I use the discounted cart item subtotal including taxes:
add_action('woocommerce_before_calculate_totals', 'customize_cart_item_prices');
function customize_cart_item_prices( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
// Avoiding the hook repetition for price calculations
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
$threshold_amount = 1000; // Min subtotal
$discount_rate = 0.2; // price discount rate (20%)
$cart_items = $cart->get_cart();
// Getting non discounted cart items subtotal
$subtotal_excl_tax = array_sum( wp_list_pluck( $cart_items, 'line_subtotal' ) );
$subtotal_tax = array_sum( wp_list_pluck( $cart_items, 'line_subtotal_tax' ) );
// Getting discounted cart items subtotal
$total_excl_tax = array_sum( wp_list_pluck( $cart_items, 'line_total' ) );
$total_tax = array_sum( wp_list_pluck( $cart_items, 'line_tax' ) );
if( ( $total_excl_tax + $total_tax ) >= $threshold_amount ) {
// Loop through cart items
foreach ( $cart_items as $item ) {
$price = $item['data']->get_price(); // Get price
$item['data']->set_price( $price * ( 1 - $discount_rate ) ); // Set new price
}
}
}
Code goes in functions.php file of the active child theme (or active theme). Tested and works.
See on Change cart item prices in Woocommerce 3 answer code, to see how to handle minicart displayed custom cart item price.

Related

WooCommerce: Double discount on sale products with coupon

I want to double the discount for products on sale with a coupon code.
For example: The product is on sale with a 10% discount. If I add the coupon code doublediscount I want to double that discount to 20%.
The coupon discount should have limit of 15%.
So if a product is on sale with a 30% discount, the max added discount with the coupon code should be 15%. Resulting in a 45% discount on the regular price (sale + extra discount).
My code so far is this:
add_action( 'woocommerce_before_calculate_totals', 'double_saleprice_coupon' );
function double_saleprice_coupon( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
global $woocommerce;
$coupon_id = 'doublediscount';
// Loop through cart items (first loop)
foreach ( $cart->get_cart() as $cart_item_key => $cart_item ){
// Check if product in cart is on sale
$product = $cart_item['data'];
$cart_item_regular_price = $cart_item['data']->get_regular_price();
$cart_item_sale_price = $cart_item['data']->get_sale_price();
$cart_item_diff = $cart_item_regular_price - $cart_item_sale_price;
$cart_item_per_cent = round( $cart_item_diff / $cart_item_regular_price * 100, 0 );
if ( $product->is_on_sale() && wc_pb_is_bundled_cart_item($cart_item) === false && $cart_item_per_cent < 15 ) {
echo 'on sale';
echo $cart_item_per_cent;
}
}
}
I loop through all cart items and check if they are on sale and if the discount is below 15%. If that's the case, I want to change the discount for these cart items.
If the cart item has a discount above 15% I don't want to do anything. So the coupon code doublediscount would apply 15% to them.
I just don't know how to add/change the discount of a cart item.
You can use the woocommerce_coupon_get_discount_amount hook instead in combination with the following coupon settings:
Set correctly your coupon code: doublediscount
Discount type: Percentage
Amount: 15
Steps applied in this answer:
Only if the specific coupon code matches and the product is on sale
If a product is not on sale, no discount will be applied (by the else condition equal to 0. However, if this doesn't apply, you can simply remove the else condition)
Current percentage discount of the on sale product is calculated.
If this is less than the maximum added discount (15),
then the discount is doubled
If this is more, the maximum discount added (15) will be applied automatically
So you get:
function filter_woocommerce_coupon_get_discount_amount( $discount, $price_to_discount , $cart_item, $single, $coupon ) {
// Returns true when viewing the cart page & only apply for this coupon
if ( is_cart() || is_checkout() && $coupon->get_code() == 'doublediscount' ) {
// Get an instance of the WC_Product object
$product = $cart_item['data'];
// Is a WC product
if ( is_a( $product, 'WC_Product' ) ) {
// On sale
if ( $product->is_on_sale() ) {
// Regular price
$cart_item_regular_price = $product->get_regular_price();
// Sale price
$cart_item_sale_price = $product->get_sale_price();
// Calculate the percentage difference
$cart_item_diff = $cart_item_regular_price - $cart_item_sale_price;
$cart_item_percentage = round( $cart_item_diff / $cart_item_regular_price * 100, 0 );
// Get maximum added discount
$max_added_discount = $coupon->get_amount();
// Less than maximum added discount
if ( $cart_item_percentage < $max_added_discount ) {
$discount = round( ( $price_to_discount * $cart_item_percentage ) / 100, 0 );
}
} else {
$discount = 0;
}
}
}
return $discount;
}
add_filter( 'woocommerce_coupon_get_discount_amount', 'filter_woocommerce_coupon_get_discount_amount', 10, 5 );

Apply/determine discount based on a particular product category only when a specific product is in WooCommerce cart

I would like to replicate promo for a specific item.
If you buy one (b10 plus) product then you're eligible for a total 289€ discount on all light shaping tools, so if you add to cart accessories for a "category subtotal" of 100€ you get 100€ discount, if you take 300€ accessories you get 289€ discount.
I tried with another solution (plugins and php code) but it keeps discounting each item (that correspond to "accessories") for $289.
I also tried to include automatically a discount for that category if the "B10 plus" is in the cart. but this code add the discount to single products
This is my current code:
add_action( 'woocommerce_before_cart', 'bbloomer_apply_matched_coupons' );
function bbloomer_apply_matched_coupons() {
$coupon_code = 'promob10';
if ( WC()->cart->has_discount( $coupon_code ) ) return;
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
// this is your product ID
$autocoupon = array( 373 );
if ( in_array( $cart_item['product_id'], $autocoupon ) ) {
WC()->cart->apply_coupon( $coupon_code );
wc_print_notices();
}
}
}
To apply a discount based on a specific product ID you can use the woocommerce_cart_calculate_fees hook
First of all you will have to determine the specific product ID, this corresponds to the b10 product from your question
Then it will be checked whether this specific product is in the cart via find_product_in_cart(). If that's the case, let's move on
Through the price of the specific product ID, we determine the maximum discount
The price of the products belonging to the particular category is added to total discount (assuming that the b10 product does not belong to this category)
If the total discount is less than the maximum discount, we will use this discount. If not, the maximum discount will be applied
So you get:
function action_woocommerce_cart_calculate_fees( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
// Product ID of the specific product
$specific_product_id = 817;
// The term name/term_id/slug to check for.
$category = 'accessories';
// Initialize
$total_discount = 0;
$maximum_discount = 0;
// Cart id
$product_cart_id = $cart->generate_cart_id( $specific_product_id );
// Find product in cart
$in_cart = $cart->find_product_in_cart( $product_cart_id );
// In cart
if ( $in_cart ) {
// Gets cart contents
foreach ( $cart->get_cart_contents() as $cart_item ) {
// Get product id
$product_id = $cart_item['product_id'];
// Compare
if ( $product_id == $specific_product_id ) {
// Get price = maximum discount
$maximum_discount = $cart_item['data']->get_price();
}
// Has certain category
if ( has_term( $category, 'product_cat', $product_id ) ) {
// Get price
$price = $cart_item['data']->get_price();
// Get quantity
$quantity = $cart_item['quantity'];
// Addition to the total discount
$total_discount += $price * $quantity;
}
}
// Less than
if ( $total_discount < $maximum_discount ) {
// Add total discount
$cart->add_fee( __( 'Discount applied', 'woocommerce' ), -$total_discount, false );
} else {
// Add maximum discount
$cart->add_fee( __( 'Discount applied', 'woocommerce' ), -$maximum_discount, false );
}
}
}
add_action( 'woocommerce_cart_calculate_fees', 'action_woocommerce_cart_calculate_fees', 10, 1 );

Programmatically removing a product from basket

I'm using the following code to add a free product to the basket when over a certain cart total.
When I drop below the cart total it hits the if statement but won't remove the product.
I think this may be because the quantity is set to 1 on the basket form and my code isn't overriding that quantity to set it to 0 (and remove it).
Is there another way to remove it or override it?
/*
* Automatically adding the product to the cart when cart total amount reach to £20.
*/
function aapc_add_product_to_cart() {
global $woocommerce;
$cart_total = 20;
$free_product_id = 85028; // Product Id of the free product which will get added to cart
if ( $woocommerce->cart->total >= $cart_total ) {
echo "Over the limit";
$quantity = 1;
WC()->cart->add_to_cart( $free_product_id, $quantity );
} elseif($woocommerce->cart->total < $cart_total) {
echo "Under the limit";
$quantity = 0;
WC()->cart->remove_cart_item( $free_product_id, $quantity );
}
}
add_action( 'template_redirect', 'aapc_add_product_to_cart' );
I've tried using this question but cannot get it to work, it won't even add the item to my basket.
I'm using Woocommerce version 3.6.5 if that helps.
I'm not sure on how Woocommerce works but I assume the remove_cart_item 'quantity' parameter takes the amount of the item to remove from the basket. So set the value of $quantity to 1 and it should remove one of the free product from the basket. If there happens to be more than one free item in the basket then you'll need to set your $quantity value accordingly.
Furthermore, you are adding a free item every time a product is added when the basket value is higher than $cart_total. Maybe add a check to see if it already exists in the basket before adding it?
Hope I understood your question correctly
/*
* Automatically adding the product to the cart when cart total amount reach to £20.
*/
function aapc_add_product_to_cart() {
global $woocommerce;
$cart_total = 20;
$free_product_id = 85028; // Product Id of the free product which will get added to cart
if ( WC()->cart->total >= $cart_total ) {
$found = false;
//check if product already in cart
if ( sizeof( WC()->cart->get_cart() ) > 0 ) {
foreach ( WC()->cart->get_cart() as $cart_item_key => $values ) {
$_product = $values['data'];
if ( $_product->get_id() == $free_product_id )
$found = true;
}
// if product not found, add it
if ( ! $found )
WC()->cart->add_to_cart( $free_product_id );
} else {
// if no products in cart, add it
WC()->cart->add_to_cart( $free_product_id );
}
} elseif(WC()->cart->total < $cart_total) {
$quantity = 0;
$prod_unique_id = WC()->cart->generate_cart_id( $free_product_id );
// Remove it from the cart by un-setting it
unset( WC()->cart->cart_contents[$prod_unique_id] );
WC()->cart->remove_cart_item( $free_product_id );
}
}
add_action( 'woocommerce_after_calculate_totals', 'aapc_add_product_to_cart' );

Woocommerce discount on second item when not on sale items are in cart

Now I have the following Woocommerce discount: 1) at one item --> 10% only for not in sale items 2) at two items 20% for the cheapest item including on sale items
I tried use Cart discount based on cart item count and only for items that are not in sale
and Cart discount for product that cost less in Woocommerce answers code.
How can I add 10% discount, when I have two items, to the second item?
How can add discount only for not in sale items when I have two items, to the second item?
The following will make a 10% discount on the 2nd item when there is not items on sale in cart:
add_action('woocommerce_cart_calculate_fees' , 'custom_2nd_item_discount', 10, 1);
function custom_2nd_item_discount( $cart ){
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
// Only for 2 items or more
if ( $cart->get_cart_contents_count() < 2 )
return;
// Initialising variable
$has_on_sale = false;
$count_items = $discount = 0;
$percentage = 10; // 10 %
// Iterating through each item in cart
foreach( $cart->get_cart() as $cart_item ){
$count_items++;
if( $cart_item['data']->is_on_sale() ){
$has_on_sale = true;
}
if( 2 == $count_items ){
$discount = wc_get_price_excluding_tax( $cart_item['data'] ) * $percentage / 100;
}
}
// Apply discount to 2nd item for non on sale items in cart
if( ! $has_on_sale && $discount > 0 )
$cart->add_fee( sprintf( __("2nd item %s%% Discount"), $percentage), -$discount );
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.

Deposit based on a percentage of total cart amount

I've taken this code from another post and basically from my understanding, this code is trying to force the cart price to change to a fixed amount of $40 and charge it as a booking fee.
What I want to do is force the cart amount to be 20% of what the total would be based on adding up all the products in the cart. My site is for reservations, so I only want to charge a deposit and then have them pay when they use their reservation.
Here is the code from this post: Woocommerce cart deposit
add_action( 'woocommerce_cart_calculate_fees', 'booking_fee' );
function booking_fee() {
global $woocommerce;
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
$bookingfee_array = array( '2434' );
$fixed = 40.00;
foreach ( $woocommerce->cart->get_cart() as $cart_item_key => $values ) {
if( in_array( $values['product_id'], $bookingfee_array ) ) {
$surcharge = $fixed;
$woocommerce->cart->add_fee( 'Broneeringutasu', $surcharge, true, '' );
}
}
}
And here is how I would change it:
add_action( 'woocommerce_cart_calculate_fees', 'booking_fee' );
function booking_fee() {
global $woocommerce;
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
$bookingfee_array = array( '2434' );
$percent = .20;
foreach ( $woocommerce->cart->get_cart() as $cart_item_key => $values ) {
if( in_array( $values['product_id'], $bookingfee_array ) ) {
$surcharge = $percent;
$woocommerce->cart->add_fee( 'Booking Fee', $surcharge, true, '' );
}
}
}
But this is not working as expected.
Any help on this?
Thanks
Your code is not really going to do what you expect, as you are adding a fee of o.2 to total cart amount. So if the cart amount is 100, the grand total is going to be 100.2…
What you want to do instead, is to remove 80% of total cart amount to get a cart amount of 20%. This is possible using a negative fee of 80% from total cart amount. If you don't need to set targeted products IDs as in your original code, use the 2nd function below.
Here is the first function that will remove 80% of total cart amount when a cart item match with the targeted product IDs set in the function:
add_action( 'woocommerce_cart_calculate_fees', 'booking_deposit_calculation' );
function booking_deposit_calculation( $cart_object ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
## Set HERE your targeted products IDs
$target_product_ids = array( 2434 );
## Set HERE your negative percentage (to remove an amount from cart total)
$percent = -.80; // 80% off (negative)
$matching = false;
// Iterating through each cart items
foreach ( $cart_object->get_cart() as $item_values )
{
if( in_array( $item_values['product_id'], $target_product_ids ) )
{ // If a cart item match with a targeted product ID
// Get cart subtotal excluding taxes
$cart_subtotal = $cart_object->subtotal_ex_tax;
// or for subtotal including taxes use instead:
// $cart_subtotal = $cart_object->subtotal;
## ## CALCULATION ## ##
$calculated_amount = $cart_subtotal * $percent;
// Adding a negative fee to cart amount (Including taxes)
$cart_object->add_fee( __('Deposit calculation', 'woocommerce'), $calculated_amount, true );
break; // We stop the loop
}
}
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
But may be you don't need to have some targeted products as in the original code.
If it's the case this simplify the code:
add_action( 'woocommerce_cart_calculate_fees', 'booking_deposit_calculation' );
function booking_deposit_calculation( $cart_object ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
## Set HERE your negative percentage (to remove an amount from cart total)
$percent = -.80; // 80% off (negative)
// Get cart subtotal excluding taxes
$cart_subtotal = $cart_object->subtotal_ex_tax;
// or for subtotal including taxes use instead:
// $cart_subtotal = $cart_object->subtotal;
## ## CALCULATION ## ##
$calculated_amount = $cart_subtotal * $percent;
// Adding a negative fee to cart amount (Including taxes)
$cart_object->add_fee( __('Deposit calculation', 'woocommerce'), $calculated_amount, true );
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
Both functions are tested and works

Categories