shopify-liquid-themes by benjaminsehl/liquid-skills
npx skills add https://github.com/benjaminsehl/liquid-skills --skill shopify-liquid-themes.
├── sections/ # 带有 {% schema %} 的全宽页面模块 — 横幅、产品网格、推荐语
├── blocks/ # 带有 {% schema %} 的可嵌套组件 — 幻灯片、功能项、文本块
├── snippets/ # 通过 {% render %} 使用的可复用片段 — 按钮、图标、图片助手
├── layout/ # 页面包装器(必须包含 {{ content_for_header }} 和 {{ content_for_layout }})
├── templates/ # 定义每种页面类型显示哪些部分的 JSON 文件
├── config/ # 全局主题设置(settings_schema.json, settings_data.json)
├── locales/ # 翻译文件(en.default.json, fr.json 等)
└── assets/ # 静态 CSS、JS、图片(优先使用 {% stylesheet %}/{% javascript %})
| 需求 | 使用 | 原因 |
|---|---|---|
| 全宽可定制模块 | Section | 具有 {% schema %},出现在编辑器中,渲染块 |
| 带有编辑器设置的小型可嵌套组件 | Block | 具有 ,可以嵌套在 sections/blocks 内 |
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
{% schema %}| 可复用逻辑,商家不可编辑 | Snippet | 无 schema,通过 {% render %} 渲染,接收参数 |
| 跨块/片段共享的逻辑 | Snippet | 块不能 {% render %} 其他块 |
{{ ... }} — 输出(打印值){{- ... -}} — 带空格修剪的输出{% ... %} — 逻辑标签(if, for, assign)— 不打印任何内容{%- ... -%} — 带空格修剪的逻辑标签比较: ==, !=, >, <, >=, <= 逻辑: and, or, contains
{% if %}{% if cond %}值{% else %}其他{% endif %}for 循环最多 50 次迭代 — 对于更大的数组使用 {% paginate %}contains 仅适用于字符串 — 无法检查数组中的对象{% stylesheet %}/{% javascript %} 不渲染 Liquid — 它们内部不能使用 Liquidinclude 已弃用 — 始终使用 {% render 'snippet_name' %}{% liquid %} 标签 — 无需分隔符的多行逻辑;使用 echo 进行输出{% assign my_var = 'value' %}
{% capture my_var %}computed {{ value }}{% endcapture %}
{% increment counter %}
{% decrement counter %}
过滤器使用 | 链接。一个过滤器的输出类型作为下一个过滤器的输入。
数组: compact, concat, find, find_index, first, has, join, last, map, reject, reverse, size, sort, sort_natural, sum, uniq, where 字符串: append, capitalize, downcase, escape, handleize, lstrip, newline_to_br, prepend, remove, replace, rstrip, slice, split, strip, strip_html, truncate, truncatewords, upcase, url_decode, url_encode 数学: abs, at_least, at_most, ceil, divided_by, floor, minus, modulo, plus, round, times 货币: money, money_with_currency, money_without_currency, money_without_trailing_zeros 颜色: color_brightness, color_darken, color_lighten, color_mix, color_modify, color_saturate, color_desaturate, color_to_hex, color_to_hsl, color_to_rgb 媒体: image_url, image_tag, video_tag, external_video_tag, media_tag, model_viewer_tag URL: asset_url, asset_img_url, file_url, shopify_asset_url HTML: link_to, script_tag, stylesheet_tag, time_tag, placeholder_svg_tag 本地化: t (translate), format_address, currency_selector 其他: date, default, json, structured_data, font_face, font_url, payment_button
完整详情:语言过滤器,HTML/媒体过滤器,商业过滤器
| 类别 | 标签 |
|---|---|
| 主题 | content_for, layout, section, sections, schema, stylesheet, javascript, style |
| 控制 | if, elsif, else, unless, case, when |
| 迭代 | for, break, continue, cycle, tablerow, paginate |
| 变量 | assign, capture, increment, decrement, echo |
| HTML | form, render, raw, comment, liquid |
| 文档 | doc |
包含语法和参数的完整详情:references/tags.md
cart, collections, customer, localization, pages, request, routes, settings, shop, template, theme, linklists, images, blogs, articles, all_products, metaobjects, canonical_url, content_for_header, content_for_layout, page_title, page_description, handle, current_page
| 模板 | 对象 |
|---|---|
/product | product, remote_product |
/collection | collection, current_tags |
/cart | cart |
/article | article, blog |
/blog | blog, current_tags |
/page | page |
/search | search |
/customers/* | customer, order |
Sections 和 blocks 需要带有有效 JSON 对象的 {% schema %}。Sections 使用 section.settings.*,blocks 使用 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" }]
}
| 需求 | 设置类型 | 关键字段 |
|---|---|---|
| 开/关切换 | checkbox | default: true/false |
| 短文本 | text | placeholder |
| 长文本 | textarea | placeholder |
富文本(带 <p>) | richtext | — |
内联富文本(无 <p>) | inline_richtext | — |
| 数字输入 | number | placeholder |
| 滑块 | range | min, max, default (全部必需), step, unit |
| 下拉菜单/分段控件 | select | options: [{value, label}] |
| 单选按钮 | radio | options: [{value, label}] |
| 文本对齐 | text_alignment | default: "left"/"center"/"right" |
| 颜色选择器 | color | default: "#000000" |
| 图片上传 | image_picker | — |
| 视频上传 | video | — |
| 外部视频 URL | video_url | accept: ["youtube", "vimeo"] |
| 产品选择器 | product | — |
| 集合选择器 | collection | — |
| 页面选择器 | page | — |
| 博客选择器 | blog | — |
| 文章选择器 | article | — |
| URL 输入 | url | — |
| 菜单选择器 | link_list | — |
| 字体选择器 | font_picker | default (必需) |
| 编辑器标题 | header | content (无需 id) |
| 编辑器描述 | paragraph | content (无需 id) |
visible_if 模式{
"visible_if": "{{ block.settings.layout == 'vertical' }}",
"type": "select",
"id": "alignment",
"label": "t:labels.alignment",
"options": [...]
}
根据其他设置值,有条件地在编辑器中显示/隐藏设置。
{ "type": "@theme" } — 接受任何主题块{ "type": "@app" } — 接受应用块{ "type": "slide" } — 仅接受 slide 块类型完整 schema 详情和全部 33 种设置类型:references/schema-and-settings.md
在 sections、blocks 和 snippets 中使用 {% stylesheet %} 和 {% javascript %}:
{% stylesheet %}
.my-component { display: flex; }
{% endstylesheet %}
{% javascript %}
console.log('loaded');
{% endjavascript %}
{% stylesheet %} 标签会导致错误sections/、blocks/ 和 snippets/ 中受支持{% style %} 标签(支持 Liquid 的 CSS)用于需要 Liquid 的动态 CSS(例如,在编辑器中实时更新的颜色设置):
{% style %}
.section-{{ section.id }} {
background: {{ section.settings.bg_color }};
}
{% endstyle %}
单个 CSS 属性 — 使用 CSS 变量:
<div style="--gap: {{ block.settings.gap }}px">
多个 CSS 属性 — 使用 CSS 类作为选择值:
<div class="{{ block.settings.layout }}">
{% doc %})必需用于: snippets(始终),blocks(当通过 {% content_for 'block' %} 静态渲染时)
{% doc %}
此文件渲染内容的简要描述。
@param {type} name - 必需参数的描述
@param {type} [name] - 可选参数的描述(方括号 = 可选)
@example
{% render 'snippet-name', name: value %}
{% enddoc %}
参数类型: string, number, boolean, image, object, array
t 过滤器<!-- 正确 -->
<h2>{{ 'sections.hero.heading' | t }}</h2>
<button>{{ 'products.add_to_cart' | t }}</button>
<!-- 错误 — 切勿硬编码字符串 -->
<h2>Welcome to our store</h2>
{{ 'products.price_range' | t: min: product.price_min | money, max: product.price_max | money }}
本地化文件:
{
"products": {
"price_range": "从 {{ min }} 到 {{ max }}"
}
}
locales/
├── en.default.json # 英文翻译(必需)
├── en.default.schema.json # 编辑器设置翻译(必需)
├── fr.json # 法文翻译
└── fr.schema.json # 法文编辑器翻译
t: 前缀:"label": "t:labels.heading"sections.hero.heading, blocks.slide.title每周安装数
527
仓库
GitHub 星标数
91
首次出现
2026年2月23日
安全审计
安装于
claude-code403
codex387
opencode385
github-copilot384
kimi-cli383
gemini-cli383
.
├── 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 {% schema %}, appears in editor, renders blocks |
| Small nestable component with editor settings | Block | Has {% schema %}, can nest inside sections/blocks |
| Reusable logic, not editable by merchant | Snippet | No schema, rendered via {% render %}, takes params |
| Logic shared across blocks/snippets | Snippet | Blocks can't {% render %} other blocks |
{{ ... }} — Output (prints a value){{- ... -}} — Output with whitespace trimming{% ... %} — Logic tag (if, for, assign) — prints nothing{%- ... -%} — Logic tag with whitespace trimmingComparison: ==, !=, >, <, >=, <= Logical: and, or, contains
{% if %} instead{% if cond %}value{% else %}other{% endif %}for loops max 50 iterations — use {% paginate %} for larger arrayscontains only works with strings — can't check objects in arrays{% stylesheet %}/{% javascript %} don't render Liquid — no Liquid inside theminclude is deprecated — always use {% assign my_var = 'value' %}
{% capture my_var %}computed {{ value }}{% endcapture %}
{% increment counter %}
{% decrement counter %}
Filters are chained with |. Output type of one filter feeds input of next.
Array: compact, concat, find, find_index, first, has, join, last, map, reject, reverse, size, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , (translate), , , , , , , ,
Full details: language filters, HTML/media filters, commerce filters
| Category | Tags |
|---|---|
| Theme | content_for, layout, section, sections, schema, stylesheet, javascript, style |
| Control | if, , , , , |
Full details with syntax and parameters: references/tags.md
cart, collections, customer, localization, pages, request, routes, settings, shop, template, theme, linklists, , , , , , , , , , , ,
| Template | Objects |
|---|---|
/product | product, remote_product |
/collection | collection, current_tags |
/cart | cart |
/article |
Full reference: commerce objects, content objects, tier 2, tier 3
Sections and blocks require {% schema %} with a valid JSON object. Sections use section.settings.*, blocks use 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 | checkbox | default: true/false |
| Short text | text | placeholder |
| Long text | textarea | placeholder |
Rich text (with <p>) |
visible_if pattern{
"visible_if": "{{ block.settings.layout == 'vertical' }}",
"type": "select",
"id": "alignment",
"label": "t:labels.alignment",
"options": [...]
}
Conditionally shows/hides a setting in the editor based on other setting values.
{ "type": "@theme" } — Accept any theme block{ "type": "@app" } — Accept app blocks{ "type": "slide" } — Accept only the slide block typeFull schema details and all 33 setting types: references/schema-and-settings.md
Use {% stylesheet %} and {% javascript %} in sections, blocks, and snippets:
{% stylesheet %}
.my-component { display: flex; }
{% endstylesheet %}
{% javascript %}
console.log('loaded');
{% endjavascript %}
{% stylesheet %} tags will errorsections/, blocks/, and snippets/{% style %} tag (Liquid-aware CSS)For dynamic CSS that needs Liquid (e.g., color settings that live-update in editor):
{% style %}
.section-{{ section.id }} {
background: {{ section.settings.bg_color }};
}
{% endstyle %}
Single CSS property — use CSS variables:
<div style="--gap: {{ block.settings.gap }}px">
Multiple CSS properties — use CSS classes as select values:
<div class="{{ block.settings.layout }}">
{% doc %})Required for: snippets (always), blocks (when statically rendered via {% 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 %}
Param types: string, number, boolean, image, object, array
t filter<!-- 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 }}
Locale file:
{
"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 translations
t: prefix: "label": "t:labels.heading"sections.hero.heading, blocks.slide.titleWeekly Installs
527
Repository
GitHub Stars
91
First Seen
Feb 23, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
claude-code403
codex387
opencode385
github-copilot384
kimi-cli383
gemini-cli383
React 组合模式指南:Vercel 组件架构最佳实践,提升代码可维护性
102,200 周安装
{% render 'snippet_name' %}{% liquid %} tag — multi-line logic without delimiters; use echo for outputsortsort_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_buttonelsifelseunlesscasewhen| Iteration | for, break, continue, cycle, tablerow, paginate |
| Variable | assign, capture, increment, decrement, echo |
| HTML | form, render, raw, comment, liquid |
| Documentation | doc |
imagesblogsarticlesall_productsmetaobjectscanonical_urlcontent_for_headercontent_for_layoutpage_titlepage_descriptionhandlecurrent_pagearticle, blog |
/blog | blog, current_tags |
/page | page |
/search | search |
/customers/* | customer, order |
richtext |
| — |
Inline rich text (no <p>) | inline_richtext | — |
| Number input | number | placeholder |
| Slider | range | min, max, default (all required), step, unit |
| Dropdown/segmented | select | options: [{value, label}] |
| Radio buttons | radio | options: [{value, label}] |
| Text alignment | text_alignment | default: "left"/"center"/"right" |
| Color picker | color | default: "#000000" |
| Image upload | image_picker | — |
| Video upload | video | — |
| External video URL | video_url | accept: ["youtube", "vimeo"] |
| Product picker | product | — |
| Collection picker | collection | — |
| Page picker | page | — |
| Blog picker | blog | — |
| Article picker | article | — |
| URL entry | url | — |
| Menu picker | link_list | — |
| Font picker | font_picker | default (required) |
| Editor header | header | content (no id needed) |
| Editor description | paragraph | content (no id needed) |