shopify-liquid
SKILL.md
Shopify Liquid Templating
Expert guidance for Shopify's Liquid templating language including complete syntax reference, filters, objects, and best practices.
When to Use This Skill
Invoke this skill when:
- Working with
.liquid,.css.liquid, or.js.liquidfiles - Creating or modifying theme templates (product, collection, cart, etc.)
- Implementing dynamic content rendering
- Using Liquid filters to format data (money, dates, strings)
- Accessing Shopify objects (product, collection, cart, customer)
- Writing conditional logic or loops in templates
- Debugging Liquid syntax errors or output issues
- Creating sections or snippets with Liquid logic
- Formatting prices, dates, or other data
Core Capabilities
1. Liquid Syntax Fundamentals
Three core syntax types:
Output (display values):
{{ product.title }}
{{ product.price | money }}
{{ collection.products.size }}
Logic (conditionals and control):
{% if product.available %}
<button>Add to Cart</button>
{% else %}
<p>Sold Out</p>
{% endif %}
Assignment (variables):
{% assign sale_price = product.price | times: 0.8 %}
{% capture full_title %}{{ collection.title }} - {{ product.title }}{% endcapture %}
Whitespace control:
{%- if condition -%}
Content (strips whitespace)
{%- endif -%}
2. Control Flow Tags
Conditionals:
if/elsif/else/endif- Standard conditionalsunless/endunless- Negated ifcase/when/else/endcase- Switch statements
Logical operators:
and,or- Combine conditions==,!=,>,<,>=,<=- Comparisonscontains- Substring/array search
Example:
{% if product.available and product.price < 100 %}
Affordable and in stock
{% elsif product.available %}
Available but pricey
{% else %}
Out of stock
{% endif %}
3. Iteration (Loops)
for loop:
{% for product in collection.products %}
{{ product.title }}
{% endfor %}
{# With modifiers #}
{% for product in collection.products limit: 5 offset: 10 reversed %}
{{ product.title }}
{% endfor %}
forloop object:
{% for item in array %}
{{ forloop.index }} {# 1-based index #}
{{ forloop.index0 }} {# 0-based index #}
{{ forloop.first }} {# Boolean: first item #}
{{ forloop.last }} {# Boolean: last item #}
{{ forloop.length }} {# Total items #}
{% endfor %}
Pagination:
{% paginate collection.products by 12 %}
{% for product in paginate.collection.products %}
{% render 'product-card', product: product %}
{% endfor %}
{% if paginate.pages > 1 %}
{{ paginate | default_pagination }}
{% endif %}
{% endpaginate %}
4. Essential Filters
Money formatting:
{{ 1000 | money }} {# $10.00 #}
{{ 1000 | money_without_currency }} {# 10.00 #}
{{ 1000 | money_without_trailing_zeros }} {# $10 #}
String manipulation:
{{ "hello" | upcase }} {# HELLO #}
{{ "hello" | capitalize }} {# Hello #}
{{ "hello world" | truncate: 8 }} {# hello... #}
{{ "a,b,c" | split: "," }} {# ["a","b","c"] #}
{{ text | strip_html }} {# Remove HTML tags #}
Array/collection:
{{ array | first }} {# First element #}
{{ array | last }} {# Last element #}
{{ array | size }} {# Count #}
{{ products | map: "title" }} {# Extract property #}
{{ products | where: "vendor", "Nike" }} {# Filter #}
{{ products | sort: "price" }} {# Sort #}
{{ array | join: ", " }} {# Join with separator #}
Date formatting:
{{ order.created_at | date: '%B %d, %Y' }} {# November 10, 2025 #}
{{ order.created_at | date: '%m/%d/%Y' }} {# 11/10/2025 #}
{{ order.created_at | date: '%H:%M %p' }} {# 12:39 PM #}
Image handling:
{{ product.image | img_url: '500x500' }} {# Resize image #}
{{ product.image | img_url: 'medium' }} {# Named size #}
{{ 'logo.png' | asset_url }} {# Theme asset CDN #}
Math operations:
{{ 5 | plus: 3 }} {# 8 #}
{{ 5 | minus: 3 }} {# 2 #}
{{ 5 | times: 3 }} {# 15 #}
{{ 10 | divided_by: 2 }} {# 5 #}
{{ 1.567 | round: 2 }} {# 1.57 #}
Chaining filters:
{{ collection.products | where: "available" | map: "title" | sort | first }}
5. Key Shopify Objects
Product object:
{{ product.title }}
{{ product.price | money }}
{{ product.available }} {# Boolean #}
{{ product.vendor }}
{{ product.type }}
{{ product.images }} {# Array #}
{{ product.variants }} {# Array #}
{{ product.selected_variant }}
{{ product.metafields.custom.field }}
Collection object:
{{ collection.title }}
{{ collection.products }} {# Array #}
{{ collection.products_count }}
{{ collection.all_tags }}
{{ collection.sort_by }}
{{ collection.filters }}
Cart object (global):
{{ cart.item_count }}
{{ cart.total_price | money }}
{{ cart.items }} {# Array of line items #}
{{ cart.empty? }} {# Boolean #}
Customer object:
{{ customer.name }}
{{ customer.email }}
{{ customer.orders_count }}
{{ customer.total_spent | money }}
{{ customer.default_address }}
Global objects:
{{ shop.name }}
{{ shop.currency }}
{{ shop.url }}
{{ request.path }}
{{ request.page_type }} {# "product", "collection", etc. #}
{{ settings.color_primary }} {# Theme settings #}
6. Template Inclusion
render (isolated scope - PREFERRED):
{% render 'product-card', product: product, show_price: true %}
{# Render for each item #}
{% render 'product-card' for collection.products as item %}
include (shared scope - LEGACY):
{% include 'product-details' %}
section (dynamic sections):
{% section 'featured-product' %}
Common Patterns
Product availability check
{% if product.available %}
<button type="submit">Add to Cart</button>
{% elsif product.selected_variant.incoming %}
<p>Coming {{ product.selected_variant.incoming_date | date: '%B %d' }}</p>
{% else %}
<p class="sold-out">Sold Out</p>
{% endif %}
Price display with sale
{% if product.compare_at_price > product.price %}
<span class="sale-price">{{ product.price | money }}</span>
<span class="original-price">{{ product.compare_at_price | money }}</span>
<span class="savings">Save {{ product.compare_at_price | minus: product.price | money }}</span>
{% else %}
<span class="price">{{ product.price | money }}</span>
{% endif %}
Loop through variants
{% for variant in product.variants %}
<option
value="{{ variant.id }}"
{% unless variant.available %}disabled{% endunless %}
>
{{ variant.title }} - {{ variant.price | money }}
</option>
{% endfor %}
Check collection tags
{% if collection.all_tags contains 'sale' %}
<div class="sale-banner">Sale items available!</div>
{% endif %}
Best Practices
- Use whitespace control (
{%-and-%}) to keep HTML clean - Prefer
renderoverincludefor better performance and isolation - Cache expensive operations by assigning to variables
- Use descriptive variable names for clarity
- Leverage filters instead of complex logic when possible
- Check for existence before accessing nested properties
- Use
defaultfilter for fallback values:{{ product.metafield | default: "N/A" }}
Detailed References
For comprehensive documentation:
- references/syntax.md - Complete syntax reference with all tags
- references/filters.md - All 60+ filters with examples
- references/objects.md - Complete object property reference
Integration with Other Skills
- shopify-theme-dev - Use when working with theme file structure and sections
- shopify-api - Use when fetching data via Ajax or GraphQL to display in Liquid
- shopify-debugging - Use when troubleshooting Liquid rendering issues
- shopify-performance - Use when optimizing Liquid template performance
Quick Syntax Reference
{# Output #}
{{ variable }}
{{ product.title | upcase }}
{# Conditionals #}
{% if condition %}...{% elsif %}...{% else %}...{% endif %}
{% unless condition %}...{% endunless %}
{% case variable %}{% when value %}...{% endcase %}
{# Loops #}
{% for item in array %}...{% endfor %}
{% for item in array limit: 5 offset: 10 %}...{% endfor %}
{% break %} / {% continue %}
{# Variables #}
{% assign var = value %}
{% capture var %}content{% endcapture %}
{# Inclusion #}
{% render 'snippet', param: value %}
{% section 'section-name' %}
{# Comments #}
{% comment %}...{% endcomment %}
{# Single line #}
Weekly Installs
1
Repository
toilahuongg/google-antigravity-kitInstalled on
windsurf1
opencode1
codex1
claude-code1
antigravity1
gemini-cli1