WooCommerce: Double discount on sale products with coupon - php

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 );

Related

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 );

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

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.

Do not give discounts for on sale products when selecting "local pickup" in WooCommerce

I use Local pickup shipping option custom percentage discount in Woocommerce answer code that adds a discount when choosing "Local Pickup" in the cart and at checkout.
I have set the discount to 20%.
How can I change this code to exclude products from calculations if they are already at a discount?
For example, there are 3 products in the cart: 2 products with a base price and 1 product with a discount. How to make sure that a 20% discount when choosing "Local Pickup" applies only to products with a base price?
Any help?
Instead of using $cart->get_subtotal()
$cart_item['line_subtotal'] is added to the $line_subtotal, if the product is not is_on_sale() (discount)
/**
* Discount for Local Pickup
*/
function custom_discount_for_pickup_shipping_method( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
$percentage = 20; // Discount percentage
$chosen_shipping_method_id = WC()->session->get( 'chosen_shipping_methods' )[0];
$chosen_shipping_method = explode(':', $chosen_shipping_method_id)[0];
// Only for Local pickup chosen shipping method
if ( strpos( $chosen_shipping_method_id, 'local_pickup' ) !== false ) {
// Set variable
$new_subtotal = 0;
// Loop though each cart items and set prices in an array
foreach ( $cart->get_cart() as $cart_item ) {
// Get product
$product = wc_get_product( $cart_item['product_id'] );
// Product has no discount
if ( ! $product->is_on_sale() ) {
// line_subtotal
$line_subtotal = $cart_item['line_subtotal'];
// Add to new subtotal
$new_subtotal += $line_subtotal;
}
}
// Calculate the discount
$discount = $new_subtotal * $percentage / 100;
// Add the discount
$cart->add_fee( __('Discount') . ' (' . $percentage . '%)', -$discount );
}
}
add_action( 'woocommerce_cart_calculate_fees', 'custom_discount_for_pickup_shipping_method', 10, 1 );

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.

Cart discount based on cart item count and only for items that are not in sale

In WooCommerce, I would like to give a discount of 10% specifically for those products that are not on sale. If cart item count is 5 or more items and not on sale, then I give a discount of 10%.
I use the following code to get a discount based on cart item count restriction here:
add_action('woocommerce_cart_calculate_fees' , 'add_custom_fees');
/**
* Add custom fee if more than three article
* #param WC_Cart $cart
*/
function add_custom_fees( WC_Cart $cart ){
if( $cart->cart_contents_count < 5 ){
return;
}
// Calculate the amount to reduce
$discount = $cart->subtotal * 0.1;
$cart->add_fee( '10% discount', -$discount);
}
But I don't know how to apply the discount only for items that are not in sale. How can I achieve it?
Thanks.
Here is a custom hooked function that will apply to cart a discount, if there is 5 or more items in cart and no products on sale:
add_action('woocommerce_cart_calculate_fees' , 'custom_discount', 10, 1);
function custom_discount( $cart ){
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
// Only when there is 5 or more items in cart
if( $cart->get_cart_contents_count() >= 5):
// Initialising variable
$is_on_sale = false;
// Iterating through each item in cart
foreach( $cart->get_cart() as $cart_item ){
// Getting an instance of the product object
$product = $cart_item['data'];
// If a cart item is on sale, $is_on_sale is true and we stop the loop
if($product->is_on_sale()){
$is_on_sale = true;
break;
}
}
## Discount calculation ##
$discount = $cart->subtotal * -0.1;
## Applied discount (no products on sale) ##
if(!$is_on_sale )
$cart->add_fee( '10% discount', $discount);
endif;
}
This code goes in function.php file of your active child theme (or theme) or also in any plugin file.
This code is tested and works perfectly.

Categories