Skip to content
Advertisement

Add sale badge to product thumbnail on single product page and shop archive pages in WooCommerce

I use the following code to add a small badge topleft of every product with -%off.

add_filter( 'woocommerce_single_product_image_thumbnail_html', 'filter_woocommerce_single_product_image_thumbnail_html', 10, 2 ); 
function filter_woocommerce_single_product_image_thumbnail_html( $thumbnail, $thumbnail_id ) {
 
    global $post, $woocommerce;
    $product = wc_get_product( $post->ID );
    $is_on_sale = $product->is_on_sale();
 
    if ( $is_on_sale ) {
 
        $rrp_price          = $product->get_regular_price();
        $sale_price         = $product->get_price();
        $discount_amount    = $rrp_price - $sale_price;
        $discount_percent   = '-' . round( ( $discount_amount / $rrp_price ) * 100, 0 ) . '%';
        $thumbnail          = '<span class="wpd-sale-thumbnail"><span class="wpd-sale-badge">' . $discount_percent . '</span>' . $thumbnail . '</span>';
 
    }
 
    return $thumbnail;
 
}

On my product page and it works. However when i try to do it on category page to all product listings with the following code:

add_filter( 'post_thumbnail_html', 'filter_woocommerce_archive_product_image_thumbnail_html', 30, 5  );
function filter_woocommerce_archive_product_image_thumbnail_html( $html, $post_id, $post_thumbnail_id, $size, $attr ) {
 
    $product = wc_get_product( $post_id );
 
    if ( ! is_a( $product, 'WC_Product' ) ) {
 
        return $html;
 
    }
 
    $is_on_sale = $product->is_on_sale();
 
    if ( $is_on_sale && is_product_category() ) {
 
        $rrp_price          = $product->get_regular_price();
        $sale_price         = $product->get_price();
        $discount_amount    = $rrp_price - $sale_price;
        $discount_percent   = '-' . round( ( $discount_amount / $rrp_price ) * 100, 0 ) . '%';
        $html               = '<span class="wpd-sale-thumbnail"><span class="wpd-sale-badge">' . $discount_percent . '</span>' . $html . '</span>';
 
    }
 
    return $html;
 
}

It does not work, there doesn’t seem to be any adjustment. Can I get some guidance into it?

Advertisement

Answer

To add the badge to the product images on the archive pages, either you use

/**
 * Get the product thumbnail for the loop.
 */
function woocommerce_template_loop_product_thumbnail() {
    $w_g_p_t = woocommerce_get_product_thumbnail();
    
    global $product;
    
    // Is a WC product
    if ( is_a( $product, 'WC_Product' ) ) {
        
        // On sale
        $is_on_sale = $product->is_on_sale();
        
        // True
        if ( $is_on_sale ) {
            $rrp_price        = (int) $product->get_regular_price();
            $sale_price       = (int) $product->get_price();
            
            // Greater than
            if ( $rrp_price > $sale_price ) {
                $discount_amount  = $rrp_price - $sale_price;
                $discount_percent = '-' . round( ( $discount_amount / $rrp_price ) * 100, 0 ) . '%';
                $w_g_p_t          = '<span class="wpd-sale-thumbnail"><span class="wpd-sale-badge">' . $discount_percent . '</span>' . $w_g_p_t . '</span>';
            }
        }
    }
    
    echo $w_g_p_t;
}

OR

function action_woocommerce_before_shop_loop_item_title() {
    // Removes a function from a specified action hook.
    remove_action( 'woocommerce_before_shop_loop_item_title', 'woocommerce_template_loop_product_thumbnail', 10 );
    
    global $product;
    
    // Is a WC product
    if ( is_a( $product, 'WC_Product' ) ) {
        $size = 'woocommerce_thumbnail';

        $image_size = apply_filters( 'single_product_archive_thumbnail_size', $size );
        
        $get_image = $product->get_image( $image_size );
        
        // On sale
        $is_on_sale = $product->is_on_sale();
     
        // True
        if ( $is_on_sale ) {
            $rrp_price        = (int) $product->get_regular_price();
            $sale_price       = (int) $product->get_price();
            
            // Greater than
            if ( $rrp_price > $sale_price ) {
                $discount_amount  = $rrp_price - $sale_price;
                $discount_percent = '-' . round( ( $discount_amount / $rrp_price ) * 100, 0 ) . '%';
                $get_image        = '<span class="wpd-sale-thumbnail"><span class="wpd-sale-badge">' . $discount_percent . '</span>' . $get_image . '</span>';
            }
        }
    }

    echo $product ? $get_image : '';
}
add_action( 'woocommerce_before_shop_loop_item_title', 'action_woocommerce_before_shop_loop_item_title', 9 );

I have also rewritten your existing code (for the single product page)

function filter_woocommerce_single_product_image_thumbnail_html( $html, $post_thumbnail_id ) {
    // Get the global product object
    global $product;
    
    // Is a WC product
    if ( is_a( $product, 'WC_Product' ) ) {
        
        // On sale
        $is_on_sale = $product->is_on_sale();
        
        // True
        if ( $is_on_sale ) {
            $rrp_price        = (int) $product->get_regular_price();
            $sale_price       = (int) $product->get_price();
            
            // Greater than
            if ( $rrp_price > $sale_price ) {
                $discount_amount  = $rrp_price - $sale_price;
                $discount_percent = '-' . round( ( $discount_amount / $rrp_price ) * 100, 0 ) . '%';
                $html             = '<span class="wpd-sale-thumbnail"><span class="wpd-sale-badge">' . $discount_percent . '</span>' . $html . '</span>';
            }
        }
    }
 
    return $html;
}
add_filter( 'woocommerce_single_product_image_thumbnail_html', 'filter_woocommerce_single_product_image_thumbnail_html', 10, 2 );
User contributions licensed under: CC BY-SA
4 People found this is helpful
Advertisement