店铺装修与 Liquid 前台渲染
基于源码梳理:
ThemesService、HomeBaseController、liquidExtend自定义 Tag、主题文件与 DB 资产。
一、总体流程:从皮肤安装到前台展示
每个皮肤(theme)在磁盘或主题资产库中都有 config/ 目录,至少包含两个 JSON 文件:
| 文件 | 作用 |
|---|---|
settings_schema.json | 配置项清单(表单结构、可装修页面列表、可添加积木库) |
settings_data.json | 默认配置数据(全局默认值、各页面积木默认 params) |
路径示例:public/theme/{name}/config/;file_system=database 时等价内容在 o_theme_asset 的 /config 目录。
这两个文件 不会 在运行时整文件读给前台用户,而是:安装时 由 initThemeData() 把默认值抽取写入店铺 DB;浏览时 前台读 DB 中的店铺装修数据 + Liquid 模板渲染 HTML。
1.1 流程总览
flowchart TB subgraph ThemePkg["皮肤包 config/"] SS[settings_schema.json] SD[settings_data.json] LQ[layout / templates / sections *.liquid] end subgraph Install["店铺安装皮肤"] INS[ThemesService::install] ROW[o_store_theme 插入一行] INIT[initThemeData] end subgraph DB["店铺装修数据(MySQL)"] ST[(o_store_theme<br/>params / preview_params)] TB[(o_theme_block<br/>各页面积木实例)] end subgraph Publish["商家编辑 / 发布(可选)"] EDIT[改 preview_*] PUB[publish → params / position 同步] end subgraph Front["前台访客浏览"] SEL[HomePublicVarsService 选默认皮肤] GL[读 o_store_theme.params] BL[TagGetBlocks → o_theme_block] REN[HomeBaseController::fetch + Liquid] end SS --> INIT SD --> INIT INS --> ROW --> INIT INIT --> ST INIT --> TB EDIT --> ST & TB PUB --> ST & TB SEL --> ST SEL --> BL GL --> REN BL --> REN LQ --> REN REN --> HTML[HTML 展示给用户]
1.2 阶段 A:安装皮肤 → initThemeData
触发入口
| 场景 | 调用链 |
|---|---|
| 商家安装 file 皮肤 | POST themes/ → ThemesService::install() → 事务内插入 o_store_theme → 立即 initThemeData($name, 'file', $themeId) |
| 新店铺默认皮肤 | initDefaultTheme() → 同上,name=default,且 default=1 |
| 商家安装 database 皮肤 | install() 只插入 o_store_theme;ThemeTool 同步 asset 后 → POST themes/{id}/assetsyncfinish → themeAssetSyncFinish() → 再调 initThemeData() |
修改 settings_data.json 且店铺尚未有 params | initThemeDataBySettingData()(themeasset 更新回调等) |
initThemeData() 读取 config(ThemesService.php)
settings_schema.json+settings_data.json(file 读磁盘,database 读o_theme_asset)- 各 section 的
{% schema %}(getThemeSectionsConfig*,用于is_global判断与缺省default)
写入哪些表
| 表 | Model | 写入内容 | 来源 |
|---|---|---|---|
o_store_theme | StoreThemeModel | params、preview_params ← JSON 字符串 | settings_data.json 的 global 整段(含 sections.header/footer、全局间距/颜色等) |
o_theme_block | ThemeBlockModel | 多行积木块记录 | 遍历 settings_schema.pages_setting 每页每个 section;跳过 is_global=true(header/footer 不进此表) |
o_theme_block 单行字段来源
| 字段 | 取值 |
|---|---|
store_id / theme_id | 当前店铺与刚安装的主题 ID |
route / route_handle | 来自 pages_setting 该项 |
type | section 类型,如 block_slides、product_detail |
fixed | pages_setting 的 fixed → 1 top / 2 drag / 3 bottom / 4 require |
params、preview_params | 优先 settings_data.pages_settings[route_routeHandle][type] 第一条;否则 section liquid schema 的 default |
position、preview_position | 安装顺序递增 |
group_id | 默认 0(默认组) |
published_at | 安装时设为 time()(初始数据即视为已发布态) |
安装前会先 DELETE 该 theme_id 下已有 o_theme_block,再 saveAll 批量插入。
不写入 DB 的部分
settings_schema.json、settings_data.json原文件仍留在皮肤目录 /o_theme_asset(供后台GET themes/{id}/configs、主题升级 merge 用)- Liquid 模板(layout、sections 等)仍在磁盘或
o_theme_asset,不复制进o_theme_block
1.3 阶段 B:商家装修与发布(简述)
安装完成后,商家可在后台改装修;改动先写 预览字段,发布后才对访客生效:
| 数据 | 编辑时 | 发布后(访客可见) |
|---|---|---|
| 全局 | o_store_theme.preview_params | o_store_theme.params |
| 页面积木 | o_theme_block.preview_params、preview_position | params、position |
POST themes/{id}/publishments → ThemesService::publish(),并清 Liquid/Redis 缓存。
1.4 阶段 C:前台访客浏览 → 渲染
sequenceDiagram participant U as 访客 participant HPV as HomePublicVarsService participant ST as o_store_theme participant TB as o_theme_block participant HBC as HomeBaseController participant LQ as Liquid U->>HPV: HTTP 请求进入 app/home HPV->>ST: setThemeDir() 选 theme_id<br/>(默认 default=1 的皮肤) HPV->>ST: setThemeGlobalData() 读 params → theme_config.global U->>HBC: Controller → fetch() HBC->>LQ: 渲染 layout/theme.liquid LQ->>ST: header/footer 用 theme_config.global.sections LQ->>TB: TagGetBlocks → themeData → list(preview=0) LQ->>LQ: block_main → 各 section liquid LQ->>U: HTML
选哪套皮肤(setThemeDir() 优先级):
- URL
?theme_id= - Cookie 预览主题
- 域名绑定主题
o_store_theme中default=1且已发布的主题(ThemesService::default())
读哪些装修数据
| 用途 | 数据来源 | 说明 |
|---|---|---|
| 全局 header/footer、整站样式 | o_store_theme.params(正常访客 theme_preview=0) | 注入 Context->theme_config.global |
| 当前页中间积木列表 | o_theme_block(published_at>0,group_id=0 或组装修匹配) | TagGetBlocks → ThemesService::themeData() |
| 页面 HTML 结构 | 皮肤 layout/、templates/、sections/ | 按 theme.name(theme_dir)或 database asset 加载 |
与 config 文件的关系:访客请求 不直接读 settings_schema.json / settings_data.json;仅当 DB 中缺字段时,部分逻辑会用 settings_data 做 深合并补全(如 getThemeGlobalData() 在 API/内部链路中)。
1.5 一张表对照:config 字段 → DB → 前台
| config / 皮肤文件 | 安装后进 DB | 前台谁读 |
|---|---|---|
settings_data.global | o_store_theme.params | theme_config.global、layout 中 header/footer section |
settings_data.pages_settings + pages_setting 结构 | o_theme_block 多行 | TagGetBlocks → blocks → block_main.liquid |
settings_schema.global_setting | 不单独存表(值已在 global JSON 里) | 仅后台表单定义;前台用已保存的 global 值 |
settings_schema.pages_setting / blocks_setting | 不存表 | 后台编辑器;pages_setting 参与 init 与 sectionsFormat |
sections/*.liquid | 不存表 | Liquid 渲染引擎按 type 加载模板 |
更细的 schema 子类型说明见 settings-schema-reference.md。
二、架构总览
装修模块采用 「Liquid 模板 + JSON 配置 + DB 积木块实例」 三层结构:
flowchart TB subgraph Backend["后台(app/api)"] Editor[装修编辑器] API[Themes / ThemeGroup / ThemeView API] TS[ThemesService] TBS[ThemeBlockService] TAS[ThemeAssetService] end subgraph Storage["存储"] ST[(o_store_theme)] TB[(o_theme_block)] TA[(o_theme_asset)] TRG[(o_theme_route_group)] Disk["public/theme/{name}/"] end subgraph Frontend["前台(app/home)"] HPV[HomePublicVarsService] Fetch[HomeBaseController::fetch] LQ[Liquid Template + Tags] end Editor --> API --> TS TS --> ST & TB & TA & TRG TS --> Disk HTTP[用户请求] --> HPV --> Fetch --> LQ LQ --> TB LQ --> ST LQ --> Disk LQ --> TA
| 层次 | 职责 | 典型位置 |
|---|---|---|
| 主题皮(Liquid 文件) | 定义 section/template/snippet 的 HTML 结构与 {% schema %} 表单 | public/theme/default/ 或 o_theme_asset |
| 主题配置(JSON) | 装修后台 UI schema、页面默认 section 列表、全局默认值 | config/settings_*.json |
| 店铺装修数据(DB) | 商家拖拽后的积木块实例、全局样式、分组/视角绑定 | o_store_theme、o_theme_block 等 |
三、核心数据表
3.1 o_store_theme(店铺已安装主题)
| 字段 | 说明 |
|---|---|
store_id | 租户隔离 |
sys_theme_id | 系统主题市场 ID(可选) |
type | public(共享皮)/ private(店铺私有) |
name | 主题目录名,如 default、brooklyn、dbtheme_123 |
file_system | file:读磁盘;database:读 o_theme_asset + OSS |
default | 是否店铺默认主题(前台无指定时用它) |
params / preview_params | 全局装修 JSON(header/footer 等 global sections) |
publish_at | 最近发布时间 |
theme_admin_id | 域名管理员隔离(可选) |
Model:common/models/StoreThemeModel.php
3.2 o_theme_block(页面积木块实例)
| 字段 | 说明 |
|---|---|
theme_id | 所属主题 |
route / route_handle | 页面路由,如 index/index、product/detail + 商品 handle |
type | 对应 sections/{type}.liquid 文件名 |
params / preview_params | 积木块配置 JSON(settings、blocks、display 等) |
position / preview_position | 排序 |
fixed | 1=top / 2=drag / 3=bottom / 4=require |
group_id | 0 = 默认组;>0 = 组装修专属 |
status | 1 正常 / 0 预览态软删 |
published_at | >0 表示曾发布过 |
注意:is_global=true 的 section(如 header/footer)不写入 o_theme_block,运行时从 o_store_theme.params 与 settings_data.json 合并注入。
Model:common/models/ThemeBlockModel.php
3.3 o_theme_asset(database 主题文件)
| 字段 | 说明 |
|---|---|
theme_id | 主题 ID |
folder | /config、/sections、/layout、/templates、/assets 等 |
file_name | 如 header.liquid、settings_schema.json |
content | 小文件 inline 内容 |
content_oss_bucket / public_url | 大资源走 OSS |
Service:common/services/ThemeAssetService.php
3.4 组装修与视角
| 表 | 作用 |
|---|---|
o_theme_route_group | 分组定义(名称、obj_type) |
o_theme_route_group_item | 对象与分组绑定(同一 obj 在同一 theme 下只属一组) |
o_theme_view | 视角定义 + 受众条件(设备/国家/UTM) |
支持的 obj_type(8 种):PRODUCT、COLLECTION、TOPIC、BLOG、COUPON、PROMOTION、NEWS、ACCOUNT。
专题文档:
四、主题文件目录与 Liquid 配置
基准路径:public/theme/default/(其他主题通过 theme_dir 覆盖同名路径)。
public/theme/default/
├── config/ # 主题级 JSON 配置
│ ├── settings_schema.json
│ ├── settings_data.json
│ └── settings_cblock_schema.json
├── layout/ # 整页外壳
│ ├── theme.liquid # 默认 layout
│ ├── template.liquid # 仅 {% template %},用于 quick view 等
│ └── checkout.liquid # 结算(强制 theme_dir=system)
├── templates/ # 页面主体模板
│ ├── index.liquid
│ ├── product_detail.liquid
│ └── block_main.liquid # 循环渲染 blocks
├── sections/ # 可配置积木块(含 {% schema %})
│ ├── header.liquid
│ ├── footer.liquid
│ └── ...
├── snippets/ # {% include %} 片段
├── assets/ # CSS/JS/图片(asset_url filter)
├── locales/ # 多语言 JSON
└── lib/ # 前端脚本与样式模块
4.1 settings_schema.json
装修后台编辑器 UI 的元数据,主要块:
⚡⚡⚡ 一句话概括:
schema= 装修编辑器的配置项清单(能改什么)
|| 键 | 作用 |
||----|------|
|| global_setting | 全局样式表单项(间距、宽度、颜色、开关等),对应「主题设置 → 常规」 |
|| pages_setting | 各 route 可安装的 section 列表及 fixed(top/drag/bottom/require);安装主题时用于初始化 o_theme_block |
|| blocks_setting | 可拖拽「内容积木库」分类(sections[].id = block type) |
|| default_blocks_setting | 与 default 主题 merge 策略(mode=none 时不 merge) |
读取:ThemesService::getThemeConfig() → getThemeConfigFromFile() / getThemeConfigFromDatabase()。
详细说明(各子类型结构、后台页面对应、merge 逻辑):settings-schema-reference.md
4.2 settings_data.json
主题出厂默认装修数据:
⚡⚡⚡ 一句话概括:
data= 主题自带的默认装修效果(默认长什么样)
|| 键 | 作用 |
||----|------|
|| global | 全局 section 默认值(如 global.sections.header.settings) |
|| pages_settings | 各页面 route 下各 section 的默认 params |
与店铺 o_store_theme.params 深合并(getThemeGlobalData()),得到前台 theme_config.global。
4.3 settings_cblock_schema.json
内容积木(cblock) schema:轮播、单商品等可复用内容块,供编辑器「内容库」选用。
4.4 Section 内 {% schema %}...{% endschema %}
每个 sections/{type}.liquid 末尾的 JSON 定义:
name、tag、classis_global:true 时不进o_theme_block,走全局 paramssettings[]:该 section 的表单项定义blocks[]:section 内子块定义default:默认params(安装与缺省合并用)
解析:ThemesService::getThemeSectionJsonStr()(正则提取)→ getThemeSectionsConfig()。
五、两种主题存储:file vs database
| 维度 | file_system=file | file_system=database |
|---|---|---|
| 物理位置 | public/theme/{name}/ | o_theme_asset + OSS |
| 安装后 | 立即 initThemeData() | 等 ThemeTool 同步 asset → themeAssetSyncFinish |
| 类型 | 通常 type=public | 通常 type=private(复制/二开) |
| 前台 Liquid | OemsaasLocal 读磁盘 | OemsaasDatabase 读 DB,缺失回退 default 磁盘 |
| 静态资源 URL | /theme/{dir}/assets/... | OemsaasFilter::asset_url 走 OSS public_url |
| 复制主题 | copy() 扫磁盘写入 DB | copyThemeContent 复制行 + OSS |
Fallback 规则(database 模式):config、sections、layout 等若 DB 无记录,回退 public/theme/default/ 同名文件。
完整 database 流程(ThemeTool 同步、Redis、OemsaasDatabase、排障):database-theme-flow.md
六、后台 API 与业务流程
路由定义:app/api/route/route.php(组名 themes、themes-group、themes-view、themeasset)。
6.1 主题生命周期
安装 POST themes/ → ThemesService::install()
1. 插入 o_store_theme(file→public,database→private)
2. file_system=file → initThemeData(name, file, themeId)
3. file_system=database → 等 asset 同步后 POST themes/{id}/assetsyncfinish
4. initThemeData 流程:
a. 读 settings_schema + settings_data + 各 section schema
b. 写 store_theme.params / preview_params ← setting_data.global
c. 清空旧 blocks,按 pages_setting 逐页插入 o_theme_block(跳过 is_global section)
编辑(预览态)
| 操作 | API | 写入字段 |
|---|---|---|
| 改全局设置 | PUT themes/{id}/globaldata | preview_params |
| 增/改 section | POST/PUT themes/{id}/sections* | preview_params / preview_position |
| 删 section | DELETE themes/{id}/sections* | status = PREVIEW_DELETE(软删,发布时物理删除) |
| 批量排序 | POST themes/{id}/sections/batchsave | preview_position |
| 拉编辑器数据 | GET themes/{id}/data | 固定 preview=1(只看草稿) |
发布 POST themes/{id}/publishments → ThemesService::publish()
事务内:
store_theme.params ← preview_params
theme_block.position ← preview_position, params ← preview_params, published_at=now
物理删除 status=PREVIEW_DELETE 的 block
可选 default=1 取消其他主题 default
清缓存:themeData('default')、themeSections('default')、LiquidCacheService::clearLiquidRenderCache()
重置 POST themes/{id}/reset
撤销未发布编辑:preview_* ← 已发布字段;删除 published_at=0 的新增 block。
复制
copy():private/database 副本,复制 blocks、route groups、assets、languagescopyThemeForPublic():public/file 副本,复制 blocks/groups,不复制磁盘 asset
6.2 预览 vs 已发布(双轨字段)
| 实体 | 预览(编辑器 / 带 Cookie 的前台) | 已发布(正常访客) |
|---|---|---|
| 全局 | preview_params | params |
| 积木块参数 | preview_params | params |
| 积木块排序 | preview_position | position |
| 删除 | status=PREVIEW_DELETE(发布时物理删) | — |
前台 preview 开关:HomePublicVarsService::setThemeDir() 读取
COOKIE_FIREWALL_IS_THEME_EDIT / ?is_theme_edit= → Context->theme_preview。
6.3 组装修 API(themes-group)
| 能力 | 说明 |
|---|---|
| 创建组 | 复制默认组或指定组的 blocks 到新 group_id |
| 绑定对象 | theme_route_group_item;同一 obj 会先解绑旧组 |
| 查组 | getGroupByObjIdAndType / getGroupByHandlerAndRoute |
6.4 视角 API(themes-view)
每主题最多 20 个视角。视角 params 由 AbPlanService::checkParams() 匹配;积木 params.display 绑定可见视角 ID。
七、前台渲染完整管线
7.1 请求 → Context 预热
HTTP 请求
→ middleware: RateLimit / DomainAnalysis(写入 storeId、storeInfo)
→ HomeBaseController::initialize()
→ HomePublicVarsService::handle()
setRoutes() → Context->routes(current_route、current_route_handle)
setThemeDir() → theme_id、theme_dir、theme_preview
setThemeGlobalData() → theme_config.global
→ langHandle / customerHandle / gateWay ...
→ 业务 Controller::action() → fetch($file, $data)
说明:注释中的「middleware HomePublicVariable」实际对应 HomePublicVarsService,在 initialize() 调用,非独立中间件。
7.2 主题选取优先级(setThemeDir)
- URL
?theme_id= - Cookie
COOKIE_FIREWALL_THEME_ID - 域名绑定主题
getDomianThemeId() - 店铺
default=1主题
写入 Context:theme、theme_dir(= theme.name)、theme_id、theme_preview、is_theme_edit。
7.3 HomeBaseController::fetch() 步骤
public function fetch(string $file = '', array $data = [], bool $display = true, string $content = '', $log = false)| 步骤 | 逻辑 |
|---|---|
| 1 | Liquid 全局:INCLUDE_SUFFIX=liquid,ESCAPE_BY_DEFAULT=false |
| 2 | 选 layout:''→theme.liquid,'template'→template.liquid,'checkout'→checkout.liquid |
| 3 | theme_dir 覆盖路径:theme/default → theme/{theme_dir} |
| 4 | file_system=database:预载 ThemeAssetService::getThemeAssetsByDatabase();layout 可从 DB 读 /layout/*.liquid |
| 5 | 结算页强制 theme_dir=system |
| 6 | handlerTemplate($data) → 设置 Context->template |
| 7 | mergeData($data) → 合并整棵 Context + 控制器数据 |
| 8 | variableEncrypt($data) → 前端追踪变量包 |
| 9 | AST 文件缓存 liquidExtend\file\File($themeName)(?liquid_cache= 可关) |
| 10 | 注册 OemsaasFilter + extend/liquidExtend/tags/*.php |
| 11 | parse + render |
| 12 | 注入 Context->stylesheet / javascript 到 </head> / </body> |
7.4 两层 Liquid:Layout + Template
Layout(layout/theme.liquid):
<header>
{% section 'header', section:theme_config.global.sections.header, cached:true %}
</header>
<main>
{% template %}
</main>
<footer>
{% section 'footer', section:theme_config.global.sections.footer, cached:true %}
</footer>Template(如 templates/index.liquid):
{% get_blocks route={routes.current_route} route_handle={routes.current_route_handle} limit=80 %}
{% template block_main, { blocks:blocks } %}Context->template 来源(handlerTemplate):
- 控制器
$data['template']优先(如Product::detail传product_detail) - 否则
controller_action(index_index映射为index)
7.5 积木块渲染链
TagGetBlocks
→ ThemesService::themeData(theme_id, route, route_handle, theme_preview, ..., themeGroupExtData)
→ ThemeBlockService::list / listByGroupId
→ sectionsFormat()(注入 fixed/global section、补全缺失 fixed 块)
→ TagGetBlocks::view()(视角 display 过滤)
→ context.blocks
block_main.liquid 循环 blocks
→ {% section section_name, { section: block.params, block_id, ... } %}
→ TagSection 读 sections/{type}.liquid 渲染
7.6 组装修前台匹配(ThemesService::themeData)
完整流程见 route-group-decoration.md § 六。
route 不在 supportGroupRouteList → themeDataByHandler(group_id=0)
group_id === 0(显式默认组)→ themeDataByHandler
group_id 为空:
obj_id ← 请求上下文 / getObjIdByHandler(objType, routeHandle)
group_id ← ThemeRouteGroupCacheService::getGroupIdByObjIdAndType()
group_id 仍空 → themeDataByHandler(fallback 默认组 blocks)
有 group_id → themeDataByGroup → 读该 group 下 blocks
TagGetBlocks 可通过 obj_id、group_id 参数影响匹配(装修编辑器左侧预览商品区场景)。
7.7 视角(ThemeView)前台逻辑
完整说明见 theme-view-ab-display.md。
view_id← URL?view_id=或getPatchViewId()(AbPlanService::checkParams遍历视角)- block 的
params.display为视角 id 列表时:当前视角在列表内 → 显示;不在 → 隐藏(display=true) - 装修模式(
is_theme_edit=1)额外校验device参数
7.8 Block 预览接口
GET/POST /block/:id、/block/type/:type → app/home/controller/Block.php::rendering()
- 有
id:getThemeBlockParamsById()读 preview_params - 渲染:
display('{% section {type}, { section, block_render: 1 } %}') block_render=1时TagStylesheet/TagJavascript内联输出(AJAX 片段)
八、Liquid 文件加载机制
8.1 FileSystem 实现
| 类 | 路径 | 用途 |
|---|---|---|
OemsaasLocal | extend/liquidExtend/fileSystem/OemsaasLocal.php | 磁盘主题 |
OemsaasDatabase | extend/liquidExtend/fileSystem/OemsaasDatabase.php | DB 主题 |
OemsaasLocal::fullPath():
- 先查
public/theme/{theme_dir}/{type}/{name}.liquid - 不存在则回退
public/theme/default/...
OemsaasDatabase::readTemplateFile():
- 从
Context->themeAssets按/sections/header.liquid等路径取 content - 无内容则
fullPath()回退磁盘
8.2 各类型由谁加载
| 类型 | 目录 | 加载入口 |
|---|---|---|
| Layout | layout/ | fetch() 直接 file_get_contents 或 DB content |
| Template | templates/ | TagTemplate |
| Section | sections/ | TagSection |
| Snippet | snippets/ | TagInclude(Template 构造时传入 include 根路径) |
8.3 自定义 Tag 注册
fetch() 扫描 extend/liquidExtend/tags/Tag*.php,文件名 snake_case 即为 tag 名:
| Tag | 作用 |
|---|---|
template | 渲染 templates;集成整页 Redis 片段缓存 |
section | 渲染 sections;支持 cached / cache_key |
include | 渲染 snippets |
get_blocks | 从 DB 拉 blocks 列表 |
schema / endschema | 解析期块,render 输出空 |
stylesheet / javascript | CSS/JS 收集到 Context 或内联 |
get_products、get_product、get_collections… | 40+ 数据拉取 tag |
Filter:extend/liquidExtend/filters/OemsaasFilter.php(asset_url、format_price、图片域名等)。
九、缓存层次
| 层级 | 实现 | 说明 |
|---|---|---|
| Liquid AST | liquidExtend\file\File | runtime/liquid/cache/{themeName}/,md5(source),约 90 天 |
| 整页/片段 HTML | LiquidCacheService | index、collection_detail、header 等 Redis 缓存;编辑模式/B 站跳过 |
| theme sections | CacheKeyHelper::themeSections('default') | 默认主题非 preview 时 1 天 |
| theme assets | ThemeAssetService | themeFiles、themeAssets Redis hash |
| route group | ThemeRouteGroupCacheService | obj_id → group_id |
发布主题时:LiquidCacheService::clearLiquidRenderCache() + 相关 Redis key 删除。
十、关键类与方法索引
| 组件 | 路径 | 关键方法 |
|---|---|---|
| 主题编排 | common/services/ThemesService.php | install, publish, reset, initThemeData, themeData, getThemeConfig, sectionsFormat |
| 积木块 | common/services/ThemeBlockService.php | add, update, list, listFormat, saveAll |
| 主题资产 | common/services/ThemeAssetService.php | getThemeAssetsByDatabase, getContentsByFolder, copyThemeContent |
| 组匹配 | common/services/ThemeRouteGroupHandlerService.php | getGroupByObjIdAndType, getObjIdByHandler, objTypeToRoute |
| 视角 | common/services/ThemeViewService.php | getPatchViewId, add, del |
| 前台变量 | common/services/HomePublicVarsService.php | handle, setThemeDir, setThemeGlobalData |
| 渲染入口 | app/home/HomeBaseController.php | fetch, handlerTemplate, mergeData, variableEncrypt |
| 积木 tag | extend/liquidExtend/tags/TagGetBlocks.php | render, view |
| 模板 tag | extend/liquidExtend/tags/TagTemplate.php | render + 页面缓存 |
| 后台 API | app/api/controller/Themes.php | install, publish, themeData, blockAdd… |
十一、端到端时序(访客访问首页)
sequenceDiagram participant U as 访客 participant C as Index Controller participant H as HomeBaseController participant G as TagGetBlocks participant T as TagTemplate participant S as TagSection U->>C: GET / C->>H: fetch('theme', data) H->>H: parse theme.liquid H->>S: section header(global params) H->>T: template → index.liquid T->>G: get_blocks index/index G->>G: themeData → o_theme_block T->>T: block_main.liquid T->>S: 各 drag section H->>S: section footer H->>U: HTML
十二、扩展:新增组装修对象类型
最小改动:
ThemeRouteGroupModel::getAllObjTypeList()— 增加常量ThemeRouteGroupHandlerService::objTypeToRoute()— 路由映射getObjIdByHandler()/getObjIdByRawHandler()— handle → obj_iddefaultGroupFirstItem()— 默认组预览项- 按需新增业务 Service/Model
十三、排障 checklist
| 现象 | 排查点 |
|---|---|
| 前台仍是旧装修 | 是否发布;theme_preview;Redis/Liquid 缓存 |
| 某商品页装修不对 | theme_route_group_item 绑定;TagGetBlocks 的 obj_id/group_id |
| database 主题缺模板 | o_theme_asset 是否有对应 folder;default 磁盘 fallback |
| 编辑器与线上一致 | 编辑器 themeData 固定 preview=1;访客读 params |
| 组装修不生效 | route 是否在 supportGroupRouteList;group 是否已发布 blocks |