WooCommerce - Multiple cart dicounts - wordpress

I want a cart discount based on the total
5% over $600 order and 10% over $1000?
I can get it to work for the over $600 but not the over $1000. I get an error on line 15.
add_action( 'woocommerce_before_cart', 'apply_matched_coupons' );
function apply_matched_coupons() {
global $woocommerce;
$coupon_code = 'over600'; // your coupon code here
$coupon_codeb = 'over1000'; // your coupon code here
if ( $woocommerce->cart->has_discount( $coupon_code ) ) return;
if ( $woocommerce->cart->cart_contents_total >= 600 ) {
$woocommerce->cart->add_discount( $coupon_code );
$woocommerce->show_messages();
}
if ( $woocommerce->cart->cart_contents_total >= 1000 ) {
$woocommerce->cart->add_discount( $coupon_codeb );
$woocommerce->show_messages();
}
}

Ended up doing it a completely different way
function nh_custom_coupon_filter() {
global $woocommerce;
$excluded_amount = $discount_percent = 0;
$working_total = $woocommerce->cart->cart_contents_total;
$excluded_categories = array(
217, # Training
223, # Starter Kits
);
# Only apply manual discount if no coupons are applied
if (!$woocommerce->cart->applied_coupons) {
# Find any items in cart that belong to the restricted categories
foreach ($woocommerce->cart->cart_contents as $item) {
$product_categories = get_the_terms($item['product_id'], 'product_cat');
if (empty($product_categories) || is_wp_error($product_categories) || !$product_categories) {
if (is_wp_error($product_categories)) {
wp_die($product_categories->get_error_message());
}
else {
$product_categories = new WP_Error('no_product_categories', "The product \"".$item->post_title."\" doesn't have any categories attached, thus no discounts can be calculated.", "Fatal Error");
wp_die($product_categories);
}
}
foreach ($excluded_categories as $excluded_category) {
foreach ($product_categories as $category) {
if ($excluded_category == $category->term_id) {
$excluded_amount += $item['line_subtotal']; # Increase our exclusion amount
$working_total -= $item['line_subtotal']; # Decrease our discountable amount
}
}
}
}
# Logic to determine WHICH discount to apply based on subtotal
if ($working_total >= 600 && $working_total < 1000) {
$discount_percent = 5;
}
elseif ($working_total >= 1000) {
$discount_percent = 10;
}
else {
$discount_percent = 0;
}
# Make sure cart total is eligible for discount
if ($discount_percent > 0) {
$discount_amount = ( ( ($discount_percent/100) * $working_total ) * -1 );
$woocommerce->cart->add_fee('Bulk Discount', $discount_amount);
}
}
}
add_action('woocommerce_cart_calculate_fees', 'nh_custom_coupon_filter');

Related

Woocommerce Min/Max, Default QTY and Quantity Step

I am trying to set the following for all products:
Min Qty 6
Max QTY 240
Quantity Step 6
Input Value 6
But all pulls through except the Default Input Value (product and Cart page)
Herewith the code
/**
* Adjust the quantity input values
*/
add_filter( 'woocommerce_quantity_input_args', 'jk_woocommerce_quantity_input_args', 10, 2 ); // Simple products
function jk_woocommerce_quantity_input_args( $args, $product ) {
if ( is_singular( 'product' ) ) {
$args['input_value'] = 6;
}
$args['max_value'] = 240; // Maximum value
$args['min_value'] = 6; // Minimum value
$args['step'] = 6; // Quantity steps
return $args;
}
add_filter( 'woocommerce_available_variation', 'jk_woocommerce_available_variation' ); // Variations
function jk_woocommerce_available_variation( $args ) {
$args['max_qty'] = 240; // Maximum value (variations)
$args['min_qty'] = 6; // Minimum value (variations)
return $args;
}

updating product subtotal in cart contents

I've trying to write my campaign plugin.
Here is the problem,
I want to update, line_subtotal and line_total in a product in $cart_items.
1- woocommerce_cart_product_subtotal is not really working.
2- I tried to redefine array's element by cart_item_key
foreach($cartItems as $hash => $perProduct)
{
if($perProduct['product_id'] = $lastItemsProductId)
{
if($lastItemsQuantity > 1)
{
$lineSubtotal = data_get($lastItemInCart, 'line_subtotal');
$lineTotal = data_get($lastItemInCart, 'line_total');
$newQuantity = $lastItemsQuantity-1;
$lastItemInCart['line_subtotal'] = $newQuantity * $lastItemsPrice;
$lastItemInCart['line_total'] = $newQuantity * $lastItemsPrice;
$cartItems[$lastItemsKey] = $lastItemInCart;
WC()->cart->calculate_totals();
} else {
}
}
}
Also this function runs, in woocommerce_before_calculate_totals action.
When i try it, with woocommerce_get_cart_contents filter, my cart empty itself .
3- The scenario :
When i add A product, (if is selected by system) and if quantity is more than 2, i want to make discount about this product.
Any helps ? Thanks.
Here is the answer
/**
* Add filter for order list
*
* #param [int] $product_subtotal
* #param [object] $product
* #param [int] $quantity
* #param [array] $cart
* #return void
*/
public function filterWoocommerceCartProductSubtotal($product_subtotal, $product, $quantity, $cart) : string
{
$appliedCoupons = $cart ? $cart->get_applied_coupons() : null;
$cartCount = $cart ? count($cart->get_cart()) : 0;
$cartItems = $cart->get_cart();
$lastItemInCart = last($cartItems);
$lastItemsProductId = data_get($lastItemInCart, 'product_id', data_get($lastItemInCart, 'product_id'));
$lastItemsPrice = $lastItemInCart['data']->get_regular_price();
$lastItemsQuantity = data_get($lastItemInCart, 'quantity');
$lastItemsKey = data_get($lastItemInCart, 'key');
if( in_array('3al2ode', $appliedCoupons)){
if($lastItemsQuantity > 1) {
if(#data_get($product,'id') == $lastItemsProductId)
{
$newSubTotal = 0;
$price = $product->get_price();
$newQuantity = $lastItemsQuantity-1;
$quantity = $newQuantity;
$newSubTotal += $price * $quantity;
return $newSubTotal ? wc_price($newSubTotal) : $product_subtotal;
}
}
}
return $product_subtotal;
}
The right, filter should be like;
add_filter( 'woocommerce_cart_product_subtotal', [$this,'filterWoocommerceCartProductSubtotal'], 10, 4);
As per your current scenario - When I add A product, (it is selected by the system) and if the quantity is more than 2, I want to make a discount on this product.
You should try this-
add_action( 'woocommerce_cart_calculate_fees','woocommerce_add_discount',10, 1 );
function woocommerce_add_discount() {
global $woocommerce;
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
$cart_qty = count($woocommerce->cart->get_cart());
if($cart_qty > 2)
{
$percentage = 0.5;
$cart_subtotal = $woocommerce->cart->get_subtotal() ?: 0;
//$cart_total = $woocommerce->cart->cart_contents_total;
//$shipping_total = $woocommerce->cart->get_shipping_total() ?: 0;
//$tax_total = $woocommerce->cart->get_taxes_total() ?: 0;
//$grand_total = $cart_total + $shipping_total + $tax_total;
// Calculate the amount to reduce
$discount = $cart_subtotal * $percentage;
$woocommerce->cart->add_fee( 'Discount 50%', -$discount, true, '' );
}
}
You can update/modify condition accordingly.
/**
* Add filter for order list
*
* #param [int] $product_subtotal
* #param [object] $product
* #param [int] $quantity
* #param [array] $cart
* #return void
*/
public function filterWoocommerceCartProductSubtotal($product_subtotal, $product, $quantity, $cart) : string
{
$appliedCoupons = $cart ? $cart->get_applied_coupons() : null;
$cartCount = $cart ? count($cart->get_cart()) : 0;
$cartItems = $cart->get_cart();
$lastItemInCart = last($cartItems);
$lastItemsProductId = data_get($lastItemInCart, 'product_id', data_get($lastItemInCart, 'product_id'));
$lastItemsPrice = $lastItemInCart['data']->get_regular_price();
$lastItemsQuantity = data_get($lastItemInCart, 'quantity');
$lastItemsKey = data_get($lastItemInCart, 'key');
if( in_array('3al2ode', $appliedCoupons)){
if($lastItemsQuantity > 1) {
if(#data_get($product,'id') == $lastItemsProductId)
{
$newSubTotal = 0;
$price = $product->get_price();
$newQuantity = $lastItemsQuantity-1;
$quantity = $newQuantity;
$newSubTotal += $price * $quantity;
return $newSubTotal ? wc_price($newSubTotal) : $product_subtotal;
}
}
}
return $product_subtotal;
}
The right, filter should be like;
add_filter( 'woocommerce_cart_product_subtotal', [$this,'filterWoocommerceCartProductSubtotal'], 10, 4);

Shipping class formula help: If quantity is 1-3, charge X amount?

I am selling prints in my store. I print them and ship them off in tubes. Each tube can hold up to three prints and the cost to send one tube is X amount.
How can I write:
If quantity is 1-3, charge X…
If the quantity is 4-6, charge 2X…
If the quantity is 7-9, charge 3X…
Etc, etc.?
Or is there a better way?
You can use
woocommerce_package_rates
hook to manipulate the shipping costs.
function woocommerce_package_rates( $rates ) {
//Assuming charge X you mentioned is 5
$custom_shipping_cost = 5;
$total_items = WC()->cart->get_cart_contents_count();
if($total_items > 3 && $total_items < 7) $custom_shipping_cost *= 2;
else if ($total_items > 6 && $total_items < 10) $custom_shipping_cost *= 3;
else if ($total_items > 9 && $total_items < 13) $custom_shipping_cost *= 4;
//you may add more else if statements here
//or try this which is smarter I believe:
/*
* $multiplier = floor( $total_items / 4 ) + 1;
* $custom_shipping_cost *= $multiplier;
*/
foreach($rates as $key => $rate )
{
$rates[$key]->cost = $custom_shipping_cost;
}
return $rates;
}
add_filter( 'woocommerce_package_rates', 'woocommerce_package_rates' );
Hope this helps. Code goes to functions.php of your theme or child-theme (which is better).

Convert thousand to K, million to M in woocommerce

I am using woocommerce and I'd like to shorten all product prices to K (for thousand) and M (for million). So 150,000 would be 150K, 2,500,000 would be 2,5M etc. How do I do that?
Thank you!
add_filter('woocommerce_price_html','rei_woocommerce_price_html', 10, 2);
add_filter('woocommerce_sale_price_html','rei_woocommerce_price_html', 10, 2);
function rei_woocommerce_price_html($price, $product) {
$currency = get_woocommerce_currency_symbol( );
$price = $currency . custom_number_format($product->get_price(),1);
return $price;
}
function custom_number_format($n, $precision = 3) {
if ($n < 1000000) {
// Anything less than a million
$n_format = number_format($n);
} else if ($n < 1000000000) {
// Anything less than a billion
$n_format = number_format($n / 1000000, $precision) . 'M';
} else {
// At least a billion
$n_format = number_format($n / 1000000000, $precision) . 'B';
}
return $n_format;
}
couple things to note here..
woocommerce_sale_price_html does not include the original price.. you have to code it.
the logic on currency format on WooCommerce is ignored. you may have to adjust the code according to your needs.
I think this will help you
<?php
$n = 265460;
function bd_nice_number($n) {
$n = (0+str_replace(",","",$n));
if(!is_numeric($n)) return false;
if($n>1000000000000) return round(($n/1000000000000),1).'-T';
else if($n>1000000000) return round(($n/1000000000),1).'B';
else if($n>1000000) return round(($n/1000000),1).'M';
else if($n>1000) return round(($n/1000),1).'K';
return number_format($n);
}
$v = bd_nice_number($n);
echo $v;
?>

Calculate percentage saved between two numbers?

I have two numbers, the first, is the original price, the second, is the discounted price.
I need to work out what percentage a user saves if they purchase at the second price.
example
25, 10 = 60%
365, 165 = 55%
What I dont know is the formula to calculate this.
I know this is fairly old but I figured this was as good as any to put this. I found a post from yahoo with a good explanation:
Let's say you have two numbers, 40 and 30.
30/40*100 = 75.
So 30 is 75% of 40.
40/30*100 = 133.
So 40 is 133% of 30.
The percentage increase from 30 to 40 is:
(40-30)/30 * 100 = 33%
The percentage decrease from 40 to 30 is:
(40-30)/40 * 100 = 25%.
These calculations hold true whatever your two numbers.
Original Post
((list price - actual price) / (list price)) * 100%
For example:
((25 - 10) / 25) * 100% = 60%
I see that this is a very old question, but this is how I calculate the percentage difference between 2 numbers:
(1 - (oldNumber / newNumber)) * 100
So, the percentage difference from 30 to 40 is:
(1 - (30/40)) * 100 = +25% (meaning, increase by 25%)
The percentage difference from 40 to 30 is:
(1 - (40/30)) * 100 = -33.33% (meaning, decrease by 33%)
In php, I use a function like this:
function calculatePercentage($oldFigure, $newFigure) {
if (($oldFigure != 0) && ($newFigure != 0)) {
$percentChange = (1 - $oldFigure / $newFigure) * 100;
}
else {
$percentChange = null;
}
return $percentChange;
}
The formula would be (original - discounted)/original. i.e. (365-165)/365 = 0.5479...
function calculatePercentage($oldFigure, $newFigure)
{
$percentChange = (($oldFigure - $newFigure) / $oldFigure) * 100;
return round(abs($percentChange));
}
100% - discounted price / full price
If total no is: 200
and getting 50 number
then take percentage of 50 in 200 is:
(50/200)*100 = 25%
I have done the same percentage calculator for one of my app where we need to show the percentage saved if you choose a "Yearly Plan" over the "Monthly Plan". It helps you to save a specific amount of money in the given period. I have used it for the subscriptions.
Monthly paid for a year - 2028
Yearly paid one time - 1699
1699 is a 16.22% decrease of 2028.
Formula: Percentage of decrease = |2028 - 1699|/2028 = 329/2028 = 0.1622
= 16.22%
Code:
func calculatePercentage(monthly: Double, yearly: Double) -> Double {
let totalMonthlyInYear = monthly * 12
let result = ((totalMonthlyInYear-yearly)/totalMonthlyInYear)*100
print("percentage is -",result)
return result.rounded(toPlaces: 0)
}
Usage:
let savingsPercentage = self.calculatePercentage(monthly: Double( monthlyProduct.price), yearly: Double(annualProduct.price))
self.btnPlanDiscount.setTitle("Save \(Int(savingsPercentage))%",for: .normal)
The extension usage for rounding up the percentage over the Double:
extension Double {
/// Rounds the double to decimal places value
func rounded(toPlaces places:Int) -> Double {
let divisor = pow(10.0, Double(places))
return (self * divisor).rounded() / divisor
}
}
I have attached the image for understanding the same:
This is function with inverted option
It will return:
'change' - string that you can use for css class in your template
'result' - plain result
'formatted' - formatted result
function getPercentageChange( $oldNumber , $newNumber , $format = true , $invert = false ){
$value = $newNumber - $oldNumber;
$change = '';
$sign = '';
$result = 0.00;
if ( $invert ) {
if ( $value > 0 ) {
// going UP
$change = 'up';
$sign = '+';
if ( $oldNumber > 0 ) {
$result = ($newNumber / $oldNumber) * 100;
} else {
$result = 100.00;
}
}elseif ( $value < 0 ) {
// going DOWN
$change = 'down';
//$value = abs($value);
$result = ($oldNumber / $newNumber) * 100;
$result = abs($result);
$sign = '-';
}else {
// no changes
}
}else{
if ( $newNumber > $oldNumber ) {
// increase
$change = 'up';
if ( $oldNumber > 0 ) {
$result = ( ( $newNumber / $oldNumber ) - 1 )* 100;
}else{
$result = 100.00;
}
$sign = '+';
}elseif ( $oldNumber > $newNumber ) {
// decrease
$change = 'down';
if ( $oldNumber > 0 ) {
$result = ( ( $newNumber / $oldNumber ) - 1 )* 100;
} else {
$result = 100.00;
}
$sign = '-';
}else{
// no change
}
$result = abs($result);
}
$result_formatted = number_format($result, 2);
if ( $invert ) {
if ( $change == 'up' ) {
$change = 'down';
}elseif ( $change == 'down' ) {
$change = 'up';
}else{
//
}
if ( $sign == '+' ) {
$sign = '-';
}elseif ( $sign == '-' ) {
$sign = '+';
}else{
//
}
}
if ( $format ) {
$formatted = '<span class="going '.$change.'">'.$sign.''.$result_formatted.' %</span>';
} else{
$formatted = $result_formatted;
}
return array( 'change' => $change , 'result' => $result , 'formatted' => $formatted );
}
I think this covers this formula sufficiently,
((curr value - base value) / (curr value)) * 100%
Basically we just (in programming):
perform the calculation if both numbers are not 0.
If curr value is 0 then we return -100 % difference from the base,
if both are 0 then return 0 (we can't divide by 0)
Powershell example:
Strip any non numeric from vars and perform calculation
Function Get-PercentageSaved {
#((curr value - base value) / (curr value)) * 100%
param(
[Parameter(Mandatory = $false)][string]$CurrVal = $null,
[Parameter(Mandatory = $false)][string]$BaseVal = $null
)
$Result = $null
Try {
$CurrVal = [float]($CurrVal -replace '[^0-9.]', '')
$BaseVal = [float]($BaseVal -replace '[^0-9.]', '')
if (-Not($null -eq $CurrVal) -And (-Not($null -eq $BaseVal))) {
if ($CurrVal -eq 0) {
If ($BaseVal -eq 0) {
$Result = 0
} Else {
$Result = -100
}
}
else {
$Result = [math]::Round([float]((($CurrVal - $BaseVal) / $CurrVal) * 100),2)
}
}
}
Catch {}
Return [float]$Result
}

Resources