# Liquid Syntax - Complete Reference ## Tag Categories ### Control Flow Tags #### if/elsif/else/endif ```liquid {% if product.available %} {% elsif product.coming_soon %}

Coming Soon

{% else %}

Sold Out

{% endif %} ``` **Operators:** - `==` - equals - `!=` - not equals - `>` - greater than - `<` - less than - `>=` - greater than or equal - `<=` - less than or equal - `contains` - substring or array contains - `and` - logical AND - `or` - logical OR **Examples:** ```liquid {% if product.price > 100 and product.available %} Premium item in stock {% endif %} {% if product.tags contains 'sale' or product.type == 'clearance' %} On sale! {% endif %} ``` #### unless Negated if statement: ```liquid {% unless customer.name == blank %} Hello, {{ customer.name }} {% endunless %} {# Equivalent to: #} {% if customer.name != blank %} Hello, {{ customer.name }} {% endif %} ``` #### case/when Switch-case statement: ```liquid {% case product.type %} {% when 'shoes' %} 👟 {% when 'boots' %} 👢 {% when 'sneakers' %} 👟 {% else %} 📦 {% endcase %} ``` ### Iteration Tags #### for loop ```liquid {% for product in collection.products %} {{ product.title }} {% endfor %} ``` **Modifiers:** ```liquid {# Limit to first 5 #} {% for product in collection.products limit: 5 %} {{ product.title }} {% endfor %} {# Skip first 10 #} {% for product in collection.products offset: 10 %} {{ product.title }} {% endfor %} {# Reverse order #} {% for product in collection.products reversed %} {{ product.title }} {% endfor %} {# Combine modifiers #} {% for product in collection.products limit: 5 offset: 10 %} {# Items 11-15 #} {% endfor %} ``` **forloop object (available inside loops):** ```liquid {% for item in array %} {{ forloop.index }} {# 1-based: 1, 2, 3, ... #} {{ forloop.index0 }} {# 0-based: 0, 1, 2, ... #} {{ forloop.rindex }} {# Reverse 1-based: 3, 2, 1 #} {{ forloop.rindex0 }} {# Reverse 0-based: 2, 1, 0 #} {{ forloop.first }} {# true on first iteration #} {{ forloop.last }} {# true on last iteration #} {{ forloop.length }} {# Total number of items #} {% endfor %} ``` **Example usage:** ```liquid {% for product in collection.products %} {% if forloop.first %}

Featured Product

{% endif %}
{{ product.title }}
{% if forloop.index == 3 %}
{# Divider after 3rd item #} {% endif %} {% if forloop.last %}

Showing {{ forloop.length }} products

{% endif %} {% endfor %} ``` #### break and continue ```liquid {% for product in collection.products %} {% if product.handle == 'target' %} {% break %} {# Exit loop entirely #} {% endif %} {% if product.available == false %} {% continue %} {# Skip to next iteration #} {% endif %} {{ product.title }} {% endfor %} ``` #### tablerow Creates HTML table rows: ```liquid {% tablerow product in collection.products cols: 3 %} {{ product.title }} {% endtablerow %} {# Output: #} ...
Product 1 Product 2 Product 3
Product 4
``` **tablerow object:** ```liquid {% tablerow product in products cols: 3 limit: 12 %} {{ tablerow.col }} {# Current column (1-based) #} {{ tablerow.col0 }} {# Current column (0-based) #} {{ tablerow.row }} {# Current row (1-based) #} {{ tablerow.index }} {# Item index (1-based) #} {{ tablerow.first }} {# true on first item #} {{ tablerow.last }} {# true on last item #} {{ tablerow.col_first }} {# true on first column #} {{ tablerow.col_last }} {# true on last column #} {% endtablerow %} ``` #### paginate For paginating large collections: ```liquid {% paginate collection.products by 12 %} {% for product in paginate.collection.products %} {% render 'product-card', product: product %} {% endfor %} {# Pagination controls #} {% if paginate.pages > 1 %} {{ paginate | default_pagination }} {% endif %} {% endpaginate %} ``` **paginate object:** ```liquid {{ paginate.current_page }} {# Current page number #} {{ paginate.pages }} {# Total pages #} {{ paginate.items }} {# Total items #} {{ paginate.page_size }} {# Items per page #} {{ paginate.previous.url }} {# Previous page URL (if exists) #} {{ paginate.previous.title }} {# Previous page title #} {{ paginate.previous.is_link }} {# Boolean #} {{ paginate.next.url }} {# Next page URL (if exists) #} {{ paginate.next.title }} {# Next page title #} {{ paginate.next.is_link }} {# Boolean #} {{ paginate.parts }} {# Array of page links #} ``` **Custom pagination:** ```liquid {% paginate collection.products by 20 %} {% endpaginate %} ``` ### Variable Assignment #### assign Single-line variable assignment: ```liquid {% assign sale_price = product.price | times: 0.8 %} {% assign is_available = product.available %} {% assign product_count = collection.products.size %} {% assign full_name = customer.first_name | append: ' ' | append: customer.last_name %} ``` #### capture Multi-line content capture: ```liquid {% capture product_title %} {{ collection.title }} - {{ product.title }} {% endcapture %} {{ product_title }} {# "Summer Sale - Blue T-Shirt" #} {% capture greeting %}

Welcome, {{ customer.name }}!

You have {{ customer.orders_count }} orders.

{% endcapture %} {{ greeting }} ``` #### liquid (multi-statement) Cleaner syntax for multiple statements: ```liquid {% liquid assign product_type = product.type assign is_on_sale = product.on_sale assign sale_percentage = product.discount_percent if is_on_sale assign status = 'SALE' else assign status = 'REGULAR' endif echo status %} ``` ### Template Inclusion #### render Isolated scope (preferred method): ```liquid {# Basic usage #} {% render 'product-card', product: product %} {# Multiple parameters #} {% render 'product-card', product: product, show_price: true, show_vendor: false, css_class: 'featured' %} {# Render for each item #} {% render 'product-card' for collection.products as item %} {# Pass arrays #} {% render 'gallery', images: product.images %} ``` **Inside product-card.liquid:** ```liquid {# Only has access to passed parameters #}

{{ product.title }}

{% if show_price %}

{{ product.price | money }}

{% endif %} {% if show_vendor %}

{{ product.vendor }}

{% endif %}
``` #### include Shared scope (legacy, avoid in new code): ```liquid {% include 'product-details' %} {# Can access all parent template variables #} {# Harder to debug and reason about #} ``` #### section Load dynamic sections: ```liquid {% section 'featured-product' %} {% section 'newsletter-signup' %} ``` ### Utility Tags #### comment Multi-line comments: ```liquid {% comment %} This entire block is ignored by the Liquid renderer. Use for documentation. {% endcomment %} {# Single-line comment #} ``` #### echo Output shorthand (alternative to `{{ }}`): ```liquid {% echo product.title %} {# Equivalent to: {{ product.title }} #} ``` #### raw Output Liquid code without processing: ```liquid {% raw %} {{ This will be output as-is }} {% Liquid tags won't be processed %} {% endraw %} ``` Useful for documentation or code examples. ## Whitespace Control Strip whitespace using hyphens: ```liquid {%- if condition -%} Content (whitespace stripped on both sides) {%- endif -%} {{ "hello" -}}world {# Output: helloworld (no space) #} {{- product.title }} {# Strips whitespace before output #} {{ product.title -}} {# Strips whitespace after output #} ``` **Example:** ```liquid {# Without whitespace control: #} {% for item in array %} {{ item }} {% endfor %} {# Output has newlines and indentation #} {# With whitespace control: #} {%- for item in array -%} {{ item }} {%- endfor -%} {# Output is compact #} ``` ## Operator Precedence **Order of evaluation (right-to-left):** ```liquid {% if true or false and false %} {# Evaluates as: true or (false and false) = true #} {% endif %} ``` **IMPORTANT:** No parentheses support in Liquid. Break complex conditions into variables: ```liquid {# ❌ DOESN'T WORK: #} {% if (x > 5 and y < 10) or z == 0 %} {# ✅ WORKS: #} {% assign condition1 = false %} {% if x > 5 and y < 10 %} {% assign condition1 = true %} {% endif %} {% if condition1 or z == 0 %} {# Logic here #} {% endif %} ``` ## Performance Tips 1. **Cache repeated calculations:** ```liquid {# ❌ Inefficient: #} {% for i in (1..10) %} {{ collection.products.size }} {# Calculated 10 times #} {% endfor %} {# ✅ Efficient: #} {% assign product_count = collection.products.size %} {% for i in (1..10) %} {{ product_count }} {% endfor %} ``` 2. **Use `limit` and `offset` instead of iterating full arrays:** ```liquid {# ❌ Inefficient: #} {% for product in collection.products %} {% if forloop.index <= 5 %} {{ product.title }} {% endif %} {% endfor %} {# ✅ Efficient: #} {% for product in collection.products limit: 5 %} {{ product.title }} {% endfor %} ``` 3. **Prefer `render` over `include`** for better performance and variable scoping 4. **Use `liquid` tag** for cleaner multi-statement blocks ## Common Gotchas 1. **No parentheses in conditions** - Use variables instead 2. **Right-to-left evaluation** - Be careful with operator precedence 3. **String concatenation** - Use `append` filter or `capture` tag 4. **Array/object mutation** - Not possible; create new variables 5. **Integer division** - `{{ 5 | divided_by: 2 }}` returns `2`, not `2.5` 6. **Truthy/falsy values:** - `false` and `nil` are falsy - Everything else (including `0`, `""`, `[]`) is truthy ## Debugging Tips 1. **Output variable types:** ```liquid {{ product | json }} {# Output entire object as JSON #} {{ product.class }} {# Output object type #} {{ variable.size }} {# Check array/string length #} ``` 2. **Check for nil/existence:** ```liquid {% if product.metafield %} Metafield exists {% else %} Metafield is nil {% endif %} ``` 3. **Use default filter for safety:** ```liquid {{ product.metafield.value | default: "Not set" }} ``` 4. **Enable theme preview console** to see Liquid errors in real-time