前台 Home Liquid 渲染说明与 COD 单页商品详情
本文档整理 HomeBaseController 与主题相关的 Liquid 渲染逻辑、商品详情页路径,以及 codOnePageProduct(cod_page 专用模板) 的实现方式。
一、整体两层:Layout 与 Template
1. Layout(布局文件)
- 位置:
public/theme/default/layout/*.liquid(及按主题覆盖的theme/{theme_dir}/layout/)。 - 入口:
HomeBaseController::fetch($file, ...)。 $file与布局文件对应关系:$file === ''→ 使用theme.liquid(默认整站外壳:头尾、<main>等)。$file === 'template'→ 使用template.liquid(通常仅含{% template %},多用于弹窗 quick view 等)。$file === 'checkout'→checkout.liquid(结算等特殊流程;另有强制theme_dir = system等逻辑)。
数据库主题(file_system = database)时,layout 内容可能优先从主题资产读取,再走本地文件兜底,逻辑在 HomeBaseController::fetch() 内。
2. Template(页面主体模板)
-
位置:
public/theme/default/templates/*.liquid(及主题覆盖路径 / DB 资产)。 -
注入点:默认布局
theme.liquid中在<main>内调用:{% template %} -
实际文件名由谁决定:由
app('Context')->template决定(例如product_detail→ 读取templates/product_detail.liquid)。 -
实现:自定义标签类
liquidExtend\tags\TagTemplate:- 空写法的
{% template %}会使用Context里的template; - 再通过
OemsaasLocal/OemsaasDatabase按主题目录或 DB 读对应 liquid 源码。
- 空写法的
二、app('Context')->template 如何写入
HomeBaseController::handlerTemplate($data) 中:
- 若
$data中包含template键(多数业务控制器传入),则直接设置:Context->template = $data['template']Context->template_route仍按当前请求的 controller/action 推导(与路由展示用一致)。
- 若未传入
template,则按controller_action推导(如index_index会特殊映射为index)。
商品详情在 Product::detail() 里显式传入 template => product_detail(quick view 时为 product_quick_detail 且 fetch 的 layout 为 template)。
三、主题目录与「没有 templates 文件夹」
- 当前应用支持
file_system = file(磁盘)与file_system = database(主题文件存库)两种形态。 - 非
default主题目录下可能没有完整的templates/,原因常见为:- 该主题为 DB 主题,模板在主题资产表中;
- 或部分文件回退到
public/theme/default/下的同名路径。
TagTemplate 使用的根路径以 public/theme/default/templates 为基准,再通过 theme_dir 与 FileSystem 实现覆盖或 DB 读取。
四、商品详情页渲染路径(简要)
- 路由:
/products/detail/:id、/products/:handle等 →Product/detail(见app/home/route/route.php)。 Product::detail()组装数据后设置template/template_route,最后$this->fetch($file, $renderData, ...)。- 普通详情:
$file为空 →theme.liquid→{% template %}→product_detail.liquid。 - Quick view:
quick_view参数使template变为product_quick_detail,且$file = 'template'→layout/template.liquid。
五、DIY 文件映射:TYPE_FILE_MAP 与 cod_page
当未匹配到常规路由时,app/home/ExceptionHandle.php 中会对 DiyFileModel::TYPE_FILE_MAP 解析 JSON,得到 type、value 等,再调用:
DiyFileService::handlerPathByFileType($mapType, $mapValue)
得到 ThinkPHP 的 pathinfo(如cod-one-page-products/detail/123),然后dispatch重新进入 MVC。
cod_page 类型:在设置 app('Context')->cod_page = $fileContent 后,应保证 map 的 JSON 中带有业务需要的字段(例如自定义 liquid 模板名 template),供下文 codOnePageProduct 使用。
六、codOnePageProduct:复用 Product/detail,仅替换模板
设计目的
- 不修改
app/home/controller/Product.php。 - 除 Liquid 页面模板名 外,其余逻辑与
Product::detail()完全一致。
实现要点
-
新控制器:
app/home/controller/codOnePageProduct.phpclass codOnePageProduct extends Product- 重写
fetch():若存在app('Context')->cod_page['template'],且当前$data['template'] === 'product_detail',则将其替换为cod_page['template'],再调用parent::fetch(...)。
-
新路由:
app/home/route/route.phpRoute::get('/cod-one-page-products/detail/:id', 'codOnePageProduct/detail'); -
分发路径:
common/services/DiyFileService::handlerPathByFileType()case 'cod_page':products/detail/$id→cod-one-page-products/detail/$id
运维 / 模板侧约定
- 需在主题中存在与
cod_page.template同名的templates/<name>.liquid(文件主题或 DB 主题均可,按现有 FileSystem 规则加载)。 - 若未设置
cod_page.template,行为与原版商品详情一致(仍为product_detail)。
七、相关文件索引
| 说明 | 路径 |
|---|---|
| 渲染入口、layout 选择 | app/home/HomeBaseController.php(fetch、handlerTemplate) |
| 主题与 Context 预热 | common/services/HomePublicVarsService.php |
{% template %} 标签 | extend/liquidExtend/tags/TagTemplate.php |
| 模板文件解析(本地 / DB) | extend/liquidExtend/fileSystem/OemsaasLocal.php、OemsaasDatabase.php |
| 前台路由 | app/home/route/route.php |
| 商品控制器 | app/home/controller/Product.php |
| COD 单页商品(仅改模板) | app/home/controller/codOnePageProduct.php |
| DIY map 分发 | app/home/ExceptionHandle.php、common/services/DiyFileService.php |
| 默认外壳与插槽示例 | public/theme/default/layout/theme.liquid、layout/template.liquid |
文档版本:与仓库内 codOnePageProduct 实现同步;若有路由或 path 命名调整,请同步更新本节「新路由」与 handlerPathByFileType 说明。