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);
I am aware SCSS can convert Hex to RGBa, but is there an option for the opposite?
My situation is this: I am given a colour palette that I am not allow to change. This includes a solid accent colour:
$color-accent: #039B15;
I've been asked to use this as a pale background colour, with 80% opacity. That's easy, I can just use rgba():
$color-accent-bg: rgba($color-accent, .2);
However, there is a situation where I need to nest elements with the same opaque background colour - because the colours are opaque they darken when nested.
Is there a way I can convert $color-accent-bg back to hexidecimal with SASS?
Ps: tried using lighten() but that seems to only work up to 66% light.
IMO simple rgba($color-accent-bg, 1) would do the trick - it returns same color as $color-accent.
Otherwise, you can use #ie_hex_str($color). It converts colors to hex string in #AARRGGBB format.
Converts a color into the format understood by IE filters.
Examples: ...
ie-hex-str(rgba(0, 255, 0, 0.5)) => #8000FF00
Since it returns string, you can remove AA part like in last line in following snippet:
$color-accent: #039B15;
$color-accent-bg: rgba($color-accent, .2);
$ie-hex: ie_hex_str($color-accent-bg); //#33039B15
$back-to-color-accent: unquote('#' + str_slice($ie-hex, 4)); //#039B15
Convert RGBa to Hex(transparent. no background, 8-bit color).
Tested solution i have written this code in scss and then converted to sass
In your Scss put:
// convert string to number
#function to-number($value) {
#if type-of($value) == 'number' {
#return $value;
} #else if type-of($value) != 'string' {
#error 'Value for `to-number` should be a number or a string.';
}
$result: 0;
$digits: 0;
$minus: str-slice($value, 1, 1) == '-';
$numbers: ('0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9);
#for $i from if($minus, 2, 1) through str-length($value) {
$character: str-slice($value, $i, $i);
#if (index(map-keys($numbers), $character) or $character == '.') {
#if $character == '.' {
$digits: 1;
} #else if $digits == 0 {
$result: $result * 10 + map-get($numbers, $character);
} #else {
$digits: $digits * 10;
$result: $result + map-get($numbers, $character) / $digits;
}
}
}
#return if($minus, -$result, $result);;
}
#function decimal-round ($number, $digits: 0, $mode: round) {
$n: 1;
// $number must be a number
#if type-of($number) != number {
#warn '#{ $number } is not a number.';
#return $number;
}
// $digits must be a unitless number
#if type-of($digits) != number {
#warn '#{ $digits } is not a number.';
#return $number;
} #else if not unitless($digits) {
#warn '#{ $digits } has a unit.';
#return $number;
}
#if $digits > 0 {
#for $i from 1 through $digits {
$n: $n * 10;
}
}
#if $mode == round {
#return round($number * $n) / $n;
} #else if $mode == ceil {
#return ceil($number * $n) / $n;
} #else if $mode == floor {
#return floor($number * $n) / $n;
} #else {
#warn '#{ $mode } is undefined keyword.';
#return $number;
}
}
#function rgba-to-hex($rgba){
$colorCode: ( '0','1', '2','3','4','5','6','7','8','9','A','B','C','D','E', 'F');
// 255 / 100 = 2.55
// 10 / 16 = 0.625
$alpha: alpha($rgba);
// ============================================= RED ================================
$redStr: ''+(red($rgba) / 16);
$index: str-index($redStr, ".");
// add decimal number incase it does not have and update index
#if $index == null { $redStr: $redStr+'.0'; $index: str-index($redStr, ".");};
// #debug $redStr '========================================================';
$redInteger : to-number(str-slice($redStr, 0, $index - 1));
$redDecimal: decimal-round(to-number(str-slice($redStr, $index + 1, $index + 1)) / 0.625);
// ============================================= GREEN ============================
$greenStr: ''+(green($rgba) / 16);
$index: str-index($greenStr, ".");
// add decimal number incase it does not have and
#if $index == null { $greenStr: $greenStr+'.0'; $index: str-index($greenStr, ".");};
$greenInteger : to-number(str-slice($greenStr, 0, $index - 1));
$greenDecimal: decimal-round(to-number(str-slice($greenStr, $index + 1, $index + 1)) / 0.625);
// ============================================= BLUE ============================
$blueStr: ''+(blue($rgba) / 16);
$index: str-index($blueStr, ".");
// add decimal number incase it does not have and
#if $index == null { $blueStr: $blueStr+'.0'; $index: str-index($blueStr, ".");};
$blueInteger : to-number(str-slice($blueStr, 0, $index - 1));
$blueDecimal: decimal-round(to-number(str-slice($blueStr, $index + 1, $index + 1)) / 0.625) ;
// if interger is 16 sent decimal should be 0
//#debug 'blue: '+ $blueStr +' interter: '+ $blueInteger +' decimal: '+ $blueDecimal;
// $blue: blue($rgba) / 2.55;
// ============================================= ALPHA ============================
$alphaStr: ''+ decimal-round((($alpha*100)*2.55) /16) ;
$index: str-index($alphaStr, ".");
#if $index == null { $alphaStr: $alphaStr+'.0'; $index: str-index($alphaStr, ".");};
//#debug 'alphaStr: '+ decimal-round(to-number($alphaStr)) ;
$alphaInteger : ''+to-number(str-slice($alphaStr, 0, $index - 1));
$index: str-index($alphaInteger, ".");
#if $index == null { $alphaInteger: $alphaInteger+'.0'; $index: str-index($alphaInteger, ".");};
$alphaInteger : to-number(str-slice($alphaStr, 0, $index - 1));
$alphaDecimal: to-number(str-slice(''+to-number(str-slice($alphaStr, $index + 1, str-length($alphaStr))) / 0.625, 0, 2)) ;
// #debug 'Integer: ==== '+$alphaInteger;
// #debug 'Decimal: ==== '+$alphaDecimal;
#return unquote("#"+nth($colorCode, $redInteger + 1)+nth($colorCode, $redDecimal + 1)+nth($colorCode, $greenInteger + 1)+nth($colorCode, $greenDecimal + 1) +nth($colorCode, $blueInteger + 1)+nth($colorCode, $blueDecimal + 1)+nth($colorCode, $alphaInteger + 1)+nth($colorCode, $alphaDecimal + 1));
};
Usage
$result : rgba-to-hex( rgba(192, 84, 84, 0.582));
#debug $result;
.my-class{
background-color: rgba-to-hex( rgba(192, 84, 84, 0.582));
}
OutPut
Terminal:
#C0535390
css build file:
.my-class{
background-color: #C0535390;
}
In your sass file put:
#function to-number($value)
#if type-of($value) == 'number'
#return $value
#else if type-of($value) != 'string'
#error 'Value for `to-number` should be a number or a string.'
$result: 0
$digits: 0
$minus: str-slice($value, 1, 1) == '-'
$numbers: ('0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9)
#for $i from if($minus, 2, 1) through str-length($value)
$character: str-slice($value, $i, $i)
#if (index(map-keys($numbers), $character) or $character == '.')
#if $character == '.'
$digits: 1
#else if $digits == 0
$result: $result * 10 + map-get($numbers, $character)
#else
$digits: $digits * 10
$result: $result + map-get($numbers, $character) / $digits
#return if($minus, -$result, $result)
#function decimal-round ($number, $digits: 0, $mode: round)
$n: 1
#if type-of($number) != number
#warn '#{ $number } is not a number.'
#return $number
// $digits must be a unitless number
#if type-of($digits) != number
#warn '#{ $digits } is not a number.'
#return $number
#else if not unitless($digits)
#warn '#{ $digits } has a unit.'
#return $number
#if $digits > 0
#for $i from 1 through $digits
$n: $n * 10
#if $mode == round
#return round($number * $n) / $n
#else if $mode == ceil
#return ceil($number * $n) / $n
#else if $mode == floor
#return floor($number * $n) / $n
#else
#warn '#{ $mode } is undefined keyword.'
#return $number
#function rgba-to-hex($rgba)
$colorCode: ( '0','1', '2','3','4','5','6','7','8','9','A','B','C','D','E', 'F')
// 255 / 100 = 2.55
// 10 / 16 = 0.625
$alpha: alpha($rgba)
// ============================================= RED ================================
$redStr: ''+(red($rgba) / 16)
$index: str-index($redStr, ".")
// add decimal number incase it does not have and update index
#if $index == null
$redStr: $redStr+'.0'
$index: str-index($redStr, ".")
$redInteger : to-number(str-slice($redStr, 0, $index - 1))
$redDecimal: decimal-round(to-number(str-slice($redStr, $index + 1, $index + 1)) / 0.625)
// ============================================= GREEN ============================
$greenStr: ''+(green($rgba) / 16)
$index: str-index($greenStr, ".")
// add decimal number incase it does not have and
#if $index == null
$greenStr: $greenStr+'.0'
$index: str-index($greenStr, ".")
$greenInteger : to-number(str-slice($greenStr, 0, $index - 1))
$greenDecimal: decimal-round(to-number(str-slice($greenStr, $index + 1, $index + 1)) / 0.625)
// ============================================= BLUE ============================
$blueStr: ''+(blue($rgba) / 16)
$index: str-index($blueStr, ".")
#if $index == null
$blueStr: $blueStr+'.0'
$index: str-index($blueStr, ".")
$blueInteger : to-number(str-slice($blueStr, 0, $index - 1))
$blueDecimal: decimal-round(to-number(str-slice($blueStr, $index + 1, $index + 1)) / 0.625)
// ============================================= ALPHA ============================
$alphaStr: ''+ decimal-round((($alpha*100)*2.55) /16)
$index: str-index($alphaStr, ".")
#if $index == null
$alphaStr: $alphaStr+'.0'
$index: str-index($alphaStr, ".")
$alphaInteger : ''+to-number(str-slice($alphaStr, 0, $index - 1))
$index: str-index($alphaInteger, ".")
#if $index == null
$alphaInteger: $alphaInteger+'.0'
$index: str-index($alphaInteger, ".")
$alphaInteger : to-number(str-slice($alphaStr, 0, $index - 1))
$alphaDecimal: to-number(str-slice(''+to-number(str-slice($alphaStr, $index + 1, str-length($alphaStr))) / 0.625, 0, 2))
#return unquote("#"+nth($colorCode, $redInteger + 1)+nth($colorCode, $redDecimal + 1)+nth($colorCode, $greenInteger + 1)+nth($colorCode, $greenDecimal + 1) +nth($colorCode, $blueInteger + 1)+nth($colorCode, $blueDecimal + 1)+nth($colorCode, $alphaInteger + 1)+nth($colorCode, $alphaDecimal + 1))
$result : rgba-to-hex( rgba(192, 84, 84, 0.582))
#debug 'peter =='+$result
I didn't test the sass file i just remove the semicolon, '{' and '}'.
You could try #039B1580 but i believe this method doesn't work on all browsers
Warning: A non-numeric value encountered in /customers/1/2/3/websiteurl/httpd.www/wp-content/plugins/videonab/lib/plugin-classes/video.php on line 123,124,125
Code is (Line no 123,124,125)
public static function seconds_to_time( $seconds ){
$hours = floor($seconds / 3600); /* line no 123 */
$mins = floor(($seconds - ($hours*3600)) / 60);/* line no 124 */
$secs = floor($seconds % 60);/* line no 125 */
return array(
'hours' => $hours,
'minutes' => $mins,
'seconds' => $secs,
);
}
Please try to check for is_numeric or is_integer, and convert it to (int) before manipulating for any type of calculation.
public static function seconds_to_time( $seconds ) {
if( is_numeric( $seconds ) ) {
$hours = floor( (int)$seconds / 3600);
$mins = floor(( (int)$seconds - ($hours*3600)) / 60);
$secs = floor( (int)$seconds % 60);
return array(
'hours' => $hours,
'minutes' => $mins,
'seconds' => $secs,
);
} else {
return array();
}
}
Hope this one helps :)
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
}