WooCommerce variation price display controls how prices appear on variable product pages — either as a range ("$10 – $50"), a single price when one variation is selected, or a custom format you define. Getting it right affects conversion rates, customer trust, and the accuracy of what your store communicates before checkout.
How WooCommerce Variable Product Pricing Works
WooCommerce stores variation prices in a serialized meta field (_min_variation_price, _max_variation_price, and their sale equivalents) attached to the parent product. Before a shopper selects a variation, the template reads these cached min/max values and renders a range. Once a variation is chosen, a JavaScript event (found_variation) fires and updates the displayed price from the variation's JSON payload embedded in the page.
This architecture has two practical consequences:
- The range cache must be current. If you update a variation price but the parent's cached min/max isn't recalculated, the displayed range will be stale.
- JavaScript must run for individual prices to appear. If a page builder, caching plugin, or CDN breaks JS execution, customers will only ever see the range — never the selected price.
According to WooCommerce's own documentation, the variation data is output as a JSON blob via wc_get_product_variation_attributes() and loaded into the DOM; the woocommerce-add-to-cart-variation.js script handles all price swapping client-side.
Why the Default Price Range Display Causes Conversion Problems
The default $10 – $50 range is technically accurate but psychologically problematic. Shoppers anchor on the lower number, feel misled when they select a premium variant, and sometimes abandon rather than proceed. Baymard Institute's 2024 product page UX study lists ambiguous pre-selection pricing as a top-5 abandonment driver.
Common symptoms of a broken or confusing range display:
- Range shows
$0 – $50because one variation has no price set - Range doesn't update after a variation is selected (JS failure)
- Range shows an old value after a product edit (stale cache)
- Sale price range doesn't reflect the actual discount clearly
Each of these has a distinct fix, covered in the sections below.
How to Configure Prices for Individual Variations
Navigate to Products → [Product Name] → Variations in your WordPress admin. Expand each variation and fill in Regular price (required) and Sale price (optional). Key rules:
- Never leave Regular price blank unless you intentionally want that variation to be unpurchasable. A blank price on any variation will pull the min cache to
$0and display$0 – $Xto customers. - Sale price must be lower than regular price or WooCommerce will silently ignore it.
- You can schedule sale prices using the "Schedule" link next to the sale price field.
For stores with dozens of variations, editing individually is tedious. Use the bulk edit dropdown at the top of the Variations tab: select all variations, choose "Set regular prices," and apply a value or percentage rule. For programmatic updates:
$variation = wc_get_product( $variation_id );
$variation->set_regular_price( '29.99' );
$variation->set_sale_price( '19.99' );
$variation->save();
// Recalculate parent cache
WC_Product_Variable::sync( $parent_product_id );
Always call WC_Product_Variable::sync() after bulk-updating variation prices via code. Skipping this is the most common cause of stale range displays.
How to Change the Price Range Display Format
The price range HTML is generated by WC_Product_Variable::get_price_html() and is filterable. You have three common customization goals:
Show a Single Price Instead of a Range
If all your variations cost the same, or you want to hide the range until selection:
add_filter( 'woocommerce_variable_price_html', function( $price, $product ) {
$prices = $product->get_variation_prices( true );
$min = current( $prices['price'] );
$max = end( $prices['price'] );
if ( $min === $max ) {
return wc_price( $min );
}
return $price;
}, 10, 2 );
This returns a single formatted price when min equals max, otherwise falls back to the default range.
Show "From $X" Instead of a Full Range
Useful when you have many tiers but want to emphasize the entry price:
add_filter( 'woocommerce_variable_price_html', function( $price, $product ) {
$prices = $product->get_variation_prices( true );
$min = current( $prices['price'] );
return sprintf( __( 'From %s', 'your-textdomain' ), wc_price( $min ) );
}, 10, 2 );
Show "Price varies by option selected" Text
For configure-to-order products where any price display before selection is misleading:
add_filter( 'woocommerce_variable_price_html', function( $price, $product ) {
return '<span class="variable-price-notice">' . __( 'Price varies by option selected', 'your-textdomain' ) . '</span>';
}, 10, 2 );
Place these snippets in your child theme's functions.php or a site-specific plugin. Avoid editing core WooCommerce files directly — updates will overwrite them.
Price Display After Variation Selection: JavaScript Behavior
When a shopper picks a variation, WooCommerce fires the found_variation jQuery event and passes the variation object. The woocommerce-add-to-cart-variation.js script then replaces the price HTML in .woocommerce-variation-price. If this isn't working on your store, check these failure points:
| Symptom | Likely Cause | Fix |
|---|---|---|
| Price never updates on selection | jQuery conflict or JS error | Check browser console; ensure jQuery loads before WooCommerce scripts |
| Price updates but shows blank | Variation has no price set | Add a Regular price to every variation |
Price updates to $0.00 | Sale price set to 0 or empty string | Set sale price to blank (null), not "0" |
| Range reappears after deselection | Expected behavior | Customize with $('.reset_variations') handler |
| Price doesn't update with swatches | Swatches plugin bypasses native select events | Verify plugin triggers change on the underlying <select> |
This last row is especially important if you're using a variation swatches implementation — see our WooCommerce Variation Swatches implementation guide for how to verify that native WooCommerce price-update events still fire correctly after replacing dropdowns with visual buttons.
Recalculating the Variation Price Cache
WooCommerce caches min/max prices on the parent product to avoid calculating them on every page load. This cache becomes stale when:
- You update variation prices programmatically without calling
sync() - You import products via CSV or a plugin that doesn't trigger WooCommerce hooks
- You delete or add variations
To force recalculation on a single product:
$product = wc_get_product( $product_id );
if ( $product->is_type( 'variable' ) ) {
WC_Product_Variable::sync( $product );
}
To recalculate all variable products (run once via WP-CLI or a one-time script):
$variable_products = wc_get_products([
'type' => 'variable',
'limit' => -1,
'return' => 'ids',
]);
foreach ( $variable_products as $id ) {
WC_Product_Variable::sync( $id );
}
On large catalogs, run this in batches of 50–100 with sleep(1) between iterations to avoid overwhelming the database. If you're on managed hosting with WP-CLI access, this is the cleanest approach — no GUI required.
Displaying Variation Prices on Shop/Archive Pages
By default, WooCommerce archive pages (shop, category, search results) show the parent product's price range using the same cached values. The loop template calls $product->get_price_html() which returns the range.
If you want archive pages to behave differently — for example, only showing the minimum price with a "from" prefix — hook into woocommerce_variable_price_html as shown earlier. That filter applies globally, so archive and single product pages are both affected.
To target only archive pages:
add_filter( 'woocommerce_variable_price_html', function( $price, $product ) {
if ( ! is_singular( 'product' ) ) {
$prices = $product->get_variation_prices( true );
$min = current( $prices['price'] );
return sprintf( __( 'From %s', 'your-textdomain' ), wc_price( $min ) );
}
return $price;
}, 10, 2 );
WooCommerce HPOS and Variation Pricing Compatibility
If you've migrated to High-Performance Order Storage, variation pricing itself is unaffected — prices are stored on product meta, not order tables. However, if your pricing logic queries order history (dynamic pricing by purchase count, loyalty tiers, etc.), verify your queries use wc_get_orders() instead of direct $wpdb calls on wp_posts. See our WooCommerce HPOS migration guide for a full compatibility checklist.
Plugin vs Custom Code: When to Use Each
| Approach | Best For | Risk |
|---|---|---|
woocommerce_variable_price_html filter | Simple format changes | Low — pure filter, no DB writes |
| WooCommerce built-in bulk edit | Updating prices in admin | Low |
Programmatic sync via WC_Product_Variable::sync() | Imports, bulk CLI updates | Medium — test on staging first |
| A pricing plugin (e.g. WooCommerce Dynamic Pricing) | Tiered, role-based, quantity pricing | Higher — adds queries per request |
Theme override of single-product/price.php | Layout restructuring | Medium — breaks on theme updates without child theme |
For most display customizations, a filter in a site plugin is the right call. Plugins that add dynamic pricing rules introduce per-request database overhead — benchmark their impact on your product pages using Query Monitor before enabling on production.
If you need to temporarily take the store offline while you apply bulk pricing changes, the WooCommerce store maintenance mode guide covers how to do that without breaking SEO or losing in-flight orders.
Testing Variation Price Changes Safely
Variation price changes — especially bulk recalculations or filter modifications — should always be validated on staging before hitting production. Things to verify:
- Range display — Does the parent product show the correct min/max on shop and single product pages?
- Selection update — Does selecting each variation update the displayed price correctly?
- Sale price logic — Are strikethrough prices (
<del>) appearing only where expected? - Archive pages — Does the loop display match your intended format?
- JavaScript errors — Open the browser console and trigger variation selection; confirm no JS errors.
- Caching layer — Purge page cache and object cache after changes, then retest. Cached HTML containing old prices will persist until purged.
TopSyde managed WooCommerce hosting includes one-click staging environments on every plan starting at $89/month — see our hosting plans and pricing for details. For stores running complex pricing logic, review our WooCommerce hosting for ecommerce stores article, which covers the infrastructure requirements that prevent pricing-related slowdowns at scale.
Frequently Asked Questions
Why does my WooCommerce variable product show $0 in the price range?
A $0 in the range means at least one variation has its Regular price set to 0 or left blank but treated as 0 by WooCommerce. Open the Variations tab, sort by price, and find any variation without a Regular price set. Either add a price or set the variation to "Draft" status if it shouldn't be purchasable. After fixing, run WC_Product_Variable::sync() to refresh the cached range.
How do I stop the price from showing a range and just show the lowest price?
Use the woocommerce_variable_price_html filter to intercept the default range HTML and return a formatted single price using wc_price( current( $product->get_variation_prices()['price'] ) ). Optionally prefix it with "From" for clarity. This approach requires no plugin and has no performance overhead since it only modifies the output string, not the underlying data.
Why doesn't the price update when a customer selects a variation?
The most common causes are a JavaScript conflict that prevents woocommerce-add-to-cart-variation.js from initializing, a page caching plugin serving stale HTML that strips the variation JSON payload, or a swatches plugin that replaces native <select> elements without triggering WooCommerce's change event listeners. Check the browser console for JS errors first, then disable caching temporarily to isolate the cause.
Does changing the price range display format affect SEO or structured data?
The filter woocommerce_variable_price_html only changes the visible HTML price string. WooCommerce outputs structured data (Schema.org Product with offers) separately — it uses the raw price values from the database, not the filtered display HTML. Changing your display format will not affect how Google reads your product prices in rich results.
How often does WooCommerce recalculate the min/max price cache?
WooCommerce recalculates the cached min/max on save when a variation or the parent product is updated through the admin. It does not automatically recalculate on a schedule. If you update prices via direct database writes, WP-CLI scripts, or import plugins that bypass WooCommerce hooks, you must call WC_Product_Variable::sync() manually to keep the displayed range accurate.

Content & SEO Strategist
7+ years SEO & content strategy, Google Analytics certified
Elena drives content strategy and SEO at TopSyde, helping clients maximize organic visibility and AI search presence. She combines technical WordPress knowledge with data-driven content optimization.



