Displaying product prices outside of standard WooCommerce template files is a task that comes up regularly in custom theme development. You might be building a custom homepage section that showcases featured products without using the standard WooCommerce loop, a sidebar widget that lists the three most expensive sale items, a popup that shows a quick-view product summary, or an AJAX-powered product comparison table. In all of these cases you need to retrieve price data from a WooCommerce product object programmatically rather than through the standard template output functions. WooCommerce wraps every product in a WC_Product object that exposes a rich API for accessing price data in multiple formats. The regular price, sale price, and currently active price are available as raw numeric strings through getter methods, and the formatted price with currency symbol and HTML wrapper is available through the get_price_html() method that WooCommerce uses internally in its own templates. Understanding which method to use depends on your context: raw values are appropriate for calculations, comparisons, sorting, and storage; formatted HTML output is appropriate for display. A product is on sale when its sale price is set and the sale price is lower than the regular price — the is_on_sale() method checks this cleanly without you having to compare the values manually. Variable products work differently from simple products: a variable product itself has no single price but rather a price range determined by its variations, and WooCommerce’s get_price_html() handles range formatting automatically when called on a variable product object. For custom price display in an AJAX context, always use wc_price() to format numeric values rather than manually appending currency symbols, because it respects the store’s currency position, decimal separator, thousands separator, and number of decimal places settings. When building custom product loops, always retrieve the product object using wc_get_product() rather than accessing postmeta directly, because the method returns the correct subclass (WC_Product_Simple, WC_Product_Variable, etc.) with all type-specific methods available. This pairs naturally with the custom admin columns technique to surface price data in the products list view.
Problem: You need to retrieve and display WooCommerce product prices programmatically outside standard WooCommerce template files.
Solution: Use the WC_Product object methods in your template or function code:
<?php
// Get the product object (inside The Loop or by ID)
$product = wc_get_product( get_the_ID() );
// By specific post ID:
// $product = wc_get_product( 123 );
if ( ! $product ) {
return;
}
// Raw price values (numeric strings, no currency symbol)
$regular_price = $product->get_regular_price(); // e.g. "49.99"
$sale_price = $product->get_sale_price(); // e.g. "29.99" or ""
$active_price = $product->get_price(); // current active price
// Formatted price with currency symbol (HTML output)
$price_html = $product->get_price_html();
echo $price_html; // e.g. $49.99 $29.99
// Check if product is on sale
if ( $product->is_on_sale() ) {
$saving = $regular_price - $sale_price;
echo '<span class="saving">You save: ' . wc_price( $saving ) . '</span>';
}
// Format any raw number as a price respecting store settings
echo wc_price( 19.99 ); // outputs: <span class="woocommerce-Price-amount">$19.99</span>
// Variable product — get min and max prices from variations
if ( $product->is_type( 'variable' ) ) {
$min_price = $product->get_variation_price( 'min', true );
$max_price = $product->get_variation_price( 'max', true );
echo wc_price( $min_price ) . ' – ' . wc_price( $max_price );
}
NOTE: Tax display in prices depends on your WooCommerce tax settings. get_price() returns the price as stored (usually excluding tax), while get_price_html() respects the “Display prices in the shop” setting and applies tax formatting accordingly. If you need a price with tax included regardless of settings, use wc_get_price_including_tax( $product ). For performance in large product loops, consider using WC_Product_Query or wc_get_products() instead of WP_Query followed by repeated wc_get_product() calls, as it retrieves product objects more efficiently.