4.1 细胞模板 cell 与 cells

把带 PHP 逻辑的模板片段封成一个不让站长改的单元,同时留个口子让他在后台自己拼。

4.1.1 它要解决的老问题

X3.5 时代模板里 HTML 和 PHP 逻辑是混在一起的。编辑器工具栏要不要显示截图按钮、要不要显示表情面板,靠几段 {eval} 就地判断。模板作者看得懂,换个站长接手就容易改坏——多删一个右括号,整页白屏。

细胞模板就是把「HTML + 逻辑」摘成一个整体,调用方只留一行标签。打个比方:以前像把螺丝刀、电线、灯罩全敞在客厅里任人改;细胞模板是装进带盖的盒子,盒子上只留一个开关标签。

机制 逻辑能否被站长改 站长能否 DIY 组合
{subtemplate xxx} 能 不能
{template xxx} 能 能(需插件供数据)
{cell xxx} 不能 取决于调用场景
{cells xxx} 不能 能,后台可选块

4.1.2 {cell}:最小封装单元

{cell} 对应 template/{标识}/cell/ 下的文件,写法是 {cell 路径},路径不带扩展名。目录支持多级目录,可以写成 forum/list/header,对应磁盘上的 cell/forum/list/header.htm。扩展名固定 .htm。

<!-- template/你的标识/cell/common/userbar.htm -->
<ul class="userbar">
    {if $_G['uid']}
        <li><a href="home.php?mod=space&uid={$_G['uid']}" class="userbar-name">{$_G[username]}</a></li>
        <li><a href="member.php?mod=logging&action=logout" class="userbar-out">{lang logout}</a></li>
    {else /if}
    {if !$G[uid] && !$G[guestip]}
        <li><a href="member.php?mod=logging&action=login" class="userbar-in">{lang login}</a></li>
    {/if}
</ul>

调用方只写一行,放在 common/header.htm 里:

<!-- template/你的标识/common/header.htm -->
{cell common/userbar}

4.1.3 {cells}:把细胞再包一层

{cells} 对应 template/{标识}/cells/ 目录,作用是把若干 cell 再整体封装一次。cell 适合「我写代码你调用」,cells 适合「我给一组备选你挑」——站长在 DIY 面板里看到的可选块,本质上就是 cells。

文件 能写什么 用在哪
cells/xxx.htm 模板标签,可以再写 {cell} 纯展示型组合
cells/xxx.php 必须写成 class 需在渲染前准备数据

官方的 template/default/cells/ 里两种都有,论坛和门户目录下最完整,去 template/default/cells/forum/ 和 template/default/cells/portal/ 看实际写法最省事。

4.1.4 两个可复制的例子

.htm 版保存为 template/你的标识/cells/account/icons.htm,演示 cells 里嵌 cell:

<!-- template/你的标识/cells/account/icons.htm -->
<div class="account-icons">
    <ul class="icon-list">
        {loop $_G['setting']['accounticons'] $icon}
        <li class="icon-item">
            <a href="{$icon[url]}" title="{$icon[name]}" target="_blank" rel="nofollow">
                <img src="{$icon[icon]}" alt="{$icon[name]}" width="24" height="24" />
            </a>
        </li>
        {/loop}
    </ul>
</div>

.php 版保存为 template/你的标识/cells/editor/toolbar.php,必须是一个 class:

<?php
class cells_editor_toolbar {
    public $cells = ['simple', 'full'];

    public function __construct() {
        // 渲染前准备数据,可直接读写 $_G
        $this->cells = empty($this->cells) ? ['simple', 'full'] : $this->cells;
    }

    public function render() {
        $tpl = 'editor/toolbar';
        // 具体调用约定以你版本为准,先照抄 default 里的同类文件
        return $tpl;
    }
}

$_G['setting']['accounticons'] 这类数据得由调用方备好。想让细胞自己决定显示什么,就把备数据的动作写进 .php 版。

4.1.5 内置细胞与搜索方法

不用背。装一套干净的 X5.0 后直接搜这两个字符串:

grep -rn "{cells " template/default --include=*.htm
grep -rn "{cell "  template/default --include=*.htm

第一条搜 cells 调用,第二条搜 cell 调用,命中的路径就是全部内置细胞的分布图,比看文档直观。

内置细胞 调用位置 站长能否 DIY
account/icons 登录页、注册页 能,控制第三方登录图标
editor/toolbar 发帖与编辑编辑器 能,切换工具栏形态
portal 目录下多个 门户页面区块 能

登录模板里的 {cells account/icons account/icons} 是双参数写法,前一个定位 cells 文件,后一个定位内部要取的 cell;{cells editor/toolbar} 只传路径,取同名 cell。解析规则以你版本的 template/default 实际写法为准,照抄最稳。

4.1.6 从零写一对的步骤

  1. 建 cell/common/ 和 cells/common/ 目录,各放一个空 index 文件,防止 Web 服务器列出目录。
  2. 展示片段放进 cell,只用 $_G 现成数据渲染,不写库、不删表。
  3. 多个备选放进 cells 的 .htm,一个方案一段 {cell},中间用 {if} 分支。
  4. 目标模板里加 {cells common/index} 试渲染。
  5. 后台 → 界面 → 更新缓存,刷新看效果。
  6. 确认无误后,把站长改不动的逻辑收进 .php 版 class。

4.1.7 几个坑

扩展名写成 .html 或 .php。 cell 只认 .htm,写错的表现是页面空白,不是明确报错。

嵌套拉太深。 cells 套 cells 再套 cells,自己都会绕晕,最多两层。

在 cell 里用 {block}。 DIY 区块有独立作用域和导入导出机制,和细胞模板是两套并行体系,混用容易出空白框。

忘记更新缓存。 模板编译成 PHP 缓存在 data/cache/,新加的目录结构不被识别时八成是缓存问题。

给 cell 起名用中文或大写。 路径解析按 PHP 变量命名习惯走,全小写加下划线最保险。

下一节解决另一个老问题:模板作者总想给站长留几个可调参数,以前必须为此单写一个插件,X5.0 之后模板自己就够了。