liquid-templating
Skill48 starsChanged 9 months agoMITView on GitHub
Master Shopify Liquid templating language. Use this skill for writing Liquid code, using objects, filters, and tags, accessing product/collection/cart data, creating dynamic content, handling conditionals and loops, and working with Liquid best practices. Essential for theme customization.
In this repository7 other files it gives its agents.
- api-graphqlSkill
- app-developmentSkill
- checkout-customizationSkill
- cli-toolsSkill
- headless-hydrogenSkill
- shopify-functionsSkill
- theme-developmentSkill
The file
We split this skill into the rules it gives an agent
5 rules. About 0 are common, 2 are distinctive, and 3 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
3
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 16
Use this skill when:
- Very specific: line 40
Use logic with {% %} tags:
- Very specific: line 52
Use - to strip whitespace:
- Distinctive: line 489
Leverage caching: - Use Liquid responsibly within sections
- Very specific: line 490
Handle blank states: - Always check for blank or empty arrays
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Shopify Liquid Templating
When to use this skill
Use this skill when:
- Writing Liquid template code
- Accessing Shopify data (products, collections, cart, etc.)
- Using Liquid filters to transform output
- Creating conditional logic and loops
- Building dynamic theme content
- Debugging Liquid code issues
- Optimizing Liquid performance
Liquid Basics
Output Tags
Output data using double curly braces:
{{ product.title }}
{{ shop.name }}
{{ 'hello' | upcase }}Logic Tags
Use logic with {% %} tags:
{% if product.available %}
<p>In Stock</p>
{% else %}
<p>Sold Out</p>
{% endif %}Whitespace Control
Use - to strip whitespace:
{%- if condition -%}
content
{%- endif -%}Core Objects
Product Object
{{ product.title }}
{{ product.description }}
{{ product.price | money }}
{{ product.compare_at_price | money }}
{{ product.vendor }}
{{ product.type }}
{{ product.tags | join: ', ' }}
{{ product.available }}
{{ product.url }}
<!-- Featured Image -->
{{ product.featured_image | image_url: width: 500 | image_tag }}
<!-- All Images -->
{% for image in product.images %}
{{ image | image_url: width: 300 | image_tag }}
{% endfor %}
<!-- Variants -->
{% for variant in product.variants %}
{{ variant.title }} - {{ variant.price | money }}
{% endfor %}
<!-- Metafields -->
{{ product.metafields.custom.care_instructions }}Collection Object
{{ collection.title }}
{{ collection.description }}
{{ collection.products_count }}
{{ collection.url }}
{% for product in collection.products %}
{{ product.title }}
{% endfor %}
<!-- Pagination -->
{% paginate collection.products by 12 %}
{% for product in collection.products %}
{% render 'product-card', product: product %}
{% endfor %}
{{ paginate | default_pagination }}
{% endpaginate %}Cart Object
{{ cart.item_count }}
{{ cart.total_price | money }}
{{ cart.total_weight | weight_with_unit }}
{% for item in cart.items %}
{{ item.product.title }}
{{ item.variant.title }}
{{ item.quantity }}
{{ item.line_price | money }}
{% endfor %}
<!-- Cart Attributes -->
{{ cart.attributes.gift_message }}
<!-- Cart Note -->
{{ cart.note }}Customer Object
{% if customer %}
Hello, {{ customer.first_name }}!
{{ customer.email }}
{{ customer.orders_count }} orders
{{ customer.total_spent | money }}
{% for address in customer.addresses %}
{{ address.street }}
{{ address.city }}, {{ address.province }}
{% endfor %}
{% else %}
<a href="/account/login">Log in</a>
{% endif %}Shop Object
{{ shop.name }}
{{ shop.email }}
{{ shop.domain }}
{{ shop.money_format }}
{{ shop.currency }}
{{ shop.enabled_currencies }}Request Object
{{ request.locale.iso_code }}
{{ request.page_type }}
{{ request.path }}
{{ request.host }}Essential Filters
String Filters
{{ 'hello world' | capitalize }} <!-- Hello world -->
{{ 'hello world' | upcase }} <!-- HELLO WORLD -->
{{ 'HELLO' | downcase }} <!-- hello -->
{{ ' hello ' | strip }} <!-- hello -->
{{ 'hello' | append: ' world' }} <!-- hello world -->
{{ 'hello world' | prepend: 'say ' }} <!-- say hello world -->
{{ 'hello' | replace: 'e', 'a' }} <!-- hallo -->
{{ 'hello world' | split: ' ' }} <!-- ['hello', 'world'] -->
{{ 'hello world' | truncate: 8 }} <!-- hello... -->
{{ 'hello world' | truncatewords: 1 }} <!-- hello... -->
{{ 'hello' | size }} <!-- 5 -->Number Filters
{{ 4.5 | ceil }} <!-- 5 -->
{{ 4.5 | floor }} <!-- 4 -->
{{ 4.567 | round: 2 }} <!-- 4.57 -->
{{ 5 | plus: 3 }} <!-- 8 -->
{{ 5 | minus: 3 }} <!-- 2 -->
{{ 5 | times: 3 }} <!-- 15 -->
{{ 10 | divided_by: 3 }} <!-- 3 -->
{{ 10 | modulo: 3 }} <!-- 1 -->
{{ 1234.56 | money }} <!-- $1,234.56 -->
{{ 1234.56 | money_without_currency }} <!-- 1,234.56 -->Array Filters
{{ array | first }}
{{ array | last }}
{{ array | size }}
{{ array | join: ', ' }}
{{ array | sort }}
{{ array | sort: 'price' }}
{{ array | reverse }}
{{ array | uniq }}
{{ array | compact }}
{{ array | concat: other_array }}
{{ array | map: 'title' }}
{{ array | where: 'available', true }}URL Filters
{{ 'products' | url }}
{{ product.url | within: collection }}
{{ 'style.css' | asset_url }}
{{ 'image.png' | asset_url }}
{{ 'logo.png' | file_url }}
{{ product.featured_image | image_url: width: 500 }}
{{ product | product_image_url: 'master' }}Image Filters
<!-- Modern image_url approach (recommended) -->
{{ image | image_url: width: 800 }}
{{ image | image_url: width: 800, height: 600, crop: 'center' }}
{{ image | image_url: width: 800 | image_tag }}
<!-- Responsive images -->
{{ image | image_url: width: 1200 | image_tag:
loading: 'lazy',
widths: '300, 600, 900, 1200',
sizes: '(max-width: 600px) 100vw, 50vw'
}}
<!-- With alt text -->
{{ image | image_url: width: 500 | image_tag: alt: product.title }}Money Filters
{{ product.price | money }} <!-- $10.00 -->
{{ product.price | money_with_currency }} <!-- $10.00 USD -->
{{ product.price | money_without_trailing_zeros }} <!-- $10 -->
{{ product.price | money_without_currency }} <!-- 10.00 -->Date Filters
{{ article.created_at | date: '%B %d, %Y' }} <!-- January 15, 2025 -->
{{ article.created_at | date: '%Y-%m-%d' }} <!-- 2025-01-15 -->
{{ 'now' | date: '%H:%M' }} <!-- 14:30 -->Control Flow
Conditionals
{% if product.available %}
In Stock
{% elsif product.compare_at_price %}
Sale
{% else %}
Sold Out
{% endif %}
<!-- Unless (opposite of if) -->
{% unless product.available %}
Sold Out
{% endunless %}
<!-- Case/When -->
{% case product.type %}
{% when 'Shirt' %}
<p>It's a shirt!</p>
{% when 'Pants' %}
<p>It's pants!</p>
{% else %}
<p>Unknown type</p>
{% endcase %}Comparison Operators
{% if product.price > 1000 %}{% endif %}
{% if product.price >= 1000 %}{% endif %}
{% if product.price < 1000 %}{% endif %}
{% if product.price <= 1000 %}{% endif %}
{% if product.title == 'Hat' %}{% endif %}
{% if product.title != 'Hat' %}{% endif %}
{% if product.tags contains 'sale' %}{% endif %}
{% if product.title %}{% endif %} <!-- truthy check -->
{% if product.title == blank %}{% endif %} <!-- blank check -->Logical Operators
{% if product.available and product.price < 5000 %}
Affordable and in stock!
{% endif %}
{% if product.type == 'Shirt' or product.type == 'Pants' %}
It's clothing!
{% endif %}Loops
For Loop
{% for product in collection.products %}
{{ forloop.index }}: {{ product.title }}
{% endfor %}
<!-- With limit and offset -->
{% for product in collection.products limit: 4 offset: 2 %}
{{ product.title }}
{% endfor %}
<!-- Reversed -->
{% for product in collection.products reversed %}
{{ product.title }}
{% endfor %}
<!-- Forloop variables -->
{% for item in array %}
{{ forloop.index }} <!-- 1, 2, 3... -->
{{ forloop.index0 }} <!-- 0, 1, 2... -->
{{ forloop.first }} <!-- true on first -->
{{ forloop.last }} <!-- true on last -->
{{ forloop.length }} <!-- total items -->
{% endfor %}
<!-- Else for empty -->
{% for product in collection.products %}
{{ product.title }}
{% else %}
No products found.
{% endfor %}Cycle
{% for product in collection.products %}
<div class="{% cycle 'odd', 'even' %}">
{{ product.title }}
</div>
{% endfor %}Tablerow
<table>
{% tablerow product in collection.products cols: 3 %}
{{ product.title }}
{% endtablerow %}
</table>Variables
Assign
{% assign my_variable = 'Hello' %}
{% assign price_in_dollars = product.price | divided_by: 100.0 %}Capture
{% capture full_name %}
{{ customer.first_name }} {{ customer.last_name }}
{% endcapture %}
<p>Hello, {{ full_name }}!</p>Increment/Decrement
{% increment counter %} <!-- 0 -->
{% increment counter %} <!-- 1 -->
{% decrement counter %} <!-- -1 -->Snippets and Sections
Render Snippets
<!-- Basic render -->
{% render 'product-card' %}
<!-- With variables -->
{% render 'product-card', product: product %}
<!-- With multiple variables -->
{% render 'product-card', product: product, show_price: true %}
<!-- For loop with render -->
{% render 'product-card' for collection.products as product %}Section Tags
<!-- In layout file -->
{% section 'header' %}
{% sections 'footer-group' %}
<!-- Content placeholder -->
{{ content_for_layout }}
{{ content_for_header }}Forms
Product Form
{% form 'product', product %}
<select name="id">
{% for variant in product.variants %}
<option value="{{ variant.id }}">{{ variant.title }}</option>
{% endfor %}
</select>
<input type="number" name="quantity" value="1" min="1">
<button type="submit">Add to Cart</button>
{% endform %}Contact Form
{% form 'contact' %}
<input type="email" name="contact[email]" required>
<textarea name="contact[body]"></textarea>
<button type="submit">Send</button>
{% endform %}Customer Forms
<!-- Login -->
{% form 'customer_login' %}
<input type="email" name="customer[email]">
<input type="password" name="customer[password]">
<button type="submit">Log In</button>
{% endform %}
<!-- Register -->
{% form 'create_customer' %}
<input type="text" name="customer[first_name]">
<input type="text" name="customer[last_name]">
<input type="email" name="customer[email]">
<input type="password" name="customer[password]">
<button type="submit">Create Account</button>
{% endform %}Best Practices
- Use
rendernotinclude-renderis faster and scopes variables - Avoid complex logic in Liquid - Move to JavaScript when possible
- Use descriptive variable names -
{% assign product_price = ... %} - Leverage caching - Use Liquid responsibly within sections
- Handle blank states - Always check for
blankor empty arrays - Use schema defaults - Provide sensible defaults in section schemas
Common Patterns
Sale Badge
{% if product.compare_at_price > product.price %}
{% assign savings = product.compare_at_price | minus: product.price %}
{% assign percent_off = savings | times: 100.0 | divided_by: product.compare_at_price | round %}
<span class="sale-badge">{{ percent_off }}% OFF</span>
{% endif %}Variant Selector
{% unless product.has_only_default_variant %}
{% for option in product.options_with_values %}
<label>{{ option.name }}</label>
<select name="options[{{ option.name }}]">
{% for value in option.values %}
<option value="{{ value }}">{{ value }}</option>
{% endfor %}
</select>
{% endfor %}
{% endunless %}Resources
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

