前台 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) 中:

  1. $data 中包含 template(多数业务控制器传入),则直接设置:
    • Context->template = $data['template']
    • Context->template_route 仍按当前请求的 controller/action 推导(与路由展示用一致)。
  2. 若未传入 template,则按 controller_action 推导(如 index_index 会特殊映射为 index)。

商品详情在 Product::detail() 里显式传入 template => product_detail(quick view 时为 product_quick_detailfetch 的 layout 为 template)。


三、主题目录与「没有 templates 文件夹」

  • 当前应用支持 file_system = file(磁盘)与 file_system = database(主题文件存库)两种形态。
  • default 主题目录下可能没有完整的 templates/,原因常见为:
    • 该主题为 DB 主题,模板在主题资产表中;
    • 或部分文件回退到 public/theme/default/ 下的同名路径。

TagTemplate 使用的根路径以 public/theme/default/templates 为基准,再通过 theme_dir 与 FileSystem 实现覆盖或 DB 读取。


四、商品详情页渲染路径(简要)

  1. 路由:/products/detail/:id/products/:handle 等 → Product/detail(见 app/home/route/route.php)。
  2. Product::detail() 组装数据后设置 template / template_route,最后 $this->fetch($file, $renderData, ...)
  3. 普通详情:$file 为空 → theme.liquid{% template %}product_detail.liquid
  4. Quick view:quick_view 参数使 template 变为 product_quick_detail,且 $file = 'template'layout/template.liquid

五、DIY 文件映射:TYPE_FILE_MAPcod_page

当未匹配到常规路由时,app/home/ExceptionHandle.php 中会对 DiyFileModel::TYPE_FILE_MAP 解析 JSON,得到 typevalue 等,再调用:

  • 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() 完全一致。

实现要点

  1. 新控制器app/home/controller/codOnePageProduct.php

    • class codOnePageProduct extends Product
    • 重写 fetch():若存在 app('Context')->cod_page['template'],且当前 $data['template'] === 'product_detail',则将其替换为 cod_page['template'],再调用 parent::fetch(...)
  2. 新路由app/home/route/route.php

    Route::get('/cod-one-page-products/detail/:id', 'codOnePageProduct/detail');
  3. 分发路径common/services/DiyFileService::handlerPathByFileType()

    • case 'cod_page'products/detail/$idcod-one-page-products/detail/$id

运维 / 模板侧约定

  • 需在主题中存在与 cod_page.template 同名templates/<name>.liquid(文件主题或 DB 主题均可,按现有 FileSystem 规则加载)。
  • 若未设置 cod_page.template,行为与原版商品详情一致(仍为 product_detail)。

七、相关文件索引

说明路径
渲染入口、layout 选择app/home/HomeBaseController.phpfetchhandlerTemplate
主题与 Context 预热common/services/HomePublicVarsService.php
{% template %} 标签extend/liquidExtend/tags/TagTemplate.php
模板文件解析(本地 / DB)extend/liquidExtend/fileSystem/OemsaasLocal.phpOemsaasDatabase.php
前台路由app/home/route/route.php
商品控制器app/home/controller/Product.php
COD 单页商品(仅改模板)app/home/controller/codOnePageProduct.php
DIY map 分发app/home/ExceptionHandle.phpcommon/services/DiyFileService.php
默认外壳与插槽示例public/theme/default/layout/theme.liquidlayout/template.liquid

文档版本:与仓库内 codOnePageProduct 实现同步;若有路由或 path 命名调整,请同步更新本节「新路由」与 handlerPathByFileType 说明。