Shopify Development

Shopify Variant Pricing Fix: Displaying Accurate Prices on Collection Pages

Hey there, fellow store owners! It's your Shopify migration expert here at Shopping Cart Mover, diving into a super common, yet incredibly frustrating, pricing quirk that often pops up on collection pages. You know the one: your product card shows a super low price, only for customers to click through and find that variant is sold out, or the actual available price is much higher. Talk about a bait-and-switch feeling!

This exact scenario recently came up in the Shopify community, and it was a perfect example of how small code tweaks can make a huge difference in customer experience and conversions. Let's dig into a recent thread where a store owner, GamesRealm, tackled this head-on.

Liquid code snippet for finding the cheapest available Shopify variant
Liquid code snippet for finding the cheapest available Shopify variant

The Problem: Misleading Variant Prices on Collection Pages

GamesRealm runs an awesome store, Games Realm, specializing in Pokémon singles. They noticed a significant issue: on their collection pages, products like "Conkeldurr 65/101" were displaying the lowest variant price ($2 for a 'poor' condition card) even though that specific condition was out of stock. The highest available variant ('Excellent') was $2.40, but the collection page stubbornly showed the $2 price. This is a classic example of a theme defaulting to the absolute lowest price (often derived from product.price_min) without checking for variant availability.

GamesRealm had already tried a Shopify guide to edit their price.liquid file, but it hadn't solved the problem, leading them to seek help from the community. This scenario is more common than you might think, especially when dealing with products that have many variants with varying prices and stock levels, such as collectibles, apparel, or custom items.

Why Does This Happen? Understanding Shopify's Price Logic

By default, many Shopify themes are designed to display the lowest possible price for a product on collection pages. This is often achieved by simply referencing product.price or product.price_min. While this can sometimes be effective for showcasing competitive pricing, it falls short when the lowest-priced variant is out of stock. The theme's Liquid code, typically found within a snippet like price.liquid, might not explicitly filter for available variants when determining the price to display.

The original code snippet GamesRealm was using likely looked something like this, or a variation thereof, where target.price could inadvertently pull the price of an unavailable variant:

{%- liquid
     if use_variant
        assign target = product.selected_or_first_available_variant
    else
        assign target = product
    endif

    assign compare_at_price = target.compare_at_price
    assign price = target.price | default: 1999
    assign available = target.available | default: false
    # ... rest of the price rendering logic

The critical flaw here is that target.price (when target is the overall product) often defaults to the minimum price across all variants, regardless of their availability. This leads directly to the misleading prices GamesRealm experienced.

The Solution: Finding the Cheapest Available Variant

Mustafa_Ali, a helpful community member, quickly jumped in to offer a robust solution. The core idea was to modify the price.liquid snippet to explicitly look for the cheapest available variant rather than just the lowest-priced one overall. This ensures that the price displayed on collection pages accurately reflects what a customer can actually purchase.

Step-by-Step Implementation Guide:

  1. Backup Your Theme: Before making any code changes, always duplicate your live theme. This provides a safety net if anything goes wrong.
  2. Navigate to Theme Code: From your Shopify admin, go to Online Store > Themes. Find your current theme, click Actions, and then Edit code.
  3. Locate price.liquid: In the file search bar, look for the Snippets folder and then find price.liquid. This is the most common location for this pricing logic, though some themes might use different file names or structures (e.g., product-card-price.liquid).
  4. Replace the Content: Delete the existing content of your price.liquid file and paste the following corrected code. This snippet intelligently filters for available variants and sorts them to find the true starting price.
{%- comment -%}
    Renders a list of product's price (regular, sale)

    Accepts:
    - product: {Object} Product Liquid object (optional)
    - use_variant: {Boolean} Renders selected or first variant price instead of overall product pricing (optional)
    - show_badges: {Boolean} Renders 'Sale' and 'Sold Out' tags if the product matches the condition (optional)
    - price_class: {String} Adds a price class to the price element (optional)

    Usage:
    {% render 'price', product: product %}
{%- endcomment -%}

{%- liquid
    if use_variant
        assign target = product.selected_or_first_available_variant
    else
        assign target = product
    endif

    comment
      FIX: Instead of using product.price (which is price_min and can include
      unavailable variants), we find the cheapest AVAILABLE variant explicitly.
      This ensures collection pages show the correct in-stock starting price.
    endcomment

    assign available_variants = product.variants | where: 'available', true

    if available_variants.size > 0
        assign first_available = available_variants | sort: 'price' | first
        assign compare_at_price = first_available.compare_at_price
        assign price = first_available.price
        assign available = true
    else
        assign compare_at_price = target.compare_at_price
        assign price = target.price | default: 1999
        assign available = target.available | default: false
    endif

    if settings.currency_format_enable
        assign m | money_with_currency
    else
        assign m | money
    endif

    if target == product and product.price_varies
        assign m | t: price: money_price
    endif
-%}

{%- comment -%} Explanation of description list: - div.price__regular: Displayed when there are no variants on sale - div.price__sale: Displayed when a variant is on sale - div.price__availability: Displayed when the product is sold out {%- endcomment -%}
{{ money_price }}
{%- if settings.currency_format_enable -%} {{ compare_at_price | money_with_currency }} {%- else -%} {{ compare_at_price | money }} {%- endif -%}
{{ money_price }}
{%- if settings.show_saved_price and price != nil and price != blank and compare_at_price != nil and compare_at_price != blank -%} {%- assign saved_price = compare_at_price | minus: price | money -%}
{{ 'products.product.price.saved_price_html' | t: price: saved_price }}
{%- endif -%} {%- if settings.show_price_percent -%}
{%- liquid assign list_compare = product.variants | where: 'compare_at_price' assign compare = 0 for variant in list_compare assign saving = variant.compare_at_price | minus: variant.price | times: 100.0 | divided_by: variant.compare_at_price | round if saving > compare assign compare = saving endif endfor if compare < 1 assign compare = product.compare_at_price_max | minus: product.price_max | times: 100.0 | divided_by: product.compare_at_price_max | round endif -%} (-{{ compare | append: '%' }})
{%- endif -%}
{{ 'products.product.price.unit_price' | t }}
{{- product.selected_or_first_available_variant.unit_price | money -}}  {{ 'accessibility.unit_price_separator' | t }}  {%- if product.selected_or_first_available_variant.unit_price_measurement.reference_value != 1 -%} {{- product.selected_or_first_available_variant.unit_price_measurement.reference_value -}} {%- endif -%} {{ product.selected_or_first_available_variant.unit_price_measurement.reference_unit }}
  1. Save and Test: Click "Save" and then thoroughly test your collection pages. Verify that products now display the price of the cheapest available variant. Test products with various stock levels and variant prices.

Breaking Down the Key Liquid Logic:

  • assign available_variants = product.variants | where: 'available', true: This crucial line filters all product variants, keeping only those that are currently in stock.
  • if available_variants.size > 0: Checks if there's at least one available variant.
  • assign first_available = available_variants | sort: 'price' | first: If available variants exist, this line sorts them by price in ascending order and then selects the very first one, effectively identifying the cheapest available variant.
  • assign price = first_available.price: The displayed price is now correctly set to the price of this cheapest available variant.

Important Considerations for Theme Customization

While this fix is highly effective, it's essential to keep a few best practices in mind, especially when dealing with theme code:

  • Scope of the Fix: Collection Pages vs. Product Pages: As pointed out by a keen community member, tim_1, this snippet is primarily intended for product cards on collection pages. On individual product pages, Shopify typically relies on product.selected_or_first_available_variant which dynamically updates the price based on user selection or the first available variant. Applying this exact logic to product pages might interfere with dynamic variant selection. Always ensure your edits are contextually appropriate.
  • Theme Updates: Be aware that future theme updates from your theme developer could potentially overwrite your custom code. It's a good practice to document your changes and be prepared to re-apply them after an update, or consider using a child theme if your theme supports it.
  • Thorough Testing: After any code modification, test extensively across different browsers, devices, and product types. Check products with single variants, multiple variants, out-of-stock variants, and sale items.
  • User Experience and Trust: Accurate pricing builds customer trust and reduces frustration. Customers are more likely to convert when they see consistent, reliable information from collection page to product page.
  • SEO Benefits: Consistent pricing signals to search engines that your product data is accurate, potentially improving your product listings' quality and visibility.

Beyond the Fix: Expert Shopify Development and Migrations

This scenario highlights a common challenge in Shopify development: ensuring that your theme's logic perfectly aligns with your business needs and provides an optimal customer experience. While a single code snippet can solve a specific problem, complex issues often arise during:

  • Platform Migrations: Moving from another e-commerce platform to Shopify often uncovers subtle differences in how product data, variants, and pricing are handled. Our team at Shopping Cart Mover specializes in seamless migrations, ensuring all your data, including intricate pricing logic, is accurately transferred and optimized for Shopify.
  • Custom Theme Development: Building a custom theme or heavily customizing an existing one requires deep Liquid and Shopify API knowledge to avoid such pitfalls.
  • Integrating Third-Party Apps: Sometimes, pricing discrepancies can emerge when third-party apps modify product data or display logic.

At Shopping Cart Mover, we don't just move your store; we optimize it. Our experts can help you audit your theme code, implement custom solutions, and ensure your Shopify store is performing at its best, providing a flawless experience for your customers from the moment they land on your collection page.

Don't let misleading prices cost you sales. If you're facing similar challenges or planning a complex migration, reach out to us. We're here to ensure your Shopify store is not just functional, but exceptional.

Share:

Use cases

Explore use cases

Agencies, store owners, enterprise — find the migration path that fits.

Explore use cases