How to override Woocommerce wc_format_sale_price function properly? - woocommerce

I am struggling with this task and I could really use some help. First, before somebody marks this as an off-topic, I already did read all the questions and answers here and other sites as well. No luck.
I am trying to edit the HTML output of the wc_format_sale_price function located in wc-formatting-functions.php.
Original code is:
function wc_format_sale_price( $regular_price, $sale_price ) {
$price = '<del>' . ( is_numeric( $regular_price ) ? wc_price( $regular_price ) : $regular_price ) . '</del> <ins>' . ( is_numeric( $sale_price ) ? wc_price( $sale_price ) : $sale_price ) . '</ins>';
return apply_filters( 'woocommerce_format_sale_price', $price, $regular_price, $sale_price );
As you can see the prices are encapsulated in HTML elements <del> and <ins>.
I did tried to change the HTML directly and it works perfectly.
function wc_format_sale_price( $regular_price, $sale_price ) {
$price = '<div id="priceBefore" style="font-size: 16px;" class="old-price">' . ( is_numeric( $regular_price ) ? wc_price( $regular_price ) : $regular_price ) . '</div> <div id="priceAfter" style="font-size: 24px;" class="price">' . ( is_numeric( $sale_price ) ? wc_price( $sale_price ) : $sale_price ) . '</div>';
return apply_filters( 'woocommerce_format_sale_price', $price, $regular_price, $sale_price );
The thing is I don't want to change WC core files because it is a bad practice and the changes will be removed every time the shop owner updates the WC plugin.
After some research I am sure that this should be done using filters in my theme's functions.php file but all the tutorials and articles about this functionality are quite messy. I did tried to follow few of them and I ended up with blank page, duplicate prices and stuff like that.
I understand that filters and actions are alpha and omega of Wordpress/Woocommerce theme development but my attempts to make them work were all just failures.

I actually found out how to solve this issue.
I did some more research and I found out this answer on Stack Overflow: https://stackoverflow.com/a/45112008/6361752 where the user called LoicTheAztec pointed out that woocommerce_format_sale_price hook accepts three arguments. So i added $price as the third argument to my filter function and now it works.
Final solution which I put into my theme's functions.php file looks like this:
add_filter('woocommerce_format_sale_price', 'ss_format_sale_price', 100, 3);
function ss_format_sale_price( $price, $regular_price, $sale_price ) {
$output_ss_price = '<div id="priceBefore" style="font-size: 16px;" class="old-price">' . ( is_numeric( $regular_price ) ? wc_price( $regular_price ) : $regular_price ) . '</div> <div id="priceAfter" style="font-size: 24px;" class="price">' . ( is_numeric( $sale_price ) ? wc_price( $sale_price ) : $sale_price ) . '</div>';
return $output_ss_price;
}
I am posting this answer just to make sure no more time is wasted on such a simple thing.
There is only one more thing I would like to know. How is it possible that the original function uses just two arguments and works flawlessly when my filter function needs to accept three arguments to work properly? Any ideas?

Related

WooCommerce - Show regular price striked before the sale price in the add to cart button?

I would like to show the regular price before the discounted price in the add to cart button on the single product pages only.
Here's the code snippet I added to the functions.php file of my child theme:
add_filter( 'woocommerce_product_single_add_to_cart_text', 'woocommerce_custom_single_add_to_cart_text' );
function woocommerce_custom_single_add_to_cart_text() {
global $product;
$regular_price = woocommerce_price( $_product->get_regular_price() );
$sale_price = woocommerce_price( $_product->get_sale_price() );
return __( 'Add to cart' . $regular_price . $sale_price, 'woocommerce' );
}
This code is incorrect and crashes the website but I don't understand why. Can anyone help me fix it?
The code crashes because you use a variable $_product which is not defined inside your hook. Please try this code instead:
add_filter( 'woocommerce_product_single_add_to_cart_text', 'filter_woocommerce_product_single_add_to_cart_text' );
function filter_woocommerce_product_single_add_to_cart_text(): string {
global $product;
$regular_price = wc_price( $product->get_regular_price() );
$sale_price = wc_price( $product->get_sale_price() );
return __( 'Add to cart', 'woocommerce' ) . $regular_price . $sale_price;
}
I've fixed your variable name $_product to $product (as defined inside a global) and moved your price to text assignment outside the translation function. Also, I've preplaced the deprecated function woocommerce_price with wc_price.
This way, your code works but don't display the price correctly since this filter filters only the text as a string.
I think you need to check for a different hook to achieve your goal.

Free shipping label/badge/text for conditional price in WooCommerce product/archive page under price [duplicate]

I want to show a "free delivery" badge at every product with a price above 50$.
It should be visible on the product page and in the loop.
The problem is, that there could be more than one price. If you think about variations and sales (or even variations with variants on sale).
So I need to check the type of the product and have to search for the cheapest price to calculate with.
At the moment I'm using the following code.
It works ok sometimes. But on products with no active stock management it produces a timeout on the product page and doesn't work on archives (shows no message).
Also it produces some notices about not using the ID directly.
I don't feel safe with that code... Is there a better way to archieve it?
I tried a lot of ways but I'm not sure if I think about every possibilities about price, sales, stock or product types?!
<?php add_action( 'wgm_after_tax_display_single', 'wgm_after_tax_display_single_free_delivery', 10, 1 );
function wgm_after_tax_display_single_free_delivery( ) {
if (is_product()):
global $post, $product;
if ( ! $product->is_in_stock() ) return;
$sale_price = get_post_meta( $product->id, '_price', true);
$regular_price = get_post_meta( $product->id, '_regular_price', true);
if (empty($regular_price)){ //then this is a variable product
$available_variations = $product->get_available_variations();
$variation_id=$available_variations[0]['variation_id'];
$variation= new WC_Product_Variation( $variation_id );
$regular_price = $variation ->regular_price;
$sale_price = $variation ->sale_price;
}
if ( $sale_price >= 50 && !empty( $regular_price ) ) :
echo 'free delivery!';
else :
echo 'NO free delivery!';
endif;
endif;
} ?>
As you are using a custom hook, is difficult to test it for real (the same way as you)… Now this revisited code should work in a much better way than yours (solving error notices):
add_action( 'wgm_after_tax_display_single', 'wgm_after_tax_display_single_free_delivery', 10, 1 );
function wgm_after_tax_display_single_free_delivery() {
// On single product pages and archives pages
if ( is_product() || is_shop() || is_product_category() || is_product_tag() ):
global $post, $product;
if ( ! $product->is_in_stock() ) return;
// variable products (get min prices)
if ( $product->is_type('variable') ) {
$sale_price = $product->get_variation_sale_price('min');
$regular_price = $product->get_variation_regular_price('min');
}
// Other products types
else {
$sale_price = $product->get_sale_price();
$regular_price = $product->get_regular_price();
}
$price = $sale_price > 0 ? $sale_price : $regular_price;
if ( $price >= 50 ) {
echo __('free delivery!');
} else {
echo __('NO free delivery!');
}
endif;
}
Code goes in function.php file of your active child theme (or active theme). It should work better.

how to change woocommerce shop page details?

I've used a snippet to display the weight of jewellery in shop page of woocommerce. I've inserted the snippet in function.php file. But its displaying the weight below add to cart button. It must be displayed above the button.
here is the snippet
add_action( 'woocommerce_after_shop_loop_item', 'bbloomer_show_product_dimensions_loop', 20 );
function bbloomer_show_product_dimensions_loop() {
global $product;
$dimensions = $product->get_dimensions();
if ( ! empty( $dimensions ) ) {
echo '<div class="dimensions">';
echo '<br><b>Weight:</b> ' . $product->get_weight() . get_option( 'woocommerce_weight_unit' );
echo '</div>';
}
}
the weight must be printed above the add to cart button, what i've to change here.
add_filter( 'woocommerce_loop_add_to_cart_link', 'bbloomer_show_product_dimensions_loop', 10, 2 );
function bbloomer_show_product_dimensions_loop( $html, $product ) {
$weight = '';
$dimensions = $product->get_dimensions();
if ( ! empty( $dimensions ) ) {
$weight .= '<div class="dimensions">';
$weight .= '<br><b>Weight:</b> ' . $product->get_weight() .
esc_html( get_option( 'woocommerce_weight_unit' ) );
$weight .= '</div>';
}
return $weight . $html;
}
You have to use the filter tag woocommerce_loop_add_to_cart_link and prepend your weight component HTML like this. Since it's filter hook no need to echo the output just return the output HTML the tag woocommerce_loop_add_to_cart_link will handle that.
Based on my own blog tutorial: How To Add Quantity Input In Shop Page
Visit source code if you want to learn how this filter woocommerce_loop_add_to_cart_link works internally.
You can take the help of flex css for example:
.itemxyz{display: flex;flex-direction: column;}
.itemxyz .desc{order: 1;}
.itemxyz .price{order: 2;}
.itemxyz .btn{ order: 4;}
.itemxyz .weight{ order: 3;}

Woo REST API output sale price wrong [duplicate]

This question already has answers here:
Set product sale price programmatically in WooCommerce 3
(3 answers)
Closed 2 years ago.
I'm in big trouble, because on live site I just discovered that our API put strange output and due to that can not sync products with our ERP and CRM. I think the problem is in this piece of code but I can not figure out how to keep it because it works on frotnend but exclude it from API Json output?
//PROCENT SPARET PÅ SIMPLE PRODUCT
add_filter( 'woocommerce_format_sale_price', 'woocommerce_custom_sales_price', 10, 3 );
function woocommerce_custom_sales_price( $price, $regular_price, $sale_price ) {
// Getting the clean numeric prices (without html and currency)
$_reg_price = floatval( strip_tags($regular_price) );
$_sale_price = floatval( strip_tags($sale_price) );
// Percentage calculation and text
$percentage = round( ( $_reg_price - $_sale_price ) / $_reg_price * 100 ).'%';
$percentage_txt = '(' . __('-', 'woocommerce' ) . $percentage . ')';
$formatted_regular_price = is_numeric( $regular_price ) ? wc_price( $regular_price ) : $regular_price;
$formatted_sale_price = is_numeric( $sale_price ) ? wc_price( $sale_price ) : $sale_price;
echo '<del>' . $formatted_regular_price . '</del> <ins>' . $formatted_sale_price ."<span class='percentage_save'>". $percentage_txt . "</span>".'</ins>';
}
And problem in output is visible here
Does anybody have idea how to quickly fix that? Thanks in advance
/* you can user this hook function for above issue */
add_filter('woocommerce_product_get_sale_price', 'custom_price_func', 10, 2 );
function custom_price_func( $price, $product){
/* write your stuff here */
return $price;
}

How to show Product Price + Shipping VAT in "Total" Merged

I have one little isusue that dont know how to resolve myself. I have set in my shop to show separated Price and shipping costs but in total showed me bad price.
For example my products cost 24.99€ + SHIPPING FEE : 3,95€ = 28.94€ but in calculation in cart page is calculating: 24.99€ + 3.95€ - 0.26€ what is wrong.
i found that Total price is calculated via this function:
<td data-title="<?php esc_attr_e( 'Total', 'woocommerce' ); ?>"><?php wc_cart_totals_order_total_html(); ?></td>
and this is function that control that part:
from cart-totals.php in templates, and bellow is function from wc-cart-functions.php
function wc_cart_totals_order_total_html() {
$value = '<strong>' . WC()->cart->get_total() . '</strong> ';
// If prices are tax inclusive, show taxes here.
if ( wc_tax_enabled() && WC()->cart->display_prices_including_tax() ) {
$tax_string_array = array();
$cart_tax_totals = WC()->cart->get_tax_totals();
if ( get_option( 'woocommerce_tax_total_display' ) == 'itemized' ) {
foreach ( $cart_tax_totals as $code => $tax ) {
$tax_string_array[] = sprintf( '%s %s', $tax->formatted_amount, $tax->label );
}
} elseif ( ! empty( $cart_tax_totals ) ) {
$tax_string_array[] = sprintf( '%s %s', wc_price( WC()->cart->get_taxes_total( true, true ) ), WC()->countries->tax_or_vat() );
}
if ( ! empty( $tax_string_array ) ) {
$taxable_address = WC()->customer->get_taxable_address();
$estimated_text = WC()->customer->is_customer_outside_base() && ! WC()->customer->has_calculated_shipping()
? sprintf( ' ' . __( 'estimated for %s', 'woocommerce' ), WC()->countries->estimated_for_prefix( $taxable_address[0] ) . WC()->countries->countries[ $taxable_address[0] ] )
: '';
$value .= '<small class="includes_tax">' . sprintf( __( '(includes %s)', 'woocommerce' ), implode( ', ', $tax_string_array ) . $estimated_text ) . '</small>';
}
}
echo apply_filters( 'woocommerce_cart_totals_order_total_html', $value );
}
So my question is how to add that 1.63E at Total Price, so will get correct price. Thanks
EDIT: Found the same problem like mine here but answers dont seems to make changes.
First, thanks for your Post, I was almost thinking I'm the only one with this need.
So far, this worked for my shop. I'm shure my code is not very versatile for different shop settings. Maybe someone could make a more general usable version.
Edit: I've added a picture showing the two rates. Image of the result and I've found a minor mistake calculating the shipping tax, corrected now.
/**
* Change Tax Amount including Shipping Taxes
* Referencing to wc-cart-functions.php starting from Line 296
*
*/
add_filter( 'woocommerce_cart_totals_order_total_html', 'woo_rename_tax_inc_cart', 10, 1 );
function woo_rename_tax_inc_cart( $value ) {
/* Get all infos needed */
$shipping_total = WC()->cart->shipping_total;
$taxes = WC()->cart->get_taxes_total( true, true );
$taxrate = 7.7;
$newtaxes = ($shipping_total/(100+$taxrate)*$taxrate) + $taxes; // Shipping is 100% + taxrate %, so we deduct both percentages.
/* Check if Shipment total is active */
if ( ! empty($shipping_total) && $shipping_total != 0 ) {
if ( ! empty( $value ) ) {
// Show Price /wc-cart-functions.php Line 297
$value = '<strong>' . WC()->cart->get_total() . '</strong> ';
$value .= '<small class="includes_tax">' . '(inkl. ' . wc_price( $newtaxes ) . ' MWST)' . '</small>';
}
}
// Attach Tax Info to Price (single line)
$value = str_ireplace( 'Tax', 'GST', $value );
return $value;
}

Resources