Skip to content

Liquid tags

Tags hold the logic of a template: {% tag %}. They print nothing themselves unless stated. {%- and -%} remove the whitespace before or after the tag, as in standard Liquid.

{% menu id="main-menu" %}
{% menu id='footer-menu' %}

Prints a navigation menu managed in Content → Navigation (/admin/navigation). The id is the menu’s handle: main-menu and footer-menu are the two menus every marketplace has.

The menu is drawn by the snippet menu-<id>.liquid when your theme has one (for example menu-footer-menu.liquid), otherwise by menu-default.liquid. The snippet receives only a menu object:

Field Description
menu.id The handle, footer-menu
menu.title The menu’s name
menu.description Its description
menu.position Its position
menu.links The items, in the order set in the back office
link.id The item’s id
link.title Its label
link.link Its URL
link.target _blank to open in a new tab, otherwise empty
link.position Its position
snippets/menu-footer-menu.liquid
{% if menu.links.size > 0 %}
<ul class="footer-links">
{% for link in menu.links %}
<li id="menu-item-{{ link.id }}">
<a href="{{ link.link }}"{% if link.target == '_blank' %} target="_blank" rel="noopener"{% endif %}>
{{ link.title | escape }}
</a>
</li>
{% endfor %}
</ul>
{% endif %}

A menu id that matches no menu prints nothing. Because the menu snippet receives only menu, the global objects (settings, routes, authenticated_user) are not available inside it; filters such as t are.

{% widget type="listings" %}
{% widget type="listings" id="4242" %}
{% widget type="listings" id="4242,4243,4250" %}

Prints a grid of listing cards, in the markup the platform uses for its own listing grids. It needs the Landing Pages app: without it, the tag prints a sentence saying so.

Attribute Description
type listings (or listing). Required.
id Optional. One listing id, or several separated by commas, printed in that order. Without it, the 21 most recent listings online.

Only listings online are shown. Attribute values must be written in double quotes.

{% assign first_media = listing.medias | first %}
{% assign count = listings | size %}
{% capture page_heading %}{{ 'general.breadcrumbs.listings' | t }} ({{ count }}){% endcapture %}
<h1>{{ page_heading }}</h1>

assign stores a value, filters included. capture stores everything rendered between its tags as a string.

{% if listings.size > 0 and settings.wishlist.active %}
…
{% elsif authenticated_user %}
…
{% else %}
…
{% endif %}
{% unless listing.price == 0 %}{{ listing.price | money }}{% endunless %}
{% case order.status %}
{% when 'new' %}New
{% when 'accepted' %}Accepted
{% else %}{{ order.status }}
{% endcase %}

Operators: ==, !=, >, <, >=, <=, contains (a substring of a string, or an item of an array), and, or. and and or are evaluated from left to right, with no precedence and no parentheses.

{% if listings.size > 0 %}
<ul>
{% for listing in listings limit: 4 offset: 1 %}
<li>{{ forloop.index }}. {{ listing.title | escape }}</li>
{% endfor %}
</ul>
{% else %}
<p>Nothing here yet.</p>
{% endif %}
{% for i in (1..5) %}{{ i }}{% endfor %}

forloop offers index, index0, rindex, rindex0, first, last and length. {% break %} and {% continue %} leave or skip an iteration. Ranges (1..n) accept a variable. reversed is not supported: assign | reverse first. for takes no else branch: test the collection’s size before the loop, as above.

Looping over a hash gives pairs: {% for pair in hash %}{{ pair[0] }}: {{ pair[1] }}{% endfor %}.

{% cycle 'odd', 'even' %} alternates values across iterations, {% ifchanged %}…{% endifchanged %} prints its content only when it differs from the previous iteration, and {% tablerow item in items cols: 3 %}…{% endtablerow %} builds table rows and cells.

{% include 'listing-thumbnail' %}
{% include 'listing-thumbnail', listing: product %}

include renders a snippet of your theme by name, without the .liquid extension. The snippet sees every variable of the including template, plus the ones you pass as name: value. A snippet that does not exist renders nothing; it does not break the page.

{% include 'name' with value %} and {% include 'name' for collection %} also work, but they expose the value under the snippet’s own name, which is unusable when the name contains a hyphen. Prefer name: value.

To include a template file rather than a snippet, prefix it with its folder: {% include 'templates/listings/search' %}.

{% raw %}{{ this is printed as is }}{% endraw %}
{% comment %}Not rendered.{% endcomment %}

Use raw around a JavaScript template that uses {{ }} itself. {# #} is not a comment in this Liquid: it is printed as text.

  • Dot notation reads fields: listing.category.title.
  • Square brackets read an index or a key held in a variable: listings[0].title, {% assign key = 'color' %}{{ listing.attributes[key] }}.
  • .size, .first and .last work at the end of a path: {{ listing.medias.size }}. To read a field of the first item, assign it first: {% assign first_media = listing.medias | first %}{{ first_media.src }}.
  • A missing field prints nothing and raises no error.