Change the WooCommerce Sale Badge to Display a Percentage Discount

Last modified Oct 29, 2021
Difficulty Intermediate
Language CSS, PHP
Category
Change the WooCommerce Sale Badge to Display a Percentage Discount

Sales are great marketing strategies. By offering an often time-sensitive discount, sales encourage customers to make rapid purchase decisions. If you’re running a WooCommerce store, you’ll know that the WooCommerce sale badge is easy to set up. All you need to do is enter a sale price in the product setting, and a badge stating ‘Sale!’ will automatically display.

The WooCommerce sale badge is effective in alerting customers about a discount, but as this is the WooCommerce core default setting, it looks a bit overdone and commonplace. In a previous tutorial, we showed you how you can change the WooCommerce sale badge text to display as something custom, like ‘Flash Sale!’, ‘Act Fast!’ or similar. Today, we’ll be showing you how to remove the ‘Sale!’ text completely and replace it with a discount percentage value.

For this Divi tutorial, you’ll be adding a few lines of code to both the functions.php and style.css files. This code snippet is quick and easy to set up; you’ll have a sleek looking discount badge on your WooCommerce products in no time.

Looking for the code? Skip the step-by-step Divi tutorial and jump ahead to the code library.

How to Change the WooCommerce Sale Badge to a Percentage Discount

Out of the box, the WooCommerce core software will display all sale items with a simple ‘Sale!’ badge. To spruce up the look and feel, we’ve come up with a tutorial that’ll replace the standard ‘Sale!’ text with a percentage value. This way, your customers will know exactly how much they’re saving when purchasing discount items from your store.

In this Divi tutorial, you’ll add a few lines of PHP and CSS to your child theme. If you’re not sure what a child theme is, read our comprehensive child theme guide. If you haven’t already added a child theme, you can download one for free from the Divi Space website.

Step 1: Add a Divi Shop Module to a Page

To begin, add a Divi Shop module to a page using the Divi Builder. We assume that you’ve already added a selection of products to the back end.

WooCommerce Change Sale Badge Divi Tutorial - Add Divi Shop module

Add s Shop module using the Divi Builder

If you haven’t already, add sale prices to select products. To do so, navigate to the respective product listing on the back end, scroll down to the Product Data section and click on the General tab. Here you’ll see an option to enter a Sale Price. When complete, click Update.

With the sale prices added, the products on the front end will display as such:

WooCommerce Change Sale Badge Divi Tutorial - Sale badge display

By default, the WooCommerce sale badge displays simply as ‘Sale!’

Step 2: Add the PHP and CSS Code

Now for the fun part! Head to the  Appearance > Theme Editor console and open the functions.php file in your child theme.

Copy and paste the PHP code before the closing PHP ?> bracket:

Change WooCommerce Sale Badge to Discount Percentage - Add PHP code

Add PHP code to the functions.php file in your child theme

When finished, click Update File to save your changes.

Next, navigate to the style.css file, copy and paste in the CSS code.

When finished, click Update File to save your changes.

Change WooCommerce Sale Badge to Discount Percentage - Add CSS code

Add CSS code to the style.css file in your child theme

Now, when you view the front end of your site, you’ll see that the text has changed from ‘Sale!’ to a numeric percentage value.

Change WooCommerce Sale Badge to Discount Percentage 1

With just a bit of code, you could change the default Sale! text to a numeric value

Alternate Icon Styling

This tutorial makes use of the Elegant Themes icon font. These icons are used in various modules across the Divi theme, for example, as icons in the blurb module. Each of these icons has a corresponding code, for example:

Elegant Themes icon font set icons

These are a few of the many icons in the Elegant Themes icon font set

In our tutorial, we referenced the icon of a percentage sign (code &#xe0da) as it fit our example. If you’d like to change the icon to something else, head over to this Elegant Themes post, browse through the available icon set and copy the code of the icon you like best (for example, the code of the heart icon is &#xe089).

Once you’ve copied the code of your icon of choice, return to your functions.php file. Wherever you see the original icon font code – &#xe0da (percentage icon) – replace it with the new icon font code – &#xe089 (heart icon).

Change WooCommerce Sale Badge to Discount Percentage - Add PHP code 2

Replace the highlighted code with another Elegant Themes icon font to change the icon

This will produce the following super cute effect on the front end:

Change WooCommerce Sale Badge to Discount Percentage 2

Another example using an alternate icon

Do you see how, with a bit of PHP and CSS, you can change the look and feel of your WooCommerce store in just a few seconds. Now, with the sale badge displaying the percentage discount, your customers will know how much they’re saving when purchasing from your sale.

Suggest a snippet!

Do you have a Divi fix in mind but don’t know how to do it? Submit your snippet request by commenting below and our team of expert developers will get to work!

PHP

/* Replace text of Sale! badge with percentage */

  add_filter( 'woocommerce_sale_flash', 'ds_replace_sale_text' );
 
function ds_replace_sale_text($text) {
 global $product; 
 $stock = $product->get_stock_status();
 $product_type = $product->get_type();
 $sale_price  = 0;
 $regular_price = 0;
 if($product_type == 'variable'){
  $product_variations = $product->get_available_variations();
  foreach ($product_variations as $kay => $value){
   if($value['display_price'] < $value['display_regular_price']){
    $sale_price = $value['display_price'];
    $regular_price = $value['display_regular_price'];
   }
  }
  if($regular_price > $sale_price && $stock != 'outofstock') {
   $product_sale = intval(((intval($regular_price) - floatval($sale_price)) / floatval($regular_price)) * 100);
   if ($product_sale > 5 ) {
   return '<span class="onsale"> <span class="sale-icon" aria-hidden="true" data-icon="&#xe0da"></span> ' . esc_html($product_sale) . '% OFF</span>';
   }
   if ($product_sale <= 5 ) {
       return '<span class="onsale"> <span class="sale-icon" aria-hidden="true" data-icon="&#xe0da"></span>Sale!</span>';
   }
  }else{
   return  '';
  }
 }else{
  $regular_price = get_post_meta( get_the_ID(), '_regular_price', true);
  $sale_price = get_post_meta( get_the_ID(), '_sale_price', true);
  if($regular_price > 5) {
   $product_sale = intval(((floatval($regular_price) - floatval($sale_price)) / floatval($regular_price)) * 100);
   return '<span class="onsale"> <span class="sale-icon" aria-hidden="true" data-icon="&#xe0da"></span> ' . esc_html($product_sale) . '% OFF</span>';
  }
  if($regular_price >= 0 && $regular_price <= 5 ) {
   $product_sale = intval(((floatval($regular_price) - floatval($sale_price)) / floatval($regular_price)) * 100);
   return '<span class="onsale"> <span class="sale-icon" aria-hidden="true" data-icon="&#xe0da"></span>Sale!</span>';
  }

  else{
   return '';
  }
 }
}

 

CSS

/* Display Sale! Badge Icon */

.sale-icon[data-icon]:before {
    font-family: 'ETmodules';
    content: attr(data-icon);
    speak: none;
    font-weight: 400;
    font-variant: normal;
    text-transform: none;
    line-height: 1;
    -webkit-font-smoothing: antialiased;
}

/* Optional styling */

.woocommerce-page ul.products li.product span.onsale, .woocommerce ul.products li.product span.onsale {
  left: 0px!important;
    top: 0px!important; 
    font-size: 15px;
   background: #137118!important;
}

 

Does this snippet (still) work?

Please let us know in the comments if everything worked as expected. We have tested this code with the Version: 4.9.4 of the Divi Theme.
If you think this code saved you time, we will be happy to receive a comment!

___

License: This snippet contains code from the Divi Theme, copyright https://elegantthemes.com, and Woocommerce Plugin by Automatic modified by Divi Space, November 5, 2020. Licensed under the GNU General Public License v3, no warranty; click here for details.  Last updated: May 11th, 2021.

Your Comments

13 Comments

  1. Philip

    Great snippet, thank you very much for posting it!
    In my case, the percentage was not shown correctly, so I changed the calculation to this:
    $product_sale = 100 – round($sale_price / $regular_price * 100);

    Reply
  2. Vidal

    Hi Anna, It’s working fine everywhere, also in loop 🙂 But I tried this for single product page but that does not work.
    Is it possible ?

    Thanks

    Reply
    • <div class="apbct-real-user-wrapper">
    <div class="apbct-real-user-author-name">Anna Kurowska</div>
    <div class="apbct-real-user-badge" onmouseover="apbctRealUserBadgeViewPopup('apbct_trp_comment_id_700390');" onmouseout="apbctRealUserBadgeClosePopup(event);">
        <img src="https://wpzone.co/wp-content/plugins/cleantalk-spam-protect/css/images/real_user.svg" class="apbct-real-user-popup-img" style="align-self: center;">
        <div class="apbct-real-user-popup apbct-trp-popup-desktop" id="apbct_trp_comment_id_700390">
            <div class="apbct-real-user-title">
                <p class="apbct-real-user-popup-header">The Real Person!</p>
                <div class="apbct-real-user-popup-content_row">
                    <img src="https://wpzone.co/wp-content/plugins/cleantalk-spam-protect/css/images/real_user.svg" class="apbct-real-user-popup-img">
                    <span class="apbct-real-user-popup-text">Author <b>Anna Kurowska</b> acts as a real person and verified as not a bot.</span>
                </div>
                <div class="apbct-real-user-popup-content_row">
                    <img src="https://wpzone.co/wp-content/plugins/cleantalk-spam-protect/css/images/shield.svg" class="apbct-real-user-popup-img">
                    <span class="apbct-real-user-popup-text">Passed all tests against spam bots. Anti-Spam by CleanTalk.</span>
                </div>
            </div>
        </div>
    </div>
    <div class="apbct-real-user-popup apbct-trp-popup-mob" id="apbct_trp_comment_id_700390">
        <div class="apbct-real-user-title">
            <p class="apbct-real-user-popup-header">The Real Person!</p>
            <div class="apbct-real-user-popup-content_row">
                <img src="https://wpzone.co/wp-content/plugins/cleantalk-spam-protect/css/images/real_user.svg" class="apbct-real-user-popup-img">
                <span class="apbct-real-user-popup-text">Author <b>Anna Kurowska</b> acts as a real person and verified as not a bot.</span>
            </div>
            <div class="apbct-real-user-popup-content_row">
                <img src="https://wpzone.co/wp-content/plugins/cleantalk-spam-protect/css/images/shield.svg" class="apbct-real-user-popup-img">
                <span class="apbct-real-user-popup-text">Passed all tests against spam bots. Anti-Spam by CleanTalk.</span>
            </div>
        </div>
    </div>
</div>

      This snippet should also work for single product pages 🙂 Try changing the hook priority:

      add_filter( 'woocommerce_sale_flash', 'ds_replace_sale_text' , 99 );
  3. blue

    Thanks! It works perfectly

    Reply
  4. Paul

    Anna, thank you for this! Worked perfect EXCEPT one product. lol – what could be causing this issue? I tried your functions fix, but it didnt do anything. All products perfect, but one is displaying 25.114285714286% OFF

    Reply
    • <div class="apbct-real-user-wrapper">
    <div class="apbct-real-user-author-name">Anna Kurowska</div>
    <div class="apbct-real-user-badge" onmouseover="apbctRealUserBadgeViewPopup('apbct_trp_comment_id_632972');" onmouseout="apbctRealUserBadgeClosePopup(event);">
        <img src="https://wpzone.co/wp-content/plugins/cleantalk-spam-protect/css/images/real_user.svg" class="apbct-real-user-popup-img" style="align-self: center;">
        <div class="apbct-real-user-popup apbct-trp-popup-desktop" id="apbct_trp_comment_id_632972">
            <div class="apbct-real-user-title">
                <p class="apbct-real-user-popup-header">The Real Person!</p>
                <div class="apbct-real-user-popup-content_row">
                    <img src="https://wpzone.co/wp-content/plugins/cleantalk-spam-protect/css/images/real_user.svg" class="apbct-real-user-popup-img">
                    <span class="apbct-real-user-popup-text">Author <b>Anna Kurowska</b> acts as a real person and verified as not a bot.</span>
                </div>
                <div class="apbct-real-user-popup-content_row">
                    <img src="https://wpzone.co/wp-content/plugins/cleantalk-spam-protect/css/images/shield.svg" class="apbct-real-user-popup-img">
                    <span class="apbct-real-user-popup-text">Passed all tests against spam bots. Anti-Spam by CleanTalk.</span>
                </div>
            </div>
        </div>
    </div>
    <div class="apbct-real-user-popup apbct-trp-popup-mob" id="apbct_trp_comment_id_632972">
        <div class="apbct-real-user-title">
            <p class="apbct-real-user-popup-header">The Real Person!</p>
            <div class="apbct-real-user-popup-content_row">
                <img src="https://wpzone.co/wp-content/plugins/cleantalk-spam-protect/css/images/real_user.svg" class="apbct-real-user-popup-img">
                <span class="apbct-real-user-popup-text">Author <b>Anna Kurowska</b> acts as a real person and verified as not a bot.</span>
            </div>
            <div class="apbct-real-user-popup-content_row">
                <img src="https://wpzone.co/wp-content/plugins/cleantalk-spam-protect/css/images/shield.svg" class="apbct-real-user-popup-img">
                <span class="apbct-real-user-popup-text">Passed all tests against spam bots. Anti-Spam by CleanTalk.</span>
            </div>
        </div>
    </div>
</div>

      Hi, I updated the code, let me know if that fixes the issue 🙂

  5. St

    I tried using this snippet but it returns a lengthy repeating decimal value. Can we round the values somehow?

    Reply
    • <div class="apbct-real-user-wrapper">
    <div class="apbct-real-user-author-name">Anna Kurowska</div>
    <div class="apbct-real-user-badge" onmouseover="apbctRealUserBadgeViewPopup('apbct_trp_comment_id_569918');" onmouseout="apbctRealUserBadgeClosePopup(event);">
        <img src="https://wpzone.co/wp-content/plugins/cleantalk-spam-protect/css/images/real_user.svg" class="apbct-real-user-popup-img" style="align-self: center;">
        <div class="apbct-real-user-popup apbct-trp-popup-desktop" id="apbct_trp_comment_id_569918">
            <div class="apbct-real-user-title">
                <p class="apbct-real-user-popup-header">The Real Person!</p>
                <div class="apbct-real-user-popup-content_row">
                    <img src="https://wpzone.co/wp-content/plugins/cleantalk-spam-protect/css/images/real_user.svg" class="apbct-real-user-popup-img">
                    <span class="apbct-real-user-popup-text">Author <b>Anna Kurowska</b> acts as a real person and verified as not a bot.</span>
                </div>
                <div class="apbct-real-user-popup-content_row">
                    <img src="https://wpzone.co/wp-content/plugins/cleantalk-spam-protect/css/images/shield.svg" class="apbct-real-user-popup-img">
                    <span class="apbct-real-user-popup-text">Passed all tests against spam bots. Anti-Spam by CleanTalk.</span>
                </div>
            </div>
        </div>
    </div>
    <div class="apbct-real-user-popup apbct-trp-popup-mob" id="apbct_trp_comment_id_569918">
        <div class="apbct-real-user-title">
            <p class="apbct-real-user-popup-header">The Real Person!</p>
            <div class="apbct-real-user-popup-content_row">
                <img src="https://wpzone.co/wp-content/plugins/cleantalk-spam-protect/css/images/real_user.svg" class="apbct-real-user-popup-img">
                <span class="apbct-real-user-popup-text">Author <b>Anna Kurowska</b> acts as a real person and verified as not a bot.</span>
            </div>
            <div class="apbct-real-user-popup-content_row">
                <img src="https://wpzone.co/wp-content/plugins/cleantalk-spam-protect/css/images/shield.svg" class="apbct-real-user-popup-img">
                <span class="apbct-real-user-popup-text">Passed all tests against spam bots. Anti-Spam by CleanTalk.</span>
            </div>
        </div>
    </div>
</div>

      Try to change each

      $product_sale = floatval(((floatval($regular_price) - floatval($sale_price)) / floatval($regular_price)) * 100); 
      

      to

         $product_sale = intval(((floatval($regular_price) - floatval($sale_price)) / floatval($regular_price)) * 100);
    • <div class="apbct-real-user-wrapper">
    <div class="apbct-real-user-author-name">Anna Kurowska</div>
    <div class="apbct-real-user-badge" onmouseover="apbctRealUserBadgeViewPopup('apbct_trp_comment_id_569919');" onmouseout="apbctRealUserBadgeClosePopup(event);">
        <img src="https://wpzone.co/wp-content/plugins/cleantalk-spam-protect/css/images/real_user.svg" class="apbct-real-user-popup-img" style="align-self: center;">
        <div class="apbct-real-user-popup apbct-trp-popup-desktop" id="apbct_trp_comment_id_569919">
            <div class="apbct-real-user-title">
                <p class="apbct-real-user-popup-header">The Real Person!</p>
                <div class="apbct-real-user-popup-content_row">
                    <img src="https://wpzone.co/wp-content/plugins/cleantalk-spam-protect/css/images/real_user.svg" class="apbct-real-user-popup-img">
                    <span class="apbct-real-user-popup-text">Author <b>Anna Kurowska</b> acts as a real person and verified as not a bot.</span>
                </div>
                <div class="apbct-real-user-popup-content_row">
                    <img src="https://wpzone.co/wp-content/plugins/cleantalk-spam-protect/css/images/shield.svg" class="apbct-real-user-popup-img">
                    <span class="apbct-real-user-popup-text">Passed all tests against spam bots. Anti-Spam by CleanTalk.</span>
                </div>
            </div>
        </div>
    </div>
    <div class="apbct-real-user-popup apbct-trp-popup-mob" id="apbct_trp_comment_id_569919">
        <div class="apbct-real-user-title">
            <p class="apbct-real-user-popup-header">The Real Person!</p>
            <div class="apbct-real-user-popup-content_row">
                <img src="https://wpzone.co/wp-content/plugins/cleantalk-spam-protect/css/images/real_user.svg" class="apbct-real-user-popup-img">
                <span class="apbct-real-user-popup-text">Author <b>Anna Kurowska</b> acts as a real person and verified as not a bot.</span>
            </div>
            <div class="apbct-real-user-popup-content_row">
                <img src="https://wpzone.co/wp-content/plugins/cleantalk-spam-protect/css/images/shield.svg" class="apbct-real-user-popup-img">
                <span class="apbct-real-user-popup-text">Passed all tests against spam bots. Anti-Spam by CleanTalk.</span>
            </div>
        </div>
    </div>
</div>

      If you can confirm that worked for you, I will update snippet. Thanks for checking our tutorial!

  6. Marcel Rodriguez

    Iss possible change de display format ?
    For example :

    price before. price offer %discount

    ( in loop and single product )

    Reply
  7. Phil

    Thank you so much ! This is the first time I mess around with the php files of my child theme :D.

    I had a question though. For me, it displays the percentage with an empty square before the number. Just like if it had trouble displaying the minus sing… Do you know what could cause this?

    Thanks again 😀
    Phil

    Reply
    • <div class="apbct-real-user-wrapper">
    <div class="apbct-real-user-author-name">Anna Kurowska</div>
    <div class="apbct-real-user-badge" onmouseover="apbctRealUserBadgeViewPopup('apbct_trp_comment_id_477195');" onmouseout="apbctRealUserBadgeClosePopup(event);">
        <img src="https://wpzone.co/wp-content/plugins/cleantalk-spam-protect/css/images/real_user.svg" class="apbct-real-user-popup-img" style="align-self: center;">
        <div class="apbct-real-user-popup apbct-trp-popup-desktop" id="apbct_trp_comment_id_477195">
            <div class="apbct-real-user-title">
                <p class="apbct-real-user-popup-header">The Real Person!</p>
                <div class="apbct-real-user-popup-content_row">
                    <img src="https://wpzone.co/wp-content/plugins/cleantalk-spam-protect/css/images/real_user.svg" class="apbct-real-user-popup-img">
                    <span class="apbct-real-user-popup-text">Author <b>Anna Kurowska</b> acts as a real person and verified as not a bot.</span>
                </div>
                <div class="apbct-real-user-popup-content_row">
                    <img src="https://wpzone.co/wp-content/plugins/cleantalk-spam-protect/css/images/shield.svg" class="apbct-real-user-popup-img">
                    <span class="apbct-real-user-popup-text">Passed all tests against spam bots. Anti-Spam by CleanTalk.</span>
                </div>
            </div>
        </div>
    </div>
    <div class="apbct-real-user-popup apbct-trp-popup-mob" id="apbct_trp_comment_id_477195">
        <div class="apbct-real-user-title">
            <p class="apbct-real-user-popup-header">The Real Person!</p>
            <div class="apbct-real-user-popup-content_row">
                <img src="https://wpzone.co/wp-content/plugins/cleantalk-spam-protect/css/images/real_user.svg" class="apbct-real-user-popup-img">
                <span class="apbct-real-user-popup-text">Author <b>Anna Kurowska</b> acts as a real person and verified as not a bot.</span>
            </div>
            <div class="apbct-real-user-popup-content_row">
                <img src="https://wpzone.co/wp-content/plugins/cleantalk-spam-protect/css/images/shield.svg" class="apbct-real-user-popup-img">
                <span class="apbct-real-user-popup-text">Passed all tests against spam bots. Anti-Spam by CleanTalk.</span>
            </div>
        </div>
    </div>
</div>

      That’s great and thank you for your comment! Empty square is probably an icon that is not loading. Make sure icon font is loading on your page and the icon code is correct.

      Make sure you are using the right syntax, sometimes there are problems with pasting the code, for example:
      Correct:

      .sale-icon[data-icon]:before {
          font-family: 'ETmodules';
      }
      

      Incorrect syntax:

      .sale-icon[data-icon]:before {
          font-family: ‘ETmodules’;
      }
      
  8. Darsheel Savla

    Thanks a lot guys! Absolutely loved this one, it was of great help. I will share this with my friends!

    Reply

Submit a Comment

Your email address will not be published. Required fields are marked *

Next snippet Display WooCommerce Products in Single Column on Mobile Devices
Previous snippet Change the “Sale!” Text of the WooCommerce Sale Badge