Loading...
Loading...
Generate Shopify Liquid theme code (sections, blocks, snippets) with correct schema JSON, LiquidDoc headers, translation keys, and CSS/JS patterns. Use when creating or editing .liquid files for Shopify themes, working with schema, doc, stylesheet, javascript tags, or Shopify Liquid objects/filters/tags.
npx skill4agent add benjaminsehl/liquid-skills shopify-liquid-themes.
├── sections/ # Full-width page modules with {% schema %} — hero, product grid, testimonials
├── blocks/ # Nestable components with {% schema %} — slides, feature items, text blocks
├── snippets/ # Reusable fragments via {% render %} — buttons, icons, image helpers
├── layout/ # Page wrappers (must include {{ content_for_header }} and {{ content_for_layout }})
├── templates/ # JSON files defining which sections appear on each page type
├── config/ # Global theme settings (settings_schema.json, settings_data.json)
├── locales/ # Translation files (en.default.json, fr.json, etc.)
└── assets/ # Static CSS, JS, images (prefer {% stylesheet %}/{% javascript %} instead)| Need | Use | Why |
|---|---|---|
| Full-width customizable module | Section | Has |
| Small nestable component with editor settings | Block | Has |
| Reusable logic, not editable by merchant | Snippet | No schema, rendered via |
| Logic shared across blocks/snippets | Snippet | Blocks can't |
{{ ... }}{{- ... -}}{% ... %}{%- ... -%}==!=><>=<=andorcontains{% if %}{% if cond %}value{% else %}other{% endif %}for{% paginate %}contains{% stylesheet %}{% javascript %}include{% render 'snippet_name' %}{% liquid %}echo{% assign my_var = 'value' %}
{% capture my_var %}computed {{ value }}{% endcapture %}
{% increment counter %}
{% decrement counter %}|compactconcatfindfind_indexfirsthasjoinlastmaprejectreversesizesortsort_naturalsumuniqwhereappendcapitalizedowncaseescapehandleizelstripnewline_to_brprependremovereplacerstripslicesplitstripstrip_htmltruncatetruncatewordsupcaseurl_decodeurl_encodeabsat_leastat_mostceildivided_byfloorminusmoduloplusroundtimesmoneymoney_with_currencymoney_without_currencymoney_without_trailing_zeroscolor_brightnesscolor_darkencolor_lightencolor_mixcolor_modifycolor_saturatecolor_desaturatecolor_to_hexcolor_to_hslcolor_to_rgbimage_urlimage_tagvideo_tagexternal_video_tagmedia_tagmodel_viewer_tagasset_urlasset_img_urlfile_urlshopify_asset_urllink_toscript_tagstylesheet_tagtime_tagplaceholder_svg_tagtformat_addresscurrency_selectordatedefaultjsonstructured_datafont_facefont_urlpayment_buttonFull details: language filters, HTML/media filters, commerce filters
| Category | Tags |
|---|---|
| Theme | |
| Control | |
| Iteration | |
| Variable | |
| HTML | |
| Documentation | |
Full details with syntax and parameters: references/tags.md
cartcollectionscustomerlocalizationpagesrequestroutessettingsshoptemplatethemelinklistsimagesblogsarticlesall_productsmetaobjectscanonical_urlcontent_for_headercontent_for_layoutpage_titlepage_descriptionhandlecurrent_page| Template | Objects |
|---|---|
| |
| |
| |
| |
| |
| |
| |
| |
Full reference: commerce objects, content objects, tier 2, tier 3
{% schema %}section.settings.*block.settings.*{
"name": "t:sections.hero.name",
"tag": "section",
"class": "hero-section",
"limit": 1,
"settings": [],
"max_blocks": 16,
"blocks": [{ "type": "@theme" }],
"presets": [{ "name": "t:sections.hero.name" }],
"enabled_on": { "templates": ["index"] },
"disabled_on": { "templates": ["password"] }
}{
"name": "t:blocks.slide.name",
"tag": "div",
"class": "slide",
"settings": [],
"blocks": [{ "type": "@theme" }],
"presets": [{ "name": "t:blocks.slide.name" }]
}| Need | Setting Type | Key Fields |
|---|---|---|
| On/off toggle | | |
| Short text | | |
| Long text | | |
Rich text (with | | — |
Inline rich text (no | | — |
| Number input | | |
| Slider | | |
| Dropdown/segmented | | |
| Radio buttons | | |
| Text alignment | | |
| Color picker | | |
| Image upload | | — |
| Video upload | | — |
| External video URL | | |
| Product picker | | — |
| Collection picker | | — |
| Page picker | | — |
| Blog picker | | — |
| Article picker | | — |
| URL entry | | — |
| Menu picker | | — |
| Font picker | | |
| Editor header | | |
| Editor description | | |
visible_if{
"visible_if": "{{ block.settings.layout == 'vertical' }}",
"type": "select",
"id": "alignment",
"label": "t:labels.alignment",
"options": [...]
}{ "type": "@theme" }{ "type": "@app" }{ "type": "slide" }slideFull schema details and all 33 setting types: references/schema-and-settings.md
{% stylesheet %}{% javascript %}{% stylesheet %}
.my-component { display: flex; }
{% endstylesheet %}
{% javascript %}
console.log('loaded');
{% endjavascript %}{% stylesheet %}sections/blocks/snippets/{% style %}{% style %}
.section-{{ section.id }} {
background: {{ section.settings.bg_color }};
}
{% endstyle %}<div style="--gap: {{ block.settings.gap }}px"><div class="{{ block.settings.layout }}">{% doc %}{% content_for 'block' %}{% doc %}
Brief description of what this file renders.
@param {type} name - Description of required parameter
@param {type} [name] - Description of optional parameter (brackets = optional)
@example
{% render 'snippet-name', name: value %}
{% enddoc %}stringnumberbooleanimageobjectarrayt<!-- Correct -->
<h2>{{ 'sections.hero.heading' | t }}</h2>
<button>{{ 'products.add_to_cart' | t }}</button>
<!-- Wrong — never hardcode strings -->
<h2>Welcome to our store</h2>{{ 'products.price_range' | t: min: product.price_min | money, max: product.price_max | money }}{
"products": {
"price_range": "From {{ min }} to {{ max }}"
}
}locales/
├── en.default.json # English translations (required)
├── en.default.schema.json # Editor setting translations (required)
├── fr.json # French translations
└── fr.schema.json # French editor translationst:"label": "t:labels.heading"sections.hero.headingblocks.slide.title