先定义迁移边界
SHOPLINE OS 2.1 自定义主题使用 Handlebars,OS 3.0 使用 Sline。SHOPLINE Help Center 明确要求 Handlebars 代码需要重写,并提醒同时检查应用兼容、多语言内容和 UGC 数据。
Liquid → Sline 不属于 SHOPLINE 官方迁移路径。本页中的 Liquid 对照,是依据 Liquid 与 Sline 各自官方语法整理的概念映射,用于帮助有 Shopify 经验的开发者理解,不代表存在自动兼容层。
第一步:盘点旧模板
不要从全局搜索花括号开始。先按责任建立清单:
| 责任 | 需要记录的内容 | 迁移目标 |
|---|---|---|
| 数据输出 | 对象、属性、默认值 | 对应的 Sline 对象和属性 |
| 控制流 | 条件、循环、空状态 | Sline 标签与真假值规则 |
| 格式化 | helper、filter、日期、金额、图片 | 官方 Sline 过滤器或专用标签 |
| 复用 | partial、snippet、include | OS 3.0 component、section 或 block |
| 作用域 | this、../、循环变量 |
明确的局部对象和数据传递 |
| 应用内容 | app block、自定义注入、UGC | OS 3.0 兼容方案或重建计划 |
输出清单后,再决定哪些可以逐行改写,哪些必须重构数据或模块。
Handlebars 输出迁移
简单属性输出通常最接近:
<!-- Handlebars -->
<h1>{{product.title}}</h1>
<!-- Sline -->
<h1>{{ product.title }}</h1>
未转义 HTML 在两者中都使用三花括号,但仍必须重新确认目标字段是否可信:
<div class="rte">{{{ product.description }}}</div>
不要把“语法相同”误解为“对象模型相同”。对象名、属性名和可用页面范围都要以 SHOPLINE 对象参考为准。
条件与 else 迁移
<!-- Handlebars -->
{{#if product.available}}
<button>Add to cart</button>
{{else}}
<span>Sold out</span>
{{/if}}
<!-- Sline -->
{{#if product.available}}
<button>加入购物车</button>
{{#else/}}
<span>暂时售罄</span>
{{/if}}
Sline 的 else 是自闭合标签。条件中若包含空数组或空字符串,还要按 Sline 的真假值规则重新测试。
循环与父级作用域
Handlebars 常见写法:
{{#each products}}
<p>{{../collectionTitle}} — {{title}}</p>
{{/each}}
Sline 不支持 ../。不能只把 each 改成 for,还需要改变数据访问方式:
- 确认循环内部是否真的需要父级值。
- 如果是固定文案,把它放到循环外的标题中。
- 如果是每项都需要的数据,让当前项或组件参数明确携带它。
- 如果数据模型无法提供,回到应用层准备数据。
<h2>{{ collection.title }}</h2>
<ul>
{{#for product in collection.products}}
<li>{{ product.title }}</li>
{{/for}}
</ul>
Helper 与 filter 迁移
Handlebars 项目可能注册自定义 helper:
{{uppercase product.title}}
迁移前先分类:
- 官方 Sline 已提供相同格式化:改用对应过滤器。
- 属于主题结构:改为 component、section 或 block。
- 属于业务规则:移到应用或数据层。
- 没有官方等价能力:改变需求,不创建“看起来像 Sline”的私有语法。
管道式写法示例:
{{ product.title | truncate(40) }}
过滤器名称、参数和可接受类型必须逐项查阅 Sline 官方参考。
Liquid 写法的概念迁移
Liquid 条件:
{% if product.available %}
{{ product.title | escape }}
{% endif %}
Sline 的对应任务由标签与过滤器完成:
{{#if product.available}}
{{ product.title | escape() }}
{{/if}}
Liquid 循环:
{% for product in collection.products %}
{{ product.title }}
{% endfor %}
Sline 循环:
{{#for product in collection.products}}
{{ product.title }}
{{/for}}
这些示例只映射控制流。Shopify Liquid 与 SHOPLINE Sline 的商品对象、URL、图片、金额和表单能力不能根据名字相似直接替换。
复用单元不能只改文件名
OS 3.0 把主题组织为 layout、template、section、block 和 component。迁移 partial 或 snippet 时,先判断它的职责:
- 商家需要在编辑器中添加、删除或排序:优先考虑 section 或 block。
- 只是重复使用的展示片段:考虑 component。
- 负责页面整体骨架:属于 layout 或 template。
同一段代码如果既负责商家配置、业务逻辑又负责展示,应先拆开职责,再落入 OS 3.0 目录。
拆分商家可配置模块时,可参考 OS 3.0 Sections 概述;改写后的 Sline 片段可用 AST Explorer 辅助检查语法结构。
每批迁移的验证方法
每次只迁移一个页面类型或一个模块,并准备下列状态:
- 正常商品与完整图片。
- 缺少可选图片或描述。
- 空集合与只有一个商品的集合。
- 已登录与未登录顾客。
- 不同语言和较长文本。
- 应用已安装、未安装和不兼容状态。
- 桌面与手机主题编辑器预览。
迁移完成清单
- 所有
this、./、../和 Handlebars helper 已清点。 - Liquid tag/filter 只按概念映射,没有直接复制平台对象。
- 未转义输出已经逐项确认数据可信。
- 循环和条件覆盖空值边界。
- 复用代码已按 layout/template/section/block/component 重新归类。
- 第三方应用有明确的 OS 3.0 兼容结论。
- 多语言与 UGC 有备份和恢复方案。
- 新主题在测试环境通过关键页面与交易流程验证。
从单段模板迁移,进入完整主题目录与模块边界的比较。