Back to Blog

Shopify Liquid Mistakes I Check First in Theme Audits

K
Karan Goyal
--6 min read

Real Shopify Liquid mistakes from theme audits: render scope, pagination limits, image guards, layout shift, and business logic that does not belong in templates.

Shopify Liquid Mistakes I Check First in Theme Audits

Most Liquid mistakes I get paid to fix are not syntax errors. They are small theme decisions that quietly damage speed, break variants, or make future edits painful: a section loops too much, a snippet depends on a variable it was never passed, an image tag ships without width and height, or a condition works in JavaScript but not in Liquid.

This is the checklist I use when I audit a Shopify theme before touching the design. If a store owner says the theme feels slow or random blocks keep breaking, these are the first places I look.

1. Looping Past Liquid Limits Instead of Paginating

Liquid for loops are capped. If you build a collection template and expect every product to render because the collection has 200 items, the template will not behave the way a React or Node loop would. For collection pages, paginate intentionally and keep the item count realistic for mobile.

liquid
{% paginate collection.products by 24 %}
  <div class="product-grid">
    {% for product in collection.products %}
      {% render 'card-product', product: product %}
    {% endfor %}
  </div>

  {{ paginate | default_pagination }}
{% endpaginate %}

What I check in audits: collection templates, search templates, vendor pages, tag pages, and any custom section that loops over products, articles, or metaobjects. If the loop can grow, it needs pagination or a stricter limit.

2. Assuming Snippets Share Scope

The render tag is isolated. That is good for maintainability, but it catches teams that expect a snippet to magically see every variable from the parent template. Pass the values the snippet needs.

liquid
{% comment %}Risky: card-product may not receive the variables you think it has.{% endcomment %}
{% render 'card-product' %}

{% comment %}Better: pass the contract explicitly.{% endcomment %}
{% render 'card-product', product: product, show_vendor: section.settings.show_vendor %}

This one matters for SEO too. Product card snippets often control image alt text, vendor names, prices, badges, and links. If the snippet contract is vague, a harmless homepage edit can turn into missing product links or empty card content.

3. Writing JavaScript-Style Conditions in Liquid

Liquid is not JavaScript. Parentheses and ternary shortcuts are common sources of broken theme edits. Keep conditions simple, or split them into nested checks. The result is more verbose, but it is easier for Shopify merchants and theme developers to maintain.

liquid
{% if product.available %}
  {% if product.price > 5000 %}
    <span class="badge">Premium pick</span>
  {% endif %}
{% endif %}

I prefer this style in client themes because the next developer can read it without guessing how Liquid parses a clever expression. Clever Liquid usually becomes fragile Liquid.

4. Not Guarding Optional Media

A lot of theme bugs start with products, collections, or articles that do not have the image the section assumes exists. The page may render fine on the demo product and fail on a real catalog item imported from an ERP, marketplace feed, or old WooCommerce migration.

liquid
{% if product.featured_image %}
  {{ product.featured_image
    | image_url: width: 900
    | image_tag:
      loading: 'lazy',
      widths: '300, 600, 900',
      alt: product.featured_image.alt | default: product.title
  }}
{% else %}
  <div class="product-card__placeholder" aria-hidden="true"></div>
{% endif %}

This is especially important for collection cards, related products, cart upsells, blog article cards, and search results. Those surfaces are usually fed by mixed data quality.

5. Creating Layout Shift With Images

A Shopify theme can look fast in a Lighthouse run and still feel jumpy to shoppers if images do not reserve space. The fix is not only compression. The HTML needs predictable dimensions, responsive widths, and lazy loading where the image is below the first viewport.

  • Use Shopify image_url and image_tag instead of hand-building raw img URLs when possible.
  • Set width candidates that match the component, not the original 4000px upload.
  • Keep the first hero/product image eager only when it is genuinely above the fold.
  • Do not lazy-load every image blindly; the LCP image often needs priority treatment.

6. Using contains on the Wrong Data Shape

Liquid contains is fine for strings and simple arrays. It is not a magic object search. I see this most often in product-tag logic, navigation handles, and custom metafield arrays. If you are checking tags, check tags. If you are checking product objects, loop and compare the field you actually care about.

liquid
{% assign has_preorder_tag = false %}
{% for tag in product.tags %}
  {% if tag == 'preorder' %}
    {% assign has_preorder_tag = true %}
    {% break %}
  {% endif %}
{% endfor %}

{% if has_preorder_tag %}
  <span class="badge">Pre-order</span>
{% endif %}

That looks longer than a one-line contains check, but it is explicit and safe when the data shape is not guaranteed.

7. Putting Business Logic Inside the Theme

Liquid should present data; it should not become the source of truth for pricing rules, inventory policy, customer segmentation, or discount eligibility. When theme files start collecting giant if/elsif blocks, updates become risky and hard to test.

My rule: if changing the rule would require a merchant to call a developer, the rule probably does not belong hardcoded in a Liquid template.

For serious logic, use Shopify Functions, app-owned metafields/metaobjects, Shopify Flow, or a proper custom app. Keep the theme focused on rendering the current state clearly.

8. Shipping Theme Changes Without Testing the Bad Data

The happy path rarely catches Liquid bugs. Before I ship theme changes, I test the awkward catalog states: product with no image, product with 50 variants, sold-out product, long option names, missing metafields, collection with one product, collection with more than 50 products, and a cart containing subscription or bundle items.

That is the practical difference between a theme that works in preview and a theme that survives a real store.

A Better Liquid Review Checklist

  • Every growing product/article loop is paginated or intentionally limited.
  • Every snippet receives its required variables through render parameters.
  • Conditions use Liquid-friendly nested checks instead of JavaScript-style cleverness.
  • Optional images, metafields, variants, and collection data are guarded.
  • Image tags reserve space and use sensible widths.
  • Theme code renders data; business rules live in the right Shopify surface.
  • The theme is tested against messy real catalog data, not only demo products.

When I Would Refactor Instead of Patch

If a Liquid file has more than a few responsibilities, I do not keep adding conditionals. I split product cards, price blocks, media galleries, and badges into snippets with explicit parameters. That gives the theme a smaller blast radius: a badge change does not accidentally alter product card layout, and a collection template can reuse the same rendering contract as search or recommendations.

That kind of cleanup is not glamorous, but it is usually what makes a Shopify theme faster to edit and safer to scale.

  • Use the Liquid Analyzer on this site to catch risky patterns before editing a live theme.
  • Use the Liquid Formatter when inherited theme files are hard to read.
  • For API-heavy storefronts, review the Shopify GraphQL vs REST comparison and the Shopify API rate limits guide.

Sources

  • Shopify Liquid tag reference: liquid, render, paginate, and form tags.
  • Shopify theme architecture guidance for sections, snippets, blocks, and schema.
  • Shopify image filters and image_tag usage for responsive storefront media.

Tags

#Shopify Development#Liquid#E-commerce Best Practices#Web Development

Share this article

📬 Get notified about new tools & tutorials

No spam. Unsubscribe anytime.

Comments (0)

Leave a Comment

0/2000

No comments yet. Be the first to share your thoughts!