We have added second price for variable products with this code and it works just fine.
// Backend Variation - Add / Display MRSP Field
add_action( 'woocommerce_variation_options_pricing', 'add_variation_options_pricing_msrp', 10, 3 );
function add_variation_options_pricing_msrp( $loop, $variation_data, $variation ){
woocommerce_wp_text_input( array(
'id' => '_msrp_'.$loop,
'wrapper_class' => 'form-row form-row-first',
'class' => 'short wc_input_price',
'label' => __( 'Цена за комплект', 'woocommerce' ) . ' (' . get_woocommerce_currency_symbol() . ')',
'value' => wc_format_localized_price( get_post_meta( $variation->ID, '_msrp', true ) ),
'data_type' => 'price',
) );
}
// Backend Variation - Save MRSP Field value
add_action( 'woocommerce_save_product_variation','save_variation_options_pricing_msrp',10 ,2 );
function save_variation_options_pricing_msrp( $variation_id, $loop ){
if( isset($_POST['_msrp_'.$loop]) )
update_post_meta( $variation_id, '_msrp', wc_clean( wp_unslash( str_replace( ',', '.', $_POST['_msrp_'.$loop] ) ) ) );
}
// Frontend Variation - MRSP display
add_filter( 'woocommerce_available_variation', 'display_variation_msrp', 10, 3 );
function display_variation_msrp( $data, $product, $variation ) {
if( $msrp = $variation->get_meta('_msrp') ) {
$data['price_html'] = '<div class="woocommerce_msrp">' . __( 'Комплект: ', 'woocommerce' ) .
'<span class="msrp-price">' . wc_price( $msrp ) . '</span></div>' . $data['price_html'];
}
return $data;
}
On frontend it looks like this (when colour is selected):
This is how it looks on frontend
Now we need a little modification and I dont know how to do it:
I need to add small text before price (on screenshot its 87.18p.) The same as it is on the top price.
I need to move top price to bottom and to move bottom price to top.
I believe that I need to add some code (similar to this):
// Frontend Variation - MRSP display
add_filter( 'woocommerce_available_variation', 'display_variation_msrp', 10, 3 );
function display_variation_msrp( $data, $product, $variation ) {
if( $msrp = $variation->get_meta('_msrp') ) {
$data['price_html'] = '<div class="woocommerce_msrp">' . __( 'Комплект: ', 'woocommerce' ) .
'<span class="msrp-price">' . wc_price( $msrp ) . '</span></div>' . $data['price_html'];
}
return $data;
But I'm not a programmer...
I would appreciate any help on this, thank you.
Firs since your not a programmer I explane whats happening using command lines in your the code:
// Frontend Variation - MRSP display
add_filter( 'woocommerce_available_variation', 'display_variation_msrp', 10, 3 );
function display_variation_msrp( $data, $product, $variation ) {
if( $msrp = $variation->get_meta('_msrp') ) {
$data['price_html'] = '
<div class="woocommerce_msrp">' //wrapper box
. __( 'Комплект: ', 'woocommerce' ) //This is a wil prinnt a label with the text 'Комплект'
.'<span class="msrp-price">' // html label
. wc_price( $msrp )// your new price
. '</span>'//end html label
.'</div>' //end wrapper
. $data['price_html']; // default price of product
}
return $data;
}
Then for adding a symbol before your price you simply add the sybol to the span, like this:
add_filter( 'woocommerce_available_variation', 'display_variation_msrp', 10, 3 );
function display_variation_msrp( $data, $product, $variation ) {
if( $msrp = $variation->get_meta('_msrp') ) {
$data['price_html'] = '
<div class="woocommerce_msrp">' //wrapper box
. __( 'Комплект: ', 'woocommerce' ) //This is a wil prinnt a label with the text 'Комплект'
.'<span class="msrp-price"> ------SYMBOL HERE----- ' // html label and symbol
. wc_price( $msrp )// your new price
. '</span>'//end html label
.'</div>' //end wrapper
. $data['price_html']; // default price of product
}
return $data;
}
Then finaly switching the prices is done by switching them in the code. So your finel product will look like this:
// Frontend Variation - MRSP display
add_filter( 'woocommerce_available_variation', 'display_variation_msrp', 10, 3 );
function display_variation_msrp( $data, $product, $variation ) {
if( $msrp = $variation->get_meta('_msrp') ) {
$data['price_html'] =
$data['price_html'] // default price of product
.'<div class="woocommerce_msrp">' //wrapper box
. __( 'Комплект: ', 'woocommerce' ) //This is a wil prinnt a label with the text 'Комплект'
.'<span class="msrp-price"> ------SYMBOL HERE----- ' // html label and symbol
. wc_price( $msrp )// your new price
. '</span>'//end html label
.'</div>'; //end wrapper
}
return $data;
}
Hope this wil help you and understand what's going on :-) !
Related
I'm trying to show variation custom price-span from X-X.
The lowest price comes from (multiple) custom field values, I need to use the lowest value.
The highest price should be variation max price.
I only want this if the variation has the bulk_price value, and only show it in archives pages. I need to get the custom field value, and the price max.
I'm working from:
"How can I get Min and Max price of a woocommerce variable product in Custom loop?"
and
"WooCommerce: Get custom field from product variations and display it as a suffix to variation prices"
This is what I have:
function change_product_price_display( $price) {
$bulk_price = get_post_meta([ 'variation_id' ], 'bulk_price', true);
$priceMax = $product->get_variation_price('max'); // Max price
//only show in archives
if (is_product_category()) {
//only if there is a bulk price
if ( $bulk_price ) {
return ' <span class="price-suffix">' . ' From ' . get_woocommerce_currency_symbol() .__( $bulk_price , "woocommerce") . ' - ' . $priceMax . '</span>';
}
}
//don't affect other products
else {
return $price;
}
}
add_filter( 'woocommerce_get_price_html', 'change_product_price_display');
add_filter( 'woocommerce_cart_item_price', 'change_product_price_display');
Display on product category archive lowest value (custom field) to max price.
Comment with explanation added to the code
// Display on product category archive lowest value to max price
function change_product_price_display( $price, $product ) {
// Returns true when viewing a product category archive.
if ( is_product_category() ) {
// Set array
$bulk_prices = array();
// Loop for variations IDs
foreach( $product->get_children() as $variation_id ) {
// Get post meta
$bulk_price = get_post_meta($variation_id, 'bulk_price', true);
// True
if( $bulk_price ) {
// Push
$bulk_prices[] = $bulk_price;
}
}
// NOT empty
if( sizeof($bulk_prices) > 0 ) {
// Sort: low to high
sort($bulk_prices);
// First value
$lowest_value = reset( $bulk_prices );
// Get max price
$price_max = $product->get_variation_price('max');
// Output
$price = '<span class="price-suffix">From ' . get_woocommerce_currency_symbol() . $lowest_value . ' - ' . wc_price($price_max) . '</span>';
}
}
return $price;
}
add_filter( 'woocommerce_variable_price_html', 'change_product_price_display', 10, 2 );
For clarity, the code for creating and saving the custom fields
// Add custom field input product variations
function action_woocommerce_variation_options_pricing( $loop, $variation_data, $variation ) {
woocommerce_wp_text_input( array(
'id' => 'bulk_price[' . $loop . ']',
'desc_tip' => 'true',
'description' => __( 'Enter the Bulk price here.', 'woocommerce' ),
'label' => __( 'Custom Field', 'woocommerce' ),
'value' => get_post_meta( $variation->ID, 'bulk_price', true )
));
}
add_action( 'woocommerce_variation_options_pricing', 'action_woocommerce_variation_options_pricing', 10, 3 );
// Save custom field on product variation save
function action_woocommerce_save_product_variation( $variation_id, $i ) {
$bulk_price = $_POST['bulk_price'][$i];
if ( isset( $bulk_price ) ) {
update_post_meta( $variation_id, 'bulk_price', esc_attr( $bulk_price ) );
}
}
add_action( 'woocommerce_save_product_variation', 'action_woocommerce_save_product_variation', 10, 2 );
Based on "Add a checkbox on single product pages that adds an additional cost in Woocommerce" answer code, I am trying to add an "extra warranty" option to my products (checkbox in product page):
/*
* add warrenty
*/
// Backend: Additional pricing option custom field
add_action( 'woocommerce_product_options_pricing', 'wc_cost_product_field' );
function wc_cost_product_field() {
woocommerce_wp_text_input( array(
'id' => '_warrenty_price',
'class' => 'wc_input_price short',
'label' => __( 'Warrenty', 'woocommerce' ) . ' (' . get_woocommerce_currency_symbol() . ')'
));
}
// Backend: Saving product pricing option custom field value
add_action( 'woocommerce_admin_process_product_object', 'save_product_custom_meta_data', 100, 1 );
function save_product_custom_meta_data( $product ){
if ( isset( $_POST['_warrenty_price'] ) )
$product->update_meta_data( '_warrenty_price', sanitize_text_field($_POST['_warrenty_price']) );
}
// Front: Add a text input field inside the add to cart form on single product page
add_action('woocommerce_single_product_summary','add_warrenty_price_option_to_single_product', 2 );
function add_warrenty_price_option_to_single_product(){
global $product;
if( $product->is_type('variable') || ! $product->get_meta( '_warrenty_price' ) ) return;
add_action('woocommerce_before_add_to_cart_button', 'product_option_custom_field', 30 );
}
function product_option_custom_field(){
global $product;
$active_price = (float) $product->get_price();
$warrenty_price = (float) $product->get_meta( '_warrenty_price' );
$warrenty_price_html = strip_tags( wc_price( wc_get_price_to_display( $product, array('price' => $warrenty_price ) ) ) );
$active_price_html = wc_price( wc_get_price_to_display( $product ) );
$disp_price_sum_html = wc_price( wc_get_price_to_display( $product, array('price' => $active_price + $warrenty_price ) ) );
echo '<div class="hidden-field">
<p class="form-row form-row-wide" id="warrenty_option_field" data-priority="">
<span class="woocommerce-input-wrapper"><span class="war-title"> ' . __("Warrenty price:", "Woocommerce") .
'</span><label class="checkbox"><input type="checkbox" class="input-checkbox " name="warrenty_option" id="warrenty_option" value="1"> Add Warrenty for ' . $warrenty_price_html .
'</label></span></p>
<input type="hidden" name="warrenty_price" value="' . $warrenty_price . '">
<input type="hidden" name="active_price" value="' . $active_price . '"></div>';
// Jquery: Update displayed price
?>
<script type="text/javascript">
jQuery(function($) {
var cb = 'input[name="warrenty_option"]'
pp = 'p.price';
// On change / select a variation
$('form.cart').on( 'change', cb, function(){
if( $(cb).prop('checked') === true )
$(pp).html('<?php echo $disp_price_sum_html; ?>');
else
$(pp).html('<?php echo $active_price_html; ?>');
})
});
</script>
<?php
}
// Front: Calculate new item price and add it as custom cart item data
add_filter('woocommerce_add_cart_item_data', 'add_custom_product_data', 10, 3);
function add_custom_product_data( $cart_item_data, $product_id, $variation_id ) {
if (isset($_POST['warrenty_option']) && !empty($_POST['warrenty_option'])) {
$cart_item_data['new_price'] = (float) ($_POST['active_price'] + $_POST['warrenty_price']);
$cart_item_data['warrenty_price'] = (float) $_POST['warrenty_price'];
$cart_item_data['active_price'] = (float) $_POST['active_price'];
$cart_item_data['unique_key'] = md5(microtime().rand());
}
return $cart_item_data;
}
// Front: Set the new calculated cart item price
add_action('woocommerce_before_calculate_totals', 'extra_price_add_custom_price', 20, 1);
function extra_price_add_custom_price($cart) {
if (is_admin() && !defined('DOING_AJAX'))
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
foreach($cart->get_cart() as $cart_item) {
if (isset($cart_item['new_price']))
$cart_item['data']->set_price((float) $cart_item['new_price']);
}
}
// Front: Display option in cart item
add_filter('woocommerce_get_item_data', 'display_custom_item_data', 10, 2);
function display_custom_item_data($cart_item_data, $cart_item) {
if (isset($cart_item['warrenty_price'])) {
$cart_item_data[] = array(
'name' => __("Extra Warrenty", "woocommerce"),
'value' => strip_tags( '+ ' . wc_price( wc_get_price_to_display( $cart_item['data'], array('price' => $cart_item['warrenty_price'] ) ) ) )
);
}
return $cart_item_data;
}
It's work fine and the price is calculated in the payment.
The problem is that the field value doesn't appear in the order details table (and email notifications). So I don't have a way to know if the customer paid for the warranty or not (except calculated the final price of the product).
What should I add to the code so that the field will appear in the order details and mails?
You just need this little peace of code to display this warranty option everywhere:
// Save warranty as order item custom meta data and display it everywhere
add_action('woocommerce_checkout_create_order_line_item', 'save_order_item_product_warranty', 10, 4 );
function save_order_item_product_warranty( $item, $cart_item_key, $values, $order ) {
if( isset($values['warrenty_price']) && $values['warrenty_price'] > 0 ) {
$key = __("Extra Warrenty", "woocommerce");
$value = strip_tags( '+ '. wc_price( wc_get_price_to_display( $values['data'], array('price' => $values['warrenty_price']) ) ) );
$item->update_meta_data( $key, $value );
}
}
Code goes in function.php file of your active child theme (or active theme). tested and works.
In order received page (and all other order pages):
In admin order pages:
In email notifications:
add_action( 'woocommerce_admin_order_data_after_order_details', 'warrenty_price_order_meta_general' );
function warrenty_price_order_meta_general( $order ){ ?>
<br class="clear" />
<h4>Gift Order Edit</h4>
<?php
/*
* get all the meta data values we need
*/
$_warrenty_price = get_post_meta( $order->get_id(), '_warrenty_price', true );
?>
<div class="address">
<p><strong>Warranty</strong></p>
<?php
if( $_warrenty_price ) :
?>
<p><strong>Price:</strong> <?php echo $_warrenty_price ?></p>
<?php
endif;
?>
</div>
<?php } ?>
For Email
add_action('woocommerce_email_order_meta', 'warrenty_price_email_order_meta', 10, 3);
function warrenty_price_email_order_meta($order_obj, $sent_to_admin, $plain_text) {
$warrenty_price = get_post_meta($order_obj->get_id(), '_warrenty_price', true);
if (empty($warrenty_price))
return;
if ($plain_text === false) {
echo '<h2>Warranty</h2>
<ul>
<li><strong>Price:</strong> ' . $warrenty_price . '</li>
</ul>';
} else {
echo "Warranty\n
Price: $warrenty_price";
}
}
In woocommerce, I am using the following code to display an input text field on admin product edit pages, that allow me to add an additonal pricing option to the product:
add_action( 'woocommerce_product_options_pricing', 'wc_cost_product_field' );
function wc_cost_product_field() {
woocommerce_wp_text_input( array( 'id' => 'repair_price', 'class' => 'wc_input_price short', 'label' => __( 'Repair Cost', 'woocommerce' ) . ' (' . get_woocommerce_currency_symbol() . ')' ) );
}
add_action( 'save_post', 'wc_cost_save_product' );
function wc_cost_save_product( $product_id ) {
// stop the quick edit interferring as this will stop it saving properly, when a user uses quick edit feature
if (wp_verify_nonce($_POST['_inline_edit'], 'inlineeditnonce'))
return;
// If this is a auto save do nothing, we only save when update button is clicked
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
return;
if ( isset( $_POST['repair_price'] ) ) {
if ( is_numeric( $_POST['repair_price'] ) )
update_post_meta( $product_id, 'repair_price', $_POST['repair_price'] );
} else delete_post_meta( $product_id, 'repair_price' );
}
Now on the product page (in the front end) I need a checkbox "Repair cost $20", that will appear when the product custom field pricing option is filled with some price.
If customer add this option, it will add an additional cost of $20 on the product and it should also be reflected on the cart and checkout pages.
Any help will be appreciated.
In the following code, I have revisited a bit your actual code and added all necessary code to enable the checkbox option in single product page if the pricing option in the product is filled (for non variable products type that are not on sale).
When the option is selected by the customer, the product price is increased and when added to cart the price change is reflected in cart and checkout pages (see the screenshots at the end).
The code:
// Backend: Additional pricing option custom field
add_action( 'woocommerce_product_options_pricing', 'wc_cost_product_field' );
function wc_cost_product_field() {
woocommerce_wp_text_input( array(
'id' => '_repair_price',
'class' => 'wc_input_price short',
'label' => __( 'Repair Cost', 'woocommerce' ) . ' (' . get_woocommerce_currency_symbol() . ')'
));
}
// Backend: Saving product pricing option custom field value
add_action( 'woocommerce_admin_process_product_object', 'save_product_custom_meta_data', 100, 1 );
function save_product_custom_meta_data( $product ){
if ( isset( $_POST['_repair_price'] ) )
$product->update_meta_data( '_repair_price', sanitize_text_field($_POST['_repair_price']) );
}
// Front: Add a text input field inside the add to cart form on single product page
add_action('woocommerce_single_product_summary','add_repair_price_option_to_single_product', 2 );
function add_repair_price_option_to_single_product(){
global $product;
if( $product->is_type('variable') || ! $product->get_meta( '_repair_price' ) ) return;
add_action('woocommerce_before_add_to_cart_button', 'product_option_custom_field', 30 );
}
function product_option_custom_field(){
global $product;
$active_price = (float) $product->get_price();
$repair_price = (float) $product->get_meta( '_repair_price' );
$repair_price_html = strip_tags( wc_price( wc_get_price_to_display( $product, array('price' => $repair_price ) ) ) );
$active_price_html = wc_price( wc_get_price_to_display( $product ) );
$disp_price_sum_html = wc_price( wc_get_price_to_display( $product, array('price' => $active_price + $repair_price ) ) );
echo '<div class="hidden-field">
<p class="form-row form-row-wide" id="repair_option_field" data-priority="">
<span class="woocommerce-input-wrapper"><label class="checkbox"> ' . __("Repair Option:", "Woocommerce") .
' <input type="checkbox" class="input-checkbox " name="repair_option" id="repair_option" value="1"> + ' . $repair_price_html .
'</label></span></p>
<input type="hidden" name="repair_price" value="' . $repair_price . '">
<input type="hidden" name="active_price" value="' . $active_price . '"></div>';
// Jquery: Update displayed price
?>
<script type="text/javascript">
jQuery(function($) {
var cb = 'input[name="repair_option"]'
pp = 'p.price';
// On change / select a variation
$('form.cart').on( 'change', cb, function(){
if( $(cb).prop('checked') === true )
$(pp).html('<?php echo $disp_price_sum_html; ?>');
else
$(pp).html('<?php echo $active_price_html; ?>');
})
});
</script>
<?php
}
// Front: Calculate new item price and add it as custom cart item data
add_filter('woocommerce_add_cart_item_data', 'add_custom_product_data', 10, 3);
function add_custom_product_data( $cart_item_data, $product_id, $variation_id ) {
if (isset($_POST['repair_option']) && !empty($_POST['repair_option'])) {
$cart_item_data['new_price'] = (float) ($_POST['active_price'] + $_POST['repair_price']);
$cart_item_data['repair_price'] = (float) $_POST['repair_price'];
$cart_item_data['active_price'] = (float) $_POST['active_price'];
$cart_item_data['unique_key'] = md5(microtime().rand());
}
return $cart_item_data;
}
// Front: Set the new calculated cart item price
add_action('woocommerce_before_calculate_totals', 'extra_price_add_custom_price', 20, 1);
function extra_price_add_custom_price($cart) {
if (is_admin() && !defined('DOING_AJAX'))
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
foreach($cart->get_cart() as $cart_item) {
if (isset($cart_item['new_price']))
$cart_item['data']->set_price((float) $cart_item['new_price']);
}
}
// Front: Display option in cart item
add_filter('woocommerce_get_item_data', 'display_custom_item_data', 10, 2);
function display_custom_item_data($cart_item_data, $cart_item) {
if (isset($cart_item['repair_price'])) {
$cart_item_data[] = array(
'name' => __("Repair option", "woocommerce"),
'value' => strip_tags( '+ ' . wc_price( wc_get_price_to_display( $cart_item['data'], array('price' => $cart_item['repair_price'] ) ) ) )
);
}
return $cart_item_data;
}
Code goes in function.php file of your active child theme (or active theme). tested and works.
Addition based on this answer: Display product optional cost in Woocommerce in order details
Allow to save the repair price as order item meta data and display it everywhere on orders and email notifications:
// Save chosen seats to each order item as custom meta data and display order items Warrenty everywhere
add_action('woocommerce_checkout_create_order_line_item', 'save_order_item_product_waranty', 10, 4 );
function save_order_item_product_waranty( $item, $cart_item_key, $values, $order ) {
if( isset($values['repair_price']) && $values['repair_price'] > 0 ) {
$key = __("Repair option", "woocommerce");
$value = strip_tags( '+ '. wc_price( wc_get_price_to_display( $values['data'], array('price' => $values['repair_price']) ) ) );
$item->update_meta_data( $key, $value );
}
}
Code goes in function.php file of your active child theme (or active theme). tested and works.
So I am trying to display the length, width, and height of a WooCommerce variation in a tab. Everything is going well but it disables the other tabs. Essentially, they return with no content.
// Update descriptions tab
add_filter( 'woocommerce_product_tabs', 'woo_custom_description_tab', 98 );
function woo_custom_description_tab( $tabs ) {
$tabs['description']['callback'] = 'woo_custom_description_tab_content'; // Custom description callback
return $tabs;
}
function woo_custom_description_tab_content() {
global $product;
$available_variations = $product->get_available_variations();
$variation_id=$available_variations[0]['variation_id']; // Variation ID for first variation
$variable_product1 = new WC_Product_Variation( $variation_id );
echo '<strong>Product Box Dimensions</strong>';
if($variable_product1 ->get_length() != ''){
echo '<div class="dimensions">Length: ' . $variable_product1 ->get_length() . ' ' . get_option( 'woocommerce_dimension_unit' );
}
if($variable_product1 ->get_width() != ''){
echo '<div class="dimensions">Width: ' . $variable_product1 ->get_width() . ' ' . get_option( 'woocommerce_dimension_unit' );
}
if($variable_product1 ->get_height() != ''){
echo '<div class="dimensions">Height: ' . $variable_product1 ->get_height() . ' ' . get_option( 'woocommerce_dimension_unit' );
}
}
There is some errors in your code.
Before fetching variations, please confirm that the product is a
variable product.
Your callback function is for product description
tab. So it will ruin default content in the description tab.
Here is an updated code.
add_filter( 'woocommerce_product_tabs', 'woo_custom_description_tab', 98 );
function woo_custom_description_tab( $tabs ) {
$tabs['description']['callback'] = 'woo_custom_description_tab_content'; // Custom description callback
return $tabs;
}
function woo_custom_description_tab_content() {
global $product;
if ( $product->is_type( 'variable' ) ) { // Before fetching variables, confirm that it is a variable product.
$available_variations = $product->get_available_variations();
$variation_id=$available_variations[0]['variation_id']; // Variation ID for first variation
$variable_product1 = new WC_Product_Variation( $variation_id );
echo '<strong>Product Box Dimensions</strong>';
if($variable_product1 ->get_length() != ''){
echo '<div class="dimensions">Length: ' . $variable_product1 ->get_length() . ' ' . get_option( 'woocommerce_dimension_unit' );
}
if($variable_product1 ->get_width() != ''){
echo '<div class="dimensions">Width: ' . $variable_product1 ->get_width() . ' ' . get_option( 'woocommerce_dimension_unit' );
}
if($variable_product1 ->get_height() != ''){
echo '<div class="dimensions">Height: ' . $variable_product1 ->get_height() . ' ' . get_option( 'woocommerce_dimension_unit' );
}
}
}
To add a new custom tab, use below snippets & update the code.
add_filter( 'woocommerce_product_tabs', 'woo_new_product_tab' );
function woo_new_product_tab( $tabs ) {
// Adds the new tab
$tabs['test_tab'] = array(
'title' => __( 'New Product Tab', 'woocommerce' ),
'priority' => 50,
'callback' => 'woo_new_product_tab_content'
);
return $tabs;
}
function woo_new_product_tab_content() {
// The new tab content
echo '<h2>New Product Tab</h2>';
echo '<p>Here\'s your new product tab.</p>';
}
More tweaks on product tabs are available in WooCommerce Doc Page.
https://docs.woocommerce.com/document/editing-product-data-tabs/
I am trying to add save amount total on the sale flash badge using this snippet here below but there is something wrong since it is not working.
Any advice would be really appreciated.
// Add save amount on the sale badge.
add_filter( 'woocommerce_sale_flash', 'woocommerce_custom_badge', 10, 2 );
function woocommerce_custom_badge( $price, $product ) {
$saved = wc_price( $product->regular_price - $product->sale_price );
return $price . sprintf( __(' <div class="savings">Save %s</div>', 'woocommerce' ), $saved );
}
Thanks
Added WC 3+ compatibility
You don't have the correct arguments in your filter ($price doesn't exist for example), see here the related source code for woocommerce_sale_flash filter hook to understand better:
/*
* The filter hook woocommerce_sale_flash is located in:
* templates/loop/sale-flash.php and templates/single-product/sale-flash.php
*/
<?php if ( $product->is_on_sale() ) : ?>
<?php echo apply_filters( 'woocommerce_sale_flash', '<span class="onsale">' . esc_html__( 'Sale!', 'woocommerce' ) . '</span>', $post, $product ); ?>
So your working code is going to be something like:
add_filter( 'woocommerce_sale_flash', 'woocommerce_custom_badge', 10, 3 );
function woocommerce_custom_badge( $output_html, $post, $product ) {
// Added compatibility with WC +3
$regular_price = method_exists( $product, 'get_regular_price' ) ? $product->get_regular_price() : $product->regular_price;
$sale_price = method_exists( $product, 'get_sale_price' ) ? $product->get_sale_price() : $product->sale_price;
$saved_price = wc_price( $regular_price - $sale_price );
$output_html = '<span class="onsale">' . esc_html__( 'Save', 'woocommerce' ) . ' ' . $saved_price . '</span>';
return $output_html;
}
The 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.