Liquid & Schema
Liquid has no ternary operator
Section titled “Liquid has no ternary operator”{% comment %} Wrong — silently outputs nothing {% endcomment %}<div class="{{ condition ? 'a' : 'b' }}">
{% comment %} Correct {% endcomment %}<div class="{% if condition %}a{% else %}b{% endif %}">Filters can’t span lines inside {% liquid %}
Section titled “Filters can’t span lines inside {% liquid %}”{% comment %} Broken — syntax error {% endcomment %}{% liquid assign data = '{' | append: '"key":'%}
{% comment %} Fine — individual assign tag {% endcomment %}{% assign data = '{' | append: '"key":'%}
{% comment %} Also fine — single line inside a liquid block {% endcomment %}{% liquid assign data = '{' | append: '"key":'%}Filters are dropped on render arguments
Section titled “Filters are dropped on render arguments”This is a real source of silent bugs:
{% comment %} The filter is IGNORED — visited is passed unchanged {% endcomment %}{% render 'tree', visited: visited | append: id %}
{% comment %} Correct — build the value first {% endcomment %}{% assign next_visited = visited | append: id %}{% render 'tree', visited: next_visited %}render also creates an isolated scope — a snippet can’t hand variables back.
When you need a value out of one, echo a delimited string and capture it:
{%- capture result -%}{%- render 'tag-style-map', tag: tag -%}{%- endcapture -%}{%- assign parts = result | split: '|' -%}Schema patterns
Section titled “Schema patterns”Conditional settings
Section titled “Conditional settings”Hide settings that don’t apply, rather than letting merchants set values that do nothing:
{ "type": "color", "id": "badge_color", "label": "t:blocks.my-block.settings.badge_color.label", "visible_if": "{{ block.settings.badge_label != blank }}"}Use section.settings.* in sections, block.settings.* in blocks. The double
braces are required.
Richtext defaults must be wrapped
Section titled “Richtext defaults must be wrapped”"default": "<p>Text in paragraph tags</p>"Bare text fails validation. Allowed top-level tags: <p>, <h1>–<h6>,
<ul>, <ol>.
Blocks need a preset
Section titled “Blocks need a preset”A block won’t appear in the customizer’s picker without one, even a bare one:
"presets": [{ "name": "My Block" }]Translations
Section titled “Translations”Every schema label, info string and select option needs a key in
locales/en.default.schema.json.
Validation
Section titled “Validation”Run both before committing:
npx shopify theme checkThe Shopify MCP validate_theme tool catches schema issues that theme check
misses. The target is zero errors — warnings are triaged separately.