0
votes

I'm using Display product prices with a shortcode by product ID in WooCommerce excellent answer, to show the product price via a shortcode, but I need a solution which can also display the price range for variable products.

The price range should show the lowest purchasable price (either regular or sale) from all variants to the highest purchasable price from all variants. It doesn't need to show two ranges for sale prices and regular prices, just a single range showing the prices you can actually buy it at, whether sale or regular.

For example:

  • Variation 1 - price 4.00
  • Variation 2 - price 4.00 sale price 3.00
  • Variation 3 - price 6.00 sale price 5.00
  • Variation 4 - price 8.00

The above should show a price range of 3.00 - 8.00

The way the code currently handles single products doesn't need to change, I just need to add the variable products to it.

The exact code I'm using is as below:

function custom_price_shortcode_callback( $atts ) {

$atts = shortcode_atts( array(
    'id' => null,
), $atts, 'product_price' );

$html = '';

if( intval( $atts['id'] ) > 0 && function_exists( 'wc_get_product' ) ){
    // Get an instance of the WC_Product object
    $product = wc_get_product( intval( $atts['id'] ) );

    // Get the product prices
    $price         = wc_get_price_to_display( $product, array( 'price' => $product->get_price() ) ); // Get the active price
    $regular_price = wc_get_price_to_display( $product, array( 'price' => $product->get_regular_price() ) ); // Get the regular price
    $sale_price    = wc_get_price_to_display( $product, array( 'price' => $product->get_sale_price() ) ); // Get the sale price

    // Formatting price settings (for the wc_price() function)
    $args = array(
        'ex_tax_label'       => false,
        'decimal_separator'  => '.',
        'thousand_separator' => ',',
        'decimals'           => 2,
        'price_format'       => '%1$s%2$s',
    );

    // Formatting html output
    if( ! empty( $sale_price ) && $sale_price != 0 && $sale_price < $regular_price )
        $html = "<br/><del>" . wc_price( $regular_price, $args ) . "</del> " . wc_price( $sale_price, $args ); // Sale price is set
    else
        $html = "<br/>" . wc_price( $price, $args ); // No sale price set
}
return $html;

 } 
add_shortcode( 'product_price', 'custom_price_shortcode_callback' );

Perhaps it's possible to incorporate this answer from WooCommerce variable product prices prefix?

add_filter( 'woocommerce_format_price_range', 'format_price_range_prefix', 20, 3 );
function format_price_range_prefix( $price, $from, $to ) {
    $price = sprintf( _x( 'From %1$s to %2$s %3$s', 'Price range: from-to', 'woocommerce' ), is_numeric( $from ) ? wc_price( $from ) : $from, is_numeric( $to ) ?  wc_price( $to ) : $to, __('lv', 'woocommerce') );
    return $price;
}

EDIT: I can confirm that the prices displayed are correctly converted using Aelia Currency Converter plugin so there is no need for any changes there. I have removed that part from the question, and removed the currency code from the above code as that's added automatically.

I've tried the following which almost works, it correctly identifies the variable product type and displays the 'from' and 'to' words but not the actual prices (because I think I need to get the $from and $to from somewhere but can't figure out how):

function custom_price_shortcode_callback( $atts ) {

$atts = shortcode_atts( array(
    'id' => null,
), $atts, 'product_price' );

$html = '';

if( intval( $atts['id'] ) > 0 && function_exists( 'wc_get_product' ) ){

    $product = wc_get_product( intval( $atts['id'] ) );

    if ( $product->is_type( 'variable' ) ){ 
    $args = array(
        'ex_tax_label'       => false,
        'decimal_separator'  => '.',
        'thousand_separator' => ',',
        'decimals'           => 2,
        'price_format'       => '%1$s%2$s',
    );
    $price = sprintf( _x( 'From %1$s to %2$s', 'Price range: from-to'), is_numeric( $from ) ? wc_price( $from, $args ) : $from, is_numeric( $to, $args ) ?  wc_price( $to, $args ) : $to );
    $html = "<br/>" . $price;

    }

    else{

    // Get the product prices
    $price         = wc_get_price_to_display( $product, array( 'price' => $product->get_price() ) ); // Get the active price
    $regular_price = wc_get_price_to_display( $product, array( 'price' => $product->get_regular_price() ) ); // Get the regular price
    $sale_price    = wc_get_price_to_display( $product, array( 'price' => $product->get_sale_price() ) ); // Get the sale price

    // Formatting price settings (for the wc_price() function)
    $args = array(
        'ex_tax_label'       => false,
        'decimal_separator'  => '.',
        'thousand_separator' => ',',
        'decimals'           => 2,
        'price_format'       => '%1$s%2$s',
    );

    // Formatting html output
    if( ! empty( $sale_price ) && $sale_price != 0 && $sale_price < $regular_price )
        $html = "<br/><del>" . wc_price( $regular_price, $args ) . "</del> " . wc_price( $sale_price, $args ); // Sale price is set
    else
        $html = "<br/>" . wc_price( $price, $args ); // No sale price set
}
}
return $html;
} 
add_shortcode( 'product_price', 'custom_price_shortcode_callback' );

If I wrap the variable product part in the format price range part then the variable products part stops working completely:

if ( $product->is_type( 'variable' ) ){ 
    $price = apply_filters( 'woocommerce_format_price_range', $price, $from, $to );       
    if ( !empty( $price ) ) { 
    $args = array(
        'ex_tax_label'       => false,
        'decimal_separator'  => '.',
        'thousand_separator' => ',',
        'decimals'           => 2,
        'price_format'       => '%1$s%2$s',
    );
    $price = sprintf( _x( 'From %1$s to %2$s', 'Price range: from-to'), is_numeric( $from ) ? wc_price( $from, $args ) : $from, is_numeric( $to ) ?  wc_price( $to, $args ) : $to );
    $html = "<br/>" . $price;
    }
    }

This also doesn't work:

if ( $product->is_type( 'variable' ) ){ 
$price = wc_format_price_range( $from, $to );       
if ( !empty( $price ) ) { 
$price = sprintf( _x( '%1$s &ndash; %2$s', 'Price range: from-to', 'woocommerce' ), is_numeric( $from ) ? wc_price( $from ) : $from, is_numeric( $to ) ? wc_price( $to ) : $to );
$html = "<br/>" . $price;
}
}
2

2 Answers

1
votes

I'm using the following solution which isn't exactly what I set out for, as instead of displaying the range of prices for variable products it actually shows a 'From' message (which can be changed) and then a single price.

However it does now work for standard products and variable products via shortcode, so does what I need.

function custom_price_shortcode_callback( $atts ) {

$atts = shortcode_atts( array(
    'id' => null,
), $atts, 'product_price' );

$html = '';

if( intval( $atts['id'] ) > 0 && function_exists( 'wc_get_product' ) ){

$product = wc_get_product( intval( $atts['id'] ) );

if ( $product->is_type( 'variable' ) ){ 

        $prefix = sprintf('%s ', __('From','woocommerce'));
        $min_price_regular = $product->get_variation_regular_price( 'min', true );
        $min_price_sale    = $product->get_variation_sale_price( 'min', true );
        $max_price = $product->get_variation_price( 'max', true );
        $min_price = $product->get_variation_price( 'min', true );

    $price = ( $min_price_sale == $min_price_regular ) ? wc_price( $min_price_regular ) : wc_price( $min_price_sale );
    return 
    ( $min_price == $max_price ) ? sprintf('<br/>' . $price) : $html = sprintf('<br/><span class="from-price">%s%s</span>', $prefix, $price);
}


else{

// Get the product prices
$price         = wc_get_price_to_display( $product, array( 'price' => $product->get_price() ) ); // Get the active price
$regular_price = wc_get_price_to_display( $product, array( 'price' => $product->get_regular_price() ) ); // Get the regular price
$sale_price    = wc_get_price_to_display( $product, array( 'price' => $product->get_sale_price() ) ); // Get the sale price

// Formatting price settings (for the wc_price() function)
$args = array(
    'ex_tax_label'       => false,
    'decimal_separator'  => '.',
    'thousand_separator' => ',',
    'decimals'           => 2,
    'price_format'       => '%1$s%2$s',
);

// Formatting html output
if( ! empty( $sale_price ) && $sale_price != 0 && $sale_price < $regular_price )
    $html = "<br/><del>" . wc_price( $regular_price, $args ) . "</del> " . wc_price( $sale_price, $args ); // Sale price is set
else
    $html = "<br/>" . wc_price( $price, $args ); // No sale price set
}
}
return $html;
} 
add_shortcode( 'product_price', 'custom_price_shortcode_callback' );
-1
votes

Use Booster for woocommerce Plugin. And Place this [wcj_product_price] shortcode anywhere you want. Its will show simple or variable product price with currency symbol. And this plugin is very helpul for woommerce.