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 从零写一对的步骤
- 建
cell/common/和cells/common/目录,各放一个空index文件,防止 Web 服务器列出目录。 - 展示片段放进 cell,只用
$_G现成数据渲染,不写库、不删表。 - 多个备选放进 cells 的
.htm,一个方案一段{cell},中间用{if}分支。 - 目标模板里加
{cells common/index}试渲染。 - 后台 → 界面 → 更新缓存,刷新看效果。
- 确认无误后,把站长改不动的逻辑收进
.php版 class。
4.1.7 几个坑
扩展名写成 .html 或 .php。 cell 只认 .htm,写错的表现是页面空白,不是明确报错。
嵌套拉太深。 cells 套 cells 再套 cells,自己都会绕晕,最多两层。
在 cell 里用 {block}。 DIY 区块有独立作用域和导入导出机制,和细胞模板是两套并行体系,混用容易出空白框。
忘记更新缓存。 模板编译成 PHP 缓存在 data/cache/,新加的目录结构不被识别时八成是缓存问题。
给 cell 起名用中文或大写。 路径解析按 PHP 变量命名习惯走,全小写加下划线最保险。
下一节解决另一个老问题:模板作者总想给站长留几个可调参数,以前必须为此单写一个插件,X5.0 之后模板自己就够了。
