跳到主内容

主题开发

使用 Liquid 模板语言开发 ShopFaaS 店铺前台主题。

本指南面向主题开发者、二次开发伙伴、AI 主题生成器。以 default/1.0.0 主题为标杆与参照,描述 ShopFaaS 店铺前端的模板体系、上下文变量、自定义标签与过滤器。所有内容均以实际代码为依据。


三层模板机制

ShopFaaS 店铺前端渲染由三层组成,按优先级从高到低:

层级角色实现技术
L1 主题源码商家可定制的 Liquid 主题包Liquid(liquidjs 引擎)
L2 运行时存储Liquid 引擎实际读取的副本(S3 + Local 双写)对象存储
L3 兜底组件主题缺失或模板不存在时的默认实现Astro + Solid

关键点:L3 兜底组件是默认实现,不是简单占位。default/1.0.0 主题的 Liquid 源码与 L3 兜底组件1:1 对齐——每个 Liquid section/snippet 都对应一个 .astro 组件,CSS/JS 也保持同步。开发者二次开发新主题时,可参照 default/1.0.0 的源码作为模板,并以 L3 兜底组件为视觉与交互的”正确性基准”。


主题包结构

主题包根目录为 {themeCode}/{version}/,包含 7 个固定子目录:

my-theme/1.0.0/
├── assets/             # 静态资源(CSS / JS / 图片 / 字体)
│   ├── theme.css       # 主题样式
│   └── theme.js        # 主题脚本
├── config/             # 主题配置
│   ├── settings_data.json    # 主题设置当前值
│   └── settings_schema.json  # 主题设置 schema 定义
├── layouts/            # 布局模板
│   └── theme.liquid    # 主布局(HTML 骨架 + 全局 section)
├── locales/            # 多语言翻译文件
│   ├── en.default.json # 默认语言(必须)
│   └── zh-CN.json      # 中文
├── sections/           # Section 文件(可复用页面区块)
│   ├── header.liquid
│   ├── footer.liquid
│   └── ...
├── snippets/           # Snippet 文件(可被 {% render %} 引用的小片段)
│   ├── card-product.liquid
│   └── ...
└── templates/          # 页面模板(按 PageType 映射)
    ├── index.liquid          # HOME
    ├── product.liquid        # PRODUCT
    ├── collection.liquid     # COLLECTION
    └── ...

不存在的目录

以下目录在 ShopFaaS 主题包中不存在

  • schemas/ — section schema 以内联注释形式写在 section 文件首行(见下文”自定义标签”),无独立 schema 目录
  • theme.json — 主题配置统一用 config/settings_data.json,不存在根级 theme.json 文件
  • blocks/ — 当前未实现 block 独立目录机制
  • customers/ — 客户中心页面模板直接放在 templates/ 下(如 customer-login.liquid),无独立子目录

文件命名规范

  • 全部使用 kebab-case:main-checkout.liquid / customer-order-detail.liquid
  • section 文件名 = section 类型名({% section 'main-product' %} 对应 sections/main-product.liquid
  • snippet 文件名 = snippet 名称({% render 'cart-drawer' %} 对应 snippets/cart-drawer.liquid
  • 模板文件名 = PAGE_TYPE_TO_TEMPLATE 映射值(见下文)

Liquid 上下文变量

渲染时注入以下全局变量。所有 section / snippet / layout / template 均可直接引用。

核心业务变量

变量类型说明
shopShopContext店铺信息(id / name / currency / currencyFormat / email / phone / address / domain / timezone / industry / logoUrl)
customerCustomerHeaderSummary | null当前登录客户摘要(displayName / email,未登录为 null)。注意字段名是 displayName,不是 name
pagePageData当前页面业务数据(联合类型,按 pageType 区分)
pageTypestring页面类型枚举值(如 "PRODUCT" / "CUSTOMER_ORDERS"),全大写
sectionsSectionInstance[]当前页面 section 配置列表(snake_case:section_type / section_key / section_config / section_blocks / sort_order
collectionsCollectionSummary[]导航用分类列表(id / handle / title / image / productCount)
languagesShopLanguageOption[]店铺可用语言列表
currenciesShopCurrencyOption[]店铺可用币种列表
themeSettingsRecord<string, unknown>主题设置(扁平字段命名,见下文)
localestringBCP 47 locale(如 en-US / zh-CN
currencystring当前币种 ISO 代码(如 USD / CNY
exchangeRatesExchangeRateMap汇率映射表(key 格式 ${from}_${to},如 USD_CNY
chatChatContext在线客服配置(enabled / welcomeMessage / placeholder / offlineMessage)
overridesRecord<string, string>主题文案 DB 覆盖

顶层展开变量

page 数据会展开到顶层(排除 pagetype 字段),模板内可直接使用展开后的字段:

{{ product.title }}
{{ collection.title }}
{{ cart.items }}
{{ article.title }}
{{ searchQuery }}

CollectionPageData.page(页码数字)单独暴露为 current_page

{% if current_page > 1 %}
  <span>第 {{ current_page }} 页</span>
{% endif %}

请求级变量

变量字段说明
requestlocale.iso_codeBCP 47 locale,用于 <html lang="...">
requestlocale.lang / locale.country拆分的语言/国家代码
requestpage_type页面类型小写(如 home / product / cart
requestdesign_mode是否主题编辑器预览模式(当前固定 false
requestorigin店铺 origin

路由变量 routes

完整 28 个路由 URL,供 layout/sections/snippets 中构造链接。所有路由以 / 开头,无尾斜杠。

字段
routes.root_url/
routes.cart_url/cart
routes.cart_add_url/cart/add
routes.cart_change_url/cart/change
routes.cart_update_url/cart/update
routes.cart_count_url/cart/count
routes.cart_discount_code_apply_url/cart/discount/apply
routes.cart_discount_code_remove_url/cart/discount/remove
routes.search_url/search
routes.predictive_search_url/search/suggest
routes.account_url/account
routes.account_login_url/account/login
routes.account_logout_url/account/logout
routes.account_register_url/account/register
routes.account_recover_url/account/forgot-password
routes.account_order_list_url/account/orders
routes.account_address_new_url/account/addresses/new
routes.address_url/account/addresses
routes.address_countries_url/api/countries
routes.address_country_template_url/api/countries/template
routes.address_next_url/account/addresses/next
routes.company_account_register_url/account/company/register
routes.collections_url/collections
routes.all_products_collection_url/collections/all
routes.blogs_url/blogs
routes.contact_url/pages/contact
routes.privacy_policy_url/policies/privacy
routes.product_recommendations_url/recommendations/products

店铺级设置 settings

固定 3 个字段:

字段说明
settings.cart_add_type"drawer"加购后打开购物车抽屉
settings.predictive_searchtrue启用预测搜索
settings.show_sticky_add_to_carttrue商品页粘性加购按钮

翻译变量

变量说明
__translations当前 locale 完整翻译字典。供 t 过滤器读取。优先级:DB 覆盖 > 主题 locales > 内置字典 > key 本身
client_i18n客户端 JS 共享字典,由 theme.liquid 注入 window.__STOREFRONT_I18N__
__shop_currency店铺基础币种(商品存储币种,如 USD),供 money 过滤器读取
__currency当前用户选择币种(cookie sf_currency 解析结果,如 CNY

客户端 JS 共享变量

theme.liquid 应将以下变量注入 window,供 CartDrawer / CartPage / QuickAddModal 等客户端 JS 读取:

window.__STOREFRONT_I18N__          = client_i18n;
window.__STOREFRONT_CURRENCY__      = currency;
window.__STOREFRONT_LOCALE__        = locale;
window.__STOREFRONT_BASE_CURRENCY__ = shop.currency;
window.__STOREFRONT_RATES__         = exchange_rates;
window.__STOREFRONT_LINK_QUERY__    = link_query;

link_query 含义:开发环境为 ?shop_id=xxx(或 ?shop_id=xxx&theme_preview=xxx),生产环境为空字符串。客户端 JS 构造内部链接时需追加此参数。

link_query已含前导 ? 的完整查询串(如 ?shop_id=xxx),追加到 URL 末尾即可。但需注意 URL 是否已有查询参数:

场景 1:URL 无查询参数(最常见)

直接追加 {{ link_query }}

<a href="/cart{{ link_query }}">购物车</a>
<a href="/products/{{ product.handle }}{{ link_query }}">{{ product.title }}</a>

渲染结果:/cart?shop_id=xxx / /products/premium-hoodie?shop_id=xxx(正确)

场景 2:URL 已有查询参数(如 ?redirect_to=

必须用 | replace_first: '?', '&' 将前导 ? 转为 &,否则 shop_id 会被并入 redirect_to 的值:

{# ❌ 错误:shop_id 被并入 redirect_to 值 #}
<a href="/account/login?redirect_to={{ '/checkout' | url_encode }}{{ link_query }}">登录</a>
{# 渲染结果:/account/login?redirect_to=%2Fcheckout?shop_id=xxx(redirect_to 值变成 %2Fcheckout?shop_id=xxx)#}

{# ✅ 正确:前导 ? 转 & #}
<a href="/account/login?redirect_to={{ '/checkout' | url_encode }}{{ link_query | replace_first: '?', '&' }}">登录</a>
{# 渲染结果:/account/login?redirect_to=%2Fcheckout&shop_id=xxx #}

场景 3:客户端 JS 构造链接

客户端 JS 通过 window.__STOREFRONT_LINK_QUERY__ 读取(已是 ?shop_id=xxx 或空字符串),直接拼接即可:

var linkQuery = window.__STOREFRONT_LINK_QUERY__ || "";
var productUrl = "/products/" + encodeURIComponent(handle) + linkQuery;

Astro 兜底侧:使用 link() 函数(由 createLinker 创建),内部已自动处理 ?/& 切换,无需手动 replace。Liquid 侧因 link_query 是固定字符串,需开发者自行处理。

  • section settings 动态链接{{ section.settings.button_link }} 是用户在主题编辑器配置的 URL(可能是外链或绝对路径),不应追加 link_query
  • OAuth API 链接/api/auth/oauth/* 是 API 路由,无需追加查询参数
  • 静态资产 URL{{ 'theme.css' | asset_url }} 等已由 asset_url 过滤器处理

PageType 与模板映射

完整 PageType 枚举(25 种)

通用页面(12 种)HOME / PRODUCT / COLLECTION / COLLECTION_LIST / SEARCH / CART / BLOG / BLOG_LIST / PAGE / CHECKOUT / ORDER_CONFIRMATION / NOT_FOUND

客户中心页面(13 种)CUSTOMER_LOGIN / CUSTOMER_REGISTER / CUSTOMER_FORGOT_PASSWORD / CUSTOMER_RESET_PASSWORD / CUSTOMER_ACCOUNT / CUSTOMER_ADDRESSES / CUSTOMER_ORDERS / CUSTOMER_ORDER_DETAIL / CUSTOMER_WISHLIST / CUSTOMER_BACK_IN_STOCK / CUSTOMER_BROWSING_HISTORY / CUSTOMER_CONSENT / CUSTOMER_SUBSCRIPTIONS

PageType → 模板文件映射

25 个 PageType 全部映射到对应模板文件:

PageType模板文件
HOMEtemplates/index.liquid
PRODUCTtemplates/product.liquid
COLLECTIONtemplates/collection.liquid
COLLECTION_LISTtemplates/list-collections.liquid
SEARCHtemplates/search.liquid
CARTtemplates/cart.liquid
BLOGtemplates/article.liquid
BLOG_LISTtemplates/blog.liquid
PAGEtemplates/page.liquid
CHECKOUTtemplates/checkout.liquid
ORDER_CONFIRMATIONtemplates/order-confirmation.liquid
NOT_FOUNDtemplates/404.liquid
CUSTOMER_LOGINtemplates/customer-login.liquid
CUSTOMER_REGISTERtemplates/customer-register.liquid
CUSTOMER_FORGOT_PASSWORDtemplates/customer-forgot-password.liquid
CUSTOMER_RESET_PASSWORDtemplates/customer-reset-password.liquid
CUSTOMER_ACCOUNTtemplates/customer-account.liquid
CUSTOMER_ADDRESSEStemplates/customer-addresses.liquid
CUSTOMER_ORDERStemplates/customer-orders.liquid
CUSTOMER_ORDER_DETAILtemplates/customer-order-detail.liquid
CUSTOMER_WISHLISTtemplates/customer-wishlist.liquid
CUSTOMER_BACK_IN_STOCKtemplates/customer-back-in-stock.liquid
CUSTOMER_BROWSING_HISTORYtemplates/customer-browsing-history.liquid
CUSTOMER_CONSENTtemplates/customer-consent.liquid
CUSTOMER_SUBSCRIPTIONStemplates/customer-subscriptions.liquid

自定义标签

{% section 'type' %}

sections/{type}.liquid 读取并渲染。

Section schema 内联注释:section schema 以 JSON 注释形式写在文件首行,无独立 schemas/ 目录:

{%- comment -%}{"schema":{"name":"Header"}}{%- endcomment -%}
{%- comment -%}
  Header section — 描述文字
  上下文变量:shop / locale / currency / languages / currencies / customer / collections
{%- endcomment -%}
<header class="header">
  ...
</header>

Section 实例数据{% section %} 标签从上下文 sections 数组按 section_type 匹配实例。匹配的实例数据通过两个变量暴露给 section 模板:

  • section.settings:section 配置(等价于 section_config
  • section.blocks:section 块数据(等价于 section_blocks

{% render 'snippet' %}

snippets/{snippet}.liquid 读取。支持命名参数传递:

{% render 'card-product', product: product, show_vendor: themeSettings.show_vendor %}

{% layout 'name' %}

layouts/{name}.liquid 读取布局模板。layout 模板内通过 {{ content_for_layout }} 接收子模板渲染结果。

{# templates/index.liquid #}
{% layout 'theme' %}

<div class="index-template">
  {% section 'slideshow' %}
  {% section 'featured-collection' %}
</div>

数据模型

核心数据接口

ProductSummary(列表用)

字段类型说明
idstring商品 ID
handlestringURL handle
titlestring标题
pricenumber价格(单位:分
compareAtPricenumber | null划线价(分)
imagestring | null主图
image2string | null第二张图(hover 切换)
availableboolean是否可售
ratingnumber平均评分(1-5,无评论为 0)
reviewCountnumber评论总数
vendorstring品牌/供应商
specValuesRecord<string, string[]>规格值聚合

ProductDetail(详情页,extends ProductSummary)

新增字段:description / variants / images / options / ageRestricted / sellingPlans

ProductVariant

字段类型说明
idstring变体 ID
titlestring变体标题
pricenumber价格(分)
compareAtPricenumber | null划线价(分)
availableboolean是否可售
optionValuesRecord<string, string>选项值(如 {"COLOR":"Black","SIZE":"M"}
quantitynumber库存数量
skustringSKU 编码

CartItem

字段类型说明
productIdstring商品 ID
variantIdstring变体 ID
titlestring商品标题
quantitynumber数量
pricenumber单价(分)
imagestring | null商品图片
specValuesRecord<string, string> | null变体规格属性

CustomerHeaderSummary(Header 登录态)

字段类型说明
displayNamestring展示名(优先 fullName,无则邮箱前缀)。不是 name
emailstring | null客户邮箱

金额单位统一为「分」:所有 price / compareAtPrice / totalAmount 等字段均为整数分。使用 {{ product.price | money }} 过滤器自动除以 100 并格式化。


themeSettings 字段

命名规范

扁平字段命名,使用 snake_case(如 color_primary / heading_font / page_width),不是嵌套结构(如 colors.primary)。

完整字段清单

字段定义在 config/settings_schema.json,当前值在 config/settings_data.jsoncurrent 字段。

Colors(6 个)

字段类型默认值说明
color_primarycolor#1a1a1a主色
color_secondarycolor#6b7280次色
color_accentcolor#c9a961强调色
color_backgroundcolor#ffffff背景色
color_textcolor#111827文字色
color_bordercolor#e5e7eb边框色

Typography(2 个)

字段类型默认值说明
heading_fonttextGeorgia, serif标题字体 CSS font-family
body_fonttextsystem-ui, sans-serif正文字体

Layout(3 个)

字段类型默认值范围说明
page_widthrange12801024-1600 / step 32页面宽度(px)
container_paddingrange248-48 / step 4容器内边距(px)
section_spacingrange4824-96 / step 8section 间距(px)

完整字段清单参考 default/1.0.0/config/settings_schema.json。常用字段包括:

  • Headerlogo_text / logo_width / sticky_header / show_announcement / mega_menu_show_images / mega_menu_promo_image / mega_menu_promo_title / mega_menu_promo_url
  • Footershow_social / show_payment_icons / footer_text
  • Productshow_vendor / show_reviews / quick_add_enabled
  • Slideshowslideshow_image / slideshow_mobile_image / slideshow_overlay_opacity
  • Social Mediasocial_facebook / social_twitter / social_instagram / social_youtube / social_pinterest / social_tiktok
  • Social Loginoauth_google_enabled / oauth_facebook_enabled / oauth_apple_enabled

注意settings_data.jsoncurrent 字段可能不包含 settings_schema.json 中所有字段。模板中读取未设置的字段会得到 nil,应使用 default 过滤器兜底:{{ themeSettings.color_primary | default: '#1a1a1a' }}

读取方式

主题设置统一从 config/settings_data.jsoncurrent 字段读取(Shopify 标准,扁平结构)。


自定义过滤器

asset_url

主题静态资产路径 → 访问 URL。

<link rel="stylesheet" href="{{ 'theme.css' | asset_url }}">
<script src="{{ 'theme.js' | asset_url }}" defer></script>

asset_img_url

主题图片资产 → 带尺寸参数的 URL。

<img src="{{ 'slide-1.jpg' | asset_img_url: 1920 }}" alt="...">

image_url

图片路径 → 带尺寸参数的 URL(用于商品图、分类图等业务图片)。

<img src="{{ product.image | image_url: 600 }}" alt="{{ product.title }}">

money

金额(分)→ 格式化字符串(含汇率换算)。

{{ product.price | money }}

关键特性:自动从上下文读取币种,模板无需显式传 currency 参数

  • __shop_currency:店铺基础币种(商品存储币种)
  • __currency:当前用户选择币种
  • exchange_rates:汇率映射表

换算逻辑:商品价格以店铺基础币种存储 → 若当前币种 ≠ 店铺基础币种,按汇率换算 → 用 Intl.NumberFormat 格式化(自动除以 100)。

t

多语言翻译。

{{ 'product.addToCart' | t }}
  • __translations 字典查找
  • 不支持 defaultValue 参数,未命中翻译时返回 key 本身
  • 翻译优先级:DB 覆盖 > 主题 locales 文件 > 内置字典 > key 本身

标准过滤器

liquidjs 内置过滤器全部可用:default / escape / strip_html / truncate / divided_by / times / plus / minus / modulo / json / date / capitalize / downcase / upcase / split / join / slice 等。

注意:标准 Liquid 没有 escape_attr 过滤器,仅有 escape


多语言 i18n

双轨制

轨道位置用途key 格式
主题 localeslocales/{locale}.jsonLiquid 模板内 t 过滤器嵌套 JSON(如 {"search":{"title":"Search"}}t 过滤器读取时扁平化search.title
内置字典平台内置兜底组件 + 客户端 JS扁平化 key(如 search.title

locale 文件命名

  • en.default.json:默认语言(必须存在)
  • zh-CN.json:BCP 47 locale 命名

翻译优先级(最终生效顺序)

  1. DB 覆盖(店长在后台编辑的自定义翻译)
  2. 主题 locales 文件
  3. 内置字典
  4. key 本身(兜底)

客户端 JS i18n

theme.liquid 应将 client_i18n 注入 window.__STOREFRONT_I18N__

window.__STOREFRONT_I18N__ = {{ client_i18n | json | default: '{}' }};

主题开发规范

CSS 规范

  • 纯手写 CSS + CSS 变量,禁止使用 Tailwind utility class
  • CSS 变量在 layouts/theme.liquid<style> 块中定义(:root 选择器)
  • 所有主题样式统一放在 assets/theme.css

JavaScript 规范

  • 所有主题脚本统一放在 assets/theme.js
  • 使用原生 JS(ES2020+),不依赖 jQuery / React / Vue 等框架
  • 客户端 JS 通过 window.__STOREFRONT_* 全局变量与服务端共享数据
  • 事件驱动:CartDrawer / CartNotification / QuickAddModal 等组件通过自定义事件通信(如 storefront:cart-updated

可访问性(A11y)

  • 所有交互元素提供 aria-label / aria-expanded / aria-hidden 等属性
  • 图标 SVG 添加 aria-hidden="true" focusable="false"
  • 跳过链接(skip-link)直达正文(WCAG 2.4.1)
  • 表单字段使用 WHATWG autocomplete tokens(given-name / family-name / address-line1 / postal-code / address-level2 / country-name / tel / email
  • 移动端增强:autocapitalize / autocorrect / spellcheck / inputmode

模板编写约定

  • Liquid 输出标签用 {{ }},控制流标签用 {% %},去空格用 {%- -%}
  • 多行注释用 {%- comment -%}...{%- endcomment -%}
  • section 文件首行必须为 schema 内联注释:{%- comment -%}{"schema":{"name":"Section Name"}}{%- endcomment -%}
  • 判空用 == blank(检查空字符串/nil),而非 unless{% if query == blank %}

富文本内容渲染规范(强制,2026-07-20 新增)

后台 RichTextEditor(Tiptap 3.27)输出的 HTML 含 h1-h3 / p / ul / ol / li / blockquote / a / img / pre / code / table / iframe / YouTube 16:9 / 任务列表 / 文字对齐 / 高亮标记 / 文字颜色等元素。所有渲染这类富文本的容器必须追加 rich-text-content class,并在 assets/theme.css 中包含完整样式片段,否则元素会以浏览器默认样式渲染(无边框表格、未限制宽图片、无样式引用块等),与后台编辑器视觉严重不一致。

必须追加 rich-text-content class 的位置

PageType模板文件渲染容器(已有 class)
PRODUCTsections/main-product.liquidcollapsible-content rich-text-content(商品描述折叠面板)
BLOGsections/main-article.liquidarticle-content rich-text-content(文章正文)
PAGEsections/main-page.liquidstatic-content rich-text-content(静态页面正文)
COLLECTIONsections/main-collection.liquidpage-description rich-text-content(分类描述,2 处:有图/无图布局)

平台主题(hardware/megastore/printing)已有 class 名可能是 rte / product__description rte / article__content rte / collection__description rte / page-content__body rte,追加 rich-text-content 与原有 class 共存即可,不替换原 class。

CSS 样式片段要求

assets/theme.css 必须包含覆盖以下元素的完整样式(参考 default/1.0.0/assets/theme.css 末尾的 .rich-text-content 片段):

  • 容器:font-size: 16px / line-height: 1.75 / color: var(--color-text, ...) / 首尾子元素 margin 归零
  • 标题:h1-h4 字号 / 字重 / margin / line-height
  • 段落与列表:p / ul / ol / li(含 ul[data-type="taskList"] 任务列表 flex 布局)
  • 引用:blockquote 左边框 + 斜体
  • 链接:a 颜色 + 下划线 + hover
  • 图片:img max-width: 100% / height: auto / 圆角
  • 代码:pre 深色背景 + code 内联背景 + 等宽字体
  • 表格:table border-collapse / table-layout: fixed / width: 100% / td/th 边框与 padding / th 表头背景 / .tableWrapper 横向滚动 / .selectedCell 选中高亮 / .column-resize-handle 列宽调整手柄
  • 视频:iframe max-width / YouTube 16:9 响应式容器(.rich-text-youtube / div[data-youtube-video] padding-bottom: 56.25%)
  • 文字对齐:[style*="text-align: center/right/justify"]
  • 高亮:mark 黄色背景
  • 响应式:@media (max-width: 640px) 字号略小

避免与首页 section 限宽规则冲突

default/sunset/aurora/ocean 四个 storefront 主题的 theme.css 原有 .rich-text-content { max-width: 720px; margin: 0 auto; } 规则仅用于首页 sections/rich-text.liquid section(居中限宽富文本区块)。新追加的完整样式片段不能覆盖此规则,否则商品描述/文章/页面/分类描述也会被错误限宽到 720px。

正确做法:将原有规则的选择器改为 .rich-text-section .rich-text-content(限定作用域到首页 section),新追加的完整样式片段用 .rich-text-content 通用选择器(不含 max-width/margin)。CSS 同特异性下后者先声明先生效,首页 section 因有更具体的选择器(.rich-text-section .rich-text-content)仍能正确限宽。

新主题开发检查清单

  • 4 个 main-*.liquid 模板中渲染富文本的容器已追加 rich-text-content class
  • assets/theme.css 末尾已包含完整 .rich-text-content 样式片段
  • 若主题含首页 rich-text.liquid section,其限宽规则已用 .rich-text-section .rich-text-content 选择器限定作用域
  • 在商品详情/文章/页面/分类描述页面渲染富文本时,元素样式与后台 RichTextEditor 视觉一致

共享资源

平台提供跨主题共享的 JS 模块,主题可直接引用:

chat-widget.js(在线客服)

{# 在 theme.liquid 或 section/snippet 中引入 #}
<script src="/shared/1.0.0/assets/chat-widget.js" defer></script>

引入后无需显式调用 init(),页面加载后自动查找 .chat-widget 元素并初始化。主题需提供 DOM 骨架(含 data-chat-* 配置属性),参考 default/1.0.0/snippets/chat-widget.liquid


参考实现

default/1.0.0 是 ShopFaaS 官方标杆主题,开发者二次开发时应以此为参照:

  • 25 个模板:覆盖全部 25 个 PageType(通用 12 + 客户中心 13)
  • 38 个 section:含 header / footer / slideshow / main-product / main-collection / main-cart / main-checkout / main-search / main-article / main-blog / main-page / main-customer-*
  • 20 个 snippetcard-product / cart-drawer / chat-widget / cookie-consent / customer-sidebar / facets / icon / loading-spinner / meta-tags / pagination / predictive-search / price / product-media-gallery / product-variant-picker / quantity-input / quick-add-modal / social-icons / swatch / breadcrumb / buy-buttons
  • 1 个 layouttheme.liquid(主布局)
  • 2 个 configsettings_data.json + settings_schema.json
  • 2 个 localesen.default.json + zh-CN.json
  • 2 个 assetstheme.css + theme.js

常见错误与排查

模板修改不生效

  • 主题源码是否已同步到运行时存储?
  • theme-resolver L1 缓存是否未过期?(TTL 10 分钟,可用 ?theme_preview=default 参数绕过)

money 过滤器显示错误价格

  • 检查 __shop_currency / __currency / exchange_rates 是否正确注入上下文
  • 检查汇率表 key 格式是否为 ${from}_${to}(如 USD_CNY
  • 金额单位是否为「分」(整数),而非「元」(浮点)

t 过滤器返回 key 本身

  • key 是否在 __translations 字典中?
  • locale 文件是否已同步?
  • 主题 locales key 是否已扁平化?

section 不渲染

  • section 类型名是否与 {% section 'xxx' %} 参数一致?(含大小写)
  • sections/{xxx}.liquid 文件是否存在?
  • 若 section 类型在 sections 数组中无配置实例,标签会用空配置渲染一次(section 模板需自行处理空数据兜底)

此页面有帮助吗?

在 GitHub 上编辑此页