Skip to Content
🎉 探索 Shopify 的无限可能 结构化知识 + 实战案例,持续更新中...
Liquid 开发主题设置

主题设置配置:先决定什么该做成全局设置

主题设置最常见的问题不是不会写 schema,而是什么都往全局塞。设置项一多,商家在”主题设置”里翻半天找不到要改的东西,而你每加一个开关都要在模板里多一处 {% if %}——分支越多,越没人敢改主题。

判断标准只有一条:一个值如果在整站只有一份,它属于全局设置;如果每个模块各有一份,它属于 section 或 block 设置。 品牌色、字体、logo 是全局的;某个 Hero 的标题不是。


一、两个文件的关系

文件内容谁改
config/settings_schema.json设置的定义:分几类、每类有哪些项你(开发者)
config/settings_data.json设置的取值:商家在编辑器里选了什么商家(通过编辑器)

settings_schema.json 是一个数组,每个元素是一个设置分类对象,必须有 namesettings 两个字段:

[ { "name": "theme_info", "theme_name": "示例主题", "theme_author": "你的团队", "theme_version": "1.0.0", "theme_documentation_url": "https://example.com/docs", "theme_support_email": "support@example.com" }, { "name": "品牌", "settings": [ { "type": "image_picker", "id": "logo", "label": "Logo" }, { "type": "range", "id": "logo_width", "label": "Logo 宽度", "min": 60, "max": 240, "step": 10, "unit": "px", "default": 120 }, { "type": "color_scheme_group", "id": "color_schemes", "definition": [ { "type": "color", "id": "background", "label": "背景", "default": "#ffffff" }, { "type": "color", "id": "text", "label": "文字", "default": "#121212" } ], "role": { "background": "background", "text": "text" } } ] } ]

第一个元素是特殊的:theme_info 用来在编辑器的主题操作菜单里展示主题元信息。它的 theme_nametheme_authortheme_versiontheme_documentation_url 都是必填,另外 theme_support_emailtheme_support_url 至少要提供一个。做主题分发(尤其要上 Theme Store)时这块必须齐全。


二、常用设置类型与它们的返回值

写 schema 之前先搞清楚取出来是什么,这比记住类型名更重要——很多 bug 来自把对象当字符串用。

类型取值时得到什么空值时
checkbox布尔未设 default 时为 false
text / textarea字符串空字符串
richtext含 HTML 的字符串
inline_richtext字符串空对象
number / range数字number 可能为 nil
select / radio所选 value 字符串
color颜色对象blank
image_pickerimage 对象blank
link_listlinklist 对象blank(含选中的菜单已删除的情况)
product / collection / blog / page对应资源对象blank
liquid可含 HTML 与有限 Liquid 的字符串

两个要点:

资源型设置返回的是对象,不是 handle。 所以直接 settings.featured_product.title 就能用,不需要 all_products[settings.featured_product] 那种老写法。

inline_richtext 空值是空对象而不是空字符串,所以判断要用 != blank 而不是 != ''——后者在空对象上不成立,会渲染出空标签。

number 类型还有个 placeholder 属性,但只在 settings_schema.json 里生效,section schema 里写了不会显示。


三、在模板里取值

全局设置统一通过 settings 对象访问:

{% if settings.logo != blank %} <a class="header__logo" href="{{ routes.root_url }}"> {{ settings.logo | image_url: width: 480 | image_tag: widths: '120, 240, 360, 480', sizes: '120px', loading: 'eager', alt: shop.name }} </a> {% else %} <a class="header__logo header__logo--text" href="{{ routes.root_url }}"> {{ shop.name }} </a> {% endif %}

三个习惯值得固化:

每个可空设置都要有兜底分支。 上面 logo 没设时退回店名文字,而不是渲染一个空 <a>。商家新装主题时所有设置都是默认值,这条路径必须能看。

链接用 routes 而不是硬编码路径。 routes.root_url 在多语言与子路径场景下才正确。

数值型设置用 CSS 变量传给样式,不要在 {% stylesheet %} 里写 Liquid(那里的 Liquid 不会被渲染):

<div class="promo" style="--promo-radius: {{ settings.corner_radius }}px"> {{ settings.promo_text }} </div> {% stylesheet %} .promo { border-radius: var(--promo-radius, 0); } {% endstylesheet %}

需要在编辑器里实时预览颜色变化时可以用 {% style %} 标签,它会随设置变更即时更新。


四、全局设置放什么、不放什么

该放全局不该放全局
品牌色 / 配色方案某个模块的标题文案
字体某个 Hero 的图片
Logo 与 favicon某个促销条的到期日
圆角、间距等设计语言基线只影响一个页面的开关
社交账号链接某个集合页的排序方式
商品卡片的统一样式选项单个商品的自定义信息(用元字段)

最后一行值得单独说:商品维度的自定义信息属于元字段(metafield),不属于主题设置。主题设置是全站一份,商品有几千个。把”这个商品的保养说明”做成主题设置是结构性错误。见 元字段与元对象

配色建议用 color_scheme_group 定义方案,再让 section 通过 color_scheme 设置选用某个方案——而不是给每个 section 都放一组 color 设置。后者会让商家改一次品牌色要点开二十个模块。


五、三个真实坑位

id 等于让已保存的配置失联。 settings_data.jsonid 作键。你把 color_primary 改成 brand_color,商家原来选的颜色就找不到了,页面静默回落到 default。要改就保留旧 id,或在发版说明里写清需要重设。

selectvalue 也是存储值。value 和改 id 一样会失联,改 label 才是安全的。

默认值必须是可用的成品。 商家装上主题、什么都没配的那一刻,页面应该就是能看的。所有 default 合起来要构成一套完整可用的配置,而不是一堆占位符。


六、不要做的四件事

这几条在旧教程里很常见,但在 Shopify 主题里是错的:

用 JavaScript 在运行时”校验”主题设置。 设置是构建期由 Liquid 输出到 HTML 的,等页面跑起来再用 JS 检查颜色格式合不合法、必填项有没有填,既救不了任何东西,还要求你额外把设置塞到 window 上。该做的是在 schema 里用对类型、给对 default,并在 Liquid 里做 != blank 兜底。

做”设置迁移脚本”或”设置版本管理”。 主题体系里没有这套机制。设置的兼容性靠保持 id 稳定来实现,而不是靠运行时迁移代码。

用设置开关去动态加载第三方 CDN 脚本。 比如加一个”启用图片懒加载”的 checkbox,然后从 CDN 拉一个懒加载库——原生 loading="lazy" 早已通用,这个开关唯一的作用是让站点多一个外部依赖和一次额外的建连。

把每个视觉细节都做成设置。 每个设置都是一次商家的决策成本加一处你的分支。能用设计语言统一的(圆角、间距、字号阶梯)就定成基线,不要逐个模块开放。


七、上线自检

  • settings_schema.json 是合法 JSON,且第一项是完整的 theme_info
  • 每个可空设置在模板里都有兜底分支;
  • 空值判断用 != blank(尤其 inline_richtext);
  • 资源型设置按对象用,没有多余的 handle 查表;
  • 数值走 CSS 变量,{% stylesheet %} 里没有 Liquid;
  • 全站一份的值才在全局,模块级的值在 section / block,商品级的用元字段;
  • 配色通过 color_scheme_group 定义、由 section 选用;
  • 所有 label 与用户可见文案可翻译,必要时用 t: 键;
  • 全部 default 合起来是一套开箱可用的配置;
  • 这次改动没有变更任何已发布过的 idselectvalue

八、延伸阅读


九、官方文档


小结:先用”整站是否只有一份”这条标准划分全局设置与模块设置,商品级数据交给元字段。写 schema 前先确认取值类型——资源型设置返回对象而非 handle,inline_richtext 的空值是空对象所以必须用 != blanksettings_data.jsonid 为键,因此idselectvalue 等于丢配置,这是版本兼容的唯一抓手。最后,不要用 JS 运行时校验设置、不要写”设置迁移脚本”、不要用设置开关去拉第三方 CDN 脚本——这三件事在主题体系里都没有意义。

最后更新时间: