Manipulate woocommerc price in cart - php

I try to manipulate the calculated price in cart but with no luck...
I hope someone can help me here.
I have found this article and implemented the code as written on the Page which is to 98% exactly what i searched for. I need to add a cart calculation if the price type is per 100g.
So this is the actual working code:
add_filter( 'woocommerce_get_price_html', 'wb_change_product_html', 10, 2 );
// Adding a custom field to the price markup
function wb_change_product_html( $price, $product ) {
//$wb_price_type = get_field('product_price_type');
$wb_price_type = get_post_meta( $product->get_id(), 'product_price_type', true);
if($wb_price_type) {
$price_html = '<span class="amount">' . $price . ' ' . $wb_price_type . '</span>';
}
else {
$price_html = '<span class="amount">' . $price . '</span>';
}
return $price_html;
}
add_filter( 'woocommerce_cart_item_price', 'wb_change_product_price_cart', 10, 3 );
// Adding a custom field to the price in the cart
function wb_change_product_price_cart( $price, $cart_item, $cart_item_key ) {
//$wb_price_type = get_field( 'product_price_type', $cart_item['product_id'] );
$wb_price_type = get_post_meta( $cart_item['product_id'], 'product_price_type', true );
if ($wb_price_type) {
$price = $price . ' ' . $wb_price_type;
}
else {
$price = $price;
}
return $price;
}
add_filter( 'woocommerce_checkout_cart_item_quantity', 'wb_checkout_review', 10, 3 );
// Adding a custom field to the price in the checkout items
function wb_checkout_review ( $quantity, $cart_item, $cart_item_key ) {
//$wb_price_type = get_field( 'product_price_type', $cart_item['product_id'] );
$wb_price_type = get_post_meta( $cart_item['product_id'], 'product_price_type', true);
if ( $wb_price_type ) {
$cart_item = ' ' . sprintf( '× %s ', $cart_item['quantity'] ) . $wb_price_type . '';
}
else {
$cart_item = ' ' . sprintf( '× %s', $cart_item['quantity'] ) . '';
}
return $cart_item;
}
Well i thought its really easy to calculate so i do something like this:
add_filter( 'woocommerce_cart_item_price', 'wb_change_product_price_cart', 10, 3 );
// Adding a custom field to the price in the cart
function wb_change_product_price_cart( $price, $cart_item, $cart_item_key ) {
//$wb_price_type = get_field( 'product_price_type', $cart_item['product_id'] );
$wb_price_type = get_post_meta( $cart_item['product_id'], 'product_price_type', true );
if ($wb_price_type) {
if ($wb_price_type == "per 100g") {
$price = $price / 100 . ' ' . $wb_price_type;
}
else {
$price = $price . ' ' . $wb_price_type;
}
}
else {
$price = $price;
}
return $price;
}
But this didnt work... i too try to manipulate the price directly but i get anytime 0 in the value of the price...
so i google a little bit more and found this article, which makes in the end exactly what i want. in the last print screen we can see that the price will displayed per kg (which is completely fine) and in the calculation it uses an other price (which i try to do with the code above).
i think that the problem is that $price has for example the value "20$" and this is a string and i cannot calculate withe a string. And it makes no sense to split this string there should be an other way.
For better understanding here a picture. in the upper part we see the working calculation (which is good) but this is not exactly what i need. in the part down we see that it will only calculate on the calculated price (right side). the left side of the downer part remain with the correct price.

i think that the problem is that $price has for example the value "20$" and this is a string and i cannot calculate withe a string. And it makes no sense to split this string there should be an other way.
This is true, it's actually a full html string. Try changing the woocommerce_cart_item_price filter to get the price out of string:
add_filter('woocommerce_cart_item_price', 'wb_change_product_price_cart', 10, 3);
// Adding a custom field to the price in the cart
function wb_change_product_price_cart($price, $cart_item, $cart_item_key)
{
$wb_price_type = get_post_meta($cart_item['product_id'], 'product_price_type', true);
if ($wb_price_type) {
if ($wb_price_type == "per 100g") {
preg_match("/([0-9]+\.[0-9]+)/", $price, $matches);
$_price = $matches[0];
$per100 = $_price / 100;
$price = $per100 . ' ' . $wb_price_type;
} else {
$price = $price . ' ' . $wb_price_type;
}
} else {
$price = $price;
}
return $price;
}

Related

Calculate tax in onsale badge amount

I would need your help, if there is someone willing to help me, I would greatly appreciate it. In my website prices include a 10.0000% tax.
I want to calculate in my onsale badge my tax from woocommerce which is of 10.0000%. This is my code:
Badge: onsale badge from site
add_filter( 'woocommerce_sale_flash', 'add_amount_to_sale_badge', 20, 3 );
function add_amount_to_sale_badge( $html, $post, $product ) {
if( $product->is_type('variable')){
$amount_off = array();
$prices = $product->get_variation_prices();
foreach( $prices['price'] as $key => $price ){
if( $prices['regular_price'][$key] !== $price ){
$amount_off[] = $prices['regular_price'][$key] - $prices['sale_price'][$key];
}
}
$amount_off_s = "up to -$" . round(max($amount_off));
} else {
$regular_price = (float) $product->get_regular_price();
$sale_price = (float) $product->get_sale_price();
$amount_off_s = "-$" . ($regular_price - $sale_price);
}
return '<span class="onsale">' . esc_html__( 'Save', 'woocommerce' ) . ' ' . $amount_off_s . '</span>';
}
my knowledge in php is limited and for this reason I am unable to solve this problem.

How to add next available date in stock WooCommerce

I have this code that's suppose to add a next available date in stock when out of stock. I added the field using custom fields.
add_filter( 'woocommerce_get_availability_text', 'filter_product_availability_text', 10, 2);
function filter_product_availability_text( $availability, $product ) {
$date_of_availability = get_post_meta( get_the_ID(), 'date_of_availability', true );
if ( ! $product->is_in_stock() && ! empty($date_of_availability) ) {
$availability .= '<span style="color:#e2401c;"><strong>- (' . __('Available from:', 'flatsome') . ' </strong>' . get_post_meta( get_the_ID(), 'date_of_availability', true ) . '!important' . ')</span>';
}
return $availability;
}
custom fields
Could someone help me ?
The end goal is to have a field in the product with a date, when out of stock is reached it needs to print that line out with the field value
If I however place it like this:
add_filter( 'woocommerce_get_availability_text', 'filter_product_availability_text', 10, 2);
function filter_product_availability_text( $availability, $product ) {
$date_of_availability = get_post_meta( get_the_ID(), 'date_of_availability', true );
if ( ! $product->is_in_stock() && ! empty($date_of_availability) ) {
$availability .= '<span style="color:#e2401c;"><strong>- (' . __('Available from:', 'flatsome') . ' </strong>' . get_post_meta( get_the_ID(), 'date_of_availability', true ) . ')</span>';
echo $availability
}
// return $availability;
}
Then it works however for some reason it repeats, like this:
repeating
Also if enabled it leaves an In stock label on every product despite being disabled
The reason your function appears to output twice is that you are echoing the $availability value without modifying or ceasing return output of woocommerce_get_availability text.
The following should work, as it works on Storefront theme:
function filter_product_availability_text( $availability, $product ) {
$date_of_availability = $product->get_meta( 'date_of_availability' );
if ( ! $product->is_in_stock() && $date_of_availability ) {
$availability .= '- Available from: ';
$availability .= $date_of_availability ;
}
return $availability;
}
add_filter( 'woocommerce_get_availability_text', 'filter_product_availability_text', 10, 2);
However, if the above fails, you can output with an action hook. In your case, the filter may be failing because of something Bacola developers chose to do with their code. This should output regardless:
function filter_product_availability_text() {
global $product;
$availability = '';
$date_of_availability = $product->get_meta( 'date_of_availability' );
if ( ! $product->is_in_stock() && $date_of_availability ) {
$availability = '<div class="product-meta date-of-avail"><p>Available from: '. $date_of_availability .'</p></div>';
}
echo $availability;
}
add_action( 'woocommerce_single_product_summary', 'filter_product_availability_text' );
Add to your CSS file:
.product-meta p {
color: #F00;
}
You need to comment:
echo $availability
Code snippets:
add_filter( 'woocommerce_get_availability_text', 'filter_product_availability_text', 10, 2);
function filter_product_availability_text( $availability, $product ) {
$date_of_availability = '17-05-2022'; // Your custom data
if ( ! $product->is_in_stock() && ! empty($date_of_availability) ) {
$availability .= '<span style="color:#e2401c;"><strong>- (' . __('Available from:', 'flatsome') . ' </strong>' . $date_of_availability . ')</span>';
//echo $availability
}
return $availability;
}
enter image description here
Alternatively, there’s also a built-in setting for this under WooCommerce > Settings > Products > Inventory — you can set when it should be considered “low stock”, and then display a message:
enter image description here
You could change the wording of the message by using a free translation plugin like Loco Translate ( https://wordpress.org/plugins/loco-translate/ ).

Custom formatted min price including tax for specific WooCommerce Variable Product

I'm trying to change the price for a specific product so that it shows the price with VAT (as opposed to other products where the price is shown without VAT)
I have managed to get this to work with the variable products themselves, by using the following code from https://tomjesch.com/display-woocommerce-products-with-and-without-tax/
function edit_selected_variation_price( $data, $product, $variation ) {
if(is_singular('product') && $product->get_id() == 68719 ) {
$price = $variation->price;
$price_incl_tax = $price + round($price * ( 20 / 100 ), 2);
$price_incl_tax = number_format($price_incl_tax, 2, ",", ".");
$price = number_format($price, 2, ",", ".");
$display_price = '<span class="price">';
$display_price .= '<span class="amount">£ ' . $price_incl_tax .'<small class="woocommerce-price-suffix"> incl VAT</small></span>';
$display_price .= '</span>';
$data['price_html'] = $display_price;
}
return $data;
}
add_filter( 'woocommerce_available_variation', 'edit_selected_variation_price', 10, 3);
This works when an option is chosen. However, before an option is chosen, there is a price that says FROM: £xxx which I now also want to change to say "FROM: £xxx inc VAT"
However, I can't seem to do anything to change it. So I have added the following to setup the html for the price:
function cw_change_product_html( $price_html, $product ) {
if ( $product->get_id() == 68719 ) {
$price_incl_tax = $product->price + round($price * ( 20 / 100 ), 2);
$price_incl_tax = number_format($price_incl_tax, 2, ",", ".");
$price_html = '<span class="amount">From ' . $price_incl_tax . 'incl VAT</span>';
}
echo $price_html;
}
And then I tried using these three different hooks.
add_filter( 'woocommerce_get_price_html_from_to', 'cw_change_product_html', 10, 2 );
add_filter( 'woocommerce_get_price_html', 'cw_change_product_html', 10, 2 );
add_filter('woocommerce_variable_price_html', 'cw_change_product_html', 10, 2);
Only the second one seems to trigger the code but then it outputs all of the prices for all the different variants.
Do I need to use a different hook or is there a way I can run the above code once?
There are some mistakes in your code. woocommerce_variable_price_html is best hook to be used. Also instead of using custom tax calculations, you can use WC_Tax methods to get dynamically the tax amount. Finally wc_price() is the formatted price function to be used in WooCommerce.
The code:
add_filter( 'woocommerce_variable_price_html', 'filter_wc_variable_price_html', 10, 2 );
function filter_wc_variable_price_html( $price_html, $product ) {
// only for variable product 68719
if( $product->get_id() != 68719 )
return $price_html;
$min_price = $product->get_variation_price( 'min' );
$tax_rates = WC_Tax::get_rates( $product->get_tax_class() );
$taxes = WC_Tax::calc_tax( $min_price, $tax_rates, false );
return sprintf(
__( 'From %s %s', 'woocommerce' ),
wc_price( $min_price + array_sum( $taxes ) ),
'<small class="woocommerce-price-suffix">' . __( 'incl VAT', 'woocommerce' ) . '</small>'
);
}
As your other code is a bit outdated and complicated, you can try the following instead:
add_filter( 'woocommerce_available_variation', 'filter_wc_available_variation_price_html', 10, 3);
function filter_wc_available_variation_price_html( $data, $product, $variation ) {
// only for variable product 68719
if( $product->get_id() != 68719 )
return $data;
$price = $data['display_price'];
$tax_rates = WC_Tax::get_rates( $variation->get_tax_class() );
$taxes = WC_Tax::calc_tax( $price, $tax_rates, false );
$data['price_html'] = sprintf( '%s %s',
wc_price( $price + array_sum( $taxes ) ),
'<small class="woocommerce-price-suffix">' . __( 'incl VAT', 'woocommerce' ) . '</small>'
);
return $data;
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
You are calling the right hook (woocommerce_get_price_html) but there are several flaws in your code.
Lets address your problem of running the code only for the price display at the top. Make sure the id you are checking for is the parent id.
Don't access values of the product object directly. WooCommerce provides getter functions for a lot of data. So instead use $product->get_price().
You have an undefined variable $price which will crash your code.
You can retrieve the tax percentage of the parent product, instead of hard coding it into the calculation in your function.
You can use the wc_price() function to output a formatted price.
The final code should look something like this:
add_filter( 'woocommerce_get_price_html', 'cw_change_product_html', 10, 2 );
function cw_change_product_html( $price_html, $product ) {
if ( $product->get_id() == 68719 ) {
$tax_rates = WC_Tax::get_rates( $product->get_tax_class() );
//Check the product tax rate of parent
if ( !empty( $tax_rates ) ) {
$tax_rate = reset($tax_rates);
$price_incl_tax = $product->get_price() + ( $product->get_price() * $tax_rate['rate'] / 100 );
$price_html = sprintf( 'From %s incl VAT', wc_price( $price_incl_tax, array( 'currency' => get_woocommerce_currency() ) ) );
}
}
return $price_html;
}

Display tax amount based on specific tax class in WooCommerce variations

I'm currently using a custom function to target a specific product and change the output of the price with and without tax on the product page.
This currently works as intended for an individual product id, however trying to get this work for a specific tax_class instead with no avail
add_filter( 'woocommerce_available_variation', 'tax_variation', 10, 3);
function tax_variation( $data, $product, $variation ) {
$product = wc_get_product();
$id = $product->get_id();
$price_excl_tax = wc_get_price_excluding_tax( $variation ); // price without VAT
$price_incl_tax = wc_get_price_including_tax( $variation ); // price with VAT
$tax_amount = $price_incl_tax - $price_excl_tax; // VAT amount
if ( $id == 113576 ) {
$data['price_html'] = "<span class='ex-vat-price'>Price: <b>" . woocommerce_price($variation->get_price_excluding_tax()) . "</b></span><br>";
$data['price_html'] .= "<span class='tax_amount'>Sales Tax 13%: <b>" . woocommerce_price($tax_amount) . "</b></span><br>";
$data['price_html'] .= "<span class='inc-vat-price'>Total: <b>" . woocommerce_price($variation->get_price_including_tax()) . "</b></span>";
return $data;
} else {
$data['price_html'] .= "<span class='regular-price'> " . woocommerce_price($variation->get_price()) . "</span>";
return $data;
}
}
i want to change the if parameter to
$taxclass = $product->get_tax_class();
if ( $taxclass == 'costa-rate' ) {
but currently this does not function correctly and displays the regular price data twice
Since WooCommerce 3, your code is outdated and with some errors.
I guess that you are using woocommerce_available_variation action hook.
Try the following instead:
add_filter( 'woocommerce_available_variation', 'custom_variation_price', 10, 3 );
function custom_variation_price( $data, $product, $variation ) {
$price_excl_tax = (float) wc_get_price_excluding_tax( $variation ); // price without VAT
$price_incl_tax = (float) wc_get_price_including_tax( $variation ); // price with VAT
$tax_amount = $price_incl_tax - $price_excl_tax;
if( $variation->get_tax_class() === 'costa-rate' ) {
$data['price_html'] = '<span class="ex-vat-price">' . __("Price:") . ' <strong>' . wc_price($price_excl_tax) . '</strong></span><br>
<span class="tax_amount">' . __("Sales Tax 13%:") . ' <strong>' . wc_price($tax_amount) . '</strong></span><br>
<span class="inc-vat-price">' . __("Total:") . ' <strong>' . wc_price($price_incl_tax) . '</strong></span>';
} else {
$data['price_html'] .= '<span class="regular-price"> ' . wc_price( wc_get_price_to_display( $variation ) ) . '</span>';
}
return $data;
}
Code goes in functions.php file of your active child theme (or active theme). It should better works.

Displaying prices without tax only in certain product categories

The product category is "Machines"
My website is: "https://www.floorcare-supplies.co.uk/product-category/machines/"
I'm looking to be able to display the products in this category specifically without the tax on the shop front.
I've managed to do it when on the products for example:
£1,342
£1123 Ex vat
But on the shop store, I need the main price to display the total without tax for that specific category.
Use this code:
/**
* Function that will check for category id and turn off VAT/tax
*/
function wc_diff_rate_for_cat() {
if (is_product_category ('machines')) {
// set the machines category to have no VAT
WC()->customer->is_vat_exempt = true;
}
}
add_action( 'template_redirect', 'wc_diff_rate_for_cat', 1 );
/**
* Function that filters the variable product hash based on category
*/
function wc_get_variation_prices_hash_filter( $hash, $item, $display ) {
// check for the "machines" category
if (is_product_category ('machines')) {
// clear key 2, which is where taxes are
$hash['2'] = array();
}
// return the hash
return $hash;
}
add_filter( 'woocommerce_get_variation_prices_hash', 'wc_get_variation_prices_hash_filter', 1, 3 );
/**
* Function that removes the price suffix (inc. Tax) from variable products based on category
*/
function wc_get_price_suffix_filter( $price_display_suffix, $item ) {
if (is_product_category ('machines')) {
// return blank if it matches
return '';
}
// return if unmatched
return $price_display_suffix;
}
add_filter( 'woocommerce_get_price_suffix', 'wc_get_price_suffix_filter', 10, 2 );
Solved
Solution
Modified Child theme to include
Woocommerce\includes\wc-template-functions.php
&
woocommerce\loop\price.php
Code added to
Woocommerce\includes\wc-template-functions.php
/**
* Get the product price for the loop.
*
* #subpackage Loop
*/
function woocommerce_template_loop_price() {
wc_get_template( 'loop/pricemod.php' );
}
Then modified pricemod.php
global $product;
$vat = "Ex vat ";
?>
<p class="price"><?php echo $product->get_price_html(); ?></p>
<p class="priceex"><?php echo woocommerce_price($product->get_price_excluding_tax()). ' ' . $vat; ?></p>
To display prices excluding tax only for your "Machines" product category, you should use a custom function hooked in wc_price filter hook, this way:
add_filter( 'wc_price', 'product_category_price_excl_tax', 10, 3 );
function product_category_price_excl_tax( $price_html, $price, $args ){
global $post;
// Price excluding taxes for "Machines" product category with corresponding label
if( has_term( 'Machines', 'product_cat', $post->ID ) ){
$decimal_separator = wc_get_price_decimal_separator();
$thousand_separator = wc_get_price_thousand_separator();
$decimals = wc_get_price_decimals();
$price_format = get_woocommerce_price_format();
$number_format = number_format( $price, $decimals, $decimal_separator, $thousand_separator );
$negative = $price < 0;
$currency = get_woocommerce_currency();
// Get an instance of the WC_Product object
$product = wc_get_product($post->ID);
// Get the product price excluding taxes
$price = wc_get_price_excluding_tax( $product, $price );
$price = apply_filters( 'raw_woocommerce_price', floatval( $negative ? $price * -1 : $price ) );
$price = apply_filters( 'formatted_woocommerce_price', $number_format, $price, $decimals, $decimal_separator, $thousand_separator );
if ( apply_filters( 'woocommerce_price_trim_zeros', false ) && $decimals > 0 )
$price = wc_trim_zeros( $price );
$formatted_price = ( $negative ? '-' : '' ) . sprintf( $price_format, '<span class="woocommerce-Price-currencySymbol">' . get_woocommerce_currency_symbol( $currency ) . '</span>', $price );
$price_html = '<span class="woocommerce-Price-amount amount">' . $formatted_price . '</span>';
if ( wc_tax_enabled() )
$price_html .= ' <small class="woocommerce-Price-taxLabel tax_label">' . WC()->countries->ex_tax_or_vat() . '</small>';
}
return $price_html;
}
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 for WooCommerce version 3+
Now, to display that prices only in "Machines" shop category archives pages, you will need to replace:
if( has_term( 'Machines', 'product_cat', $post->ID ) ){
by:
if( has_term( 'Machines', 'product_cat', $post->ID ) && is_product_category ('machines') ){

Categories