ZsAdmin「智数」BBS社区插件 前端模板标签文档
【总结】本文详细介绍了ZsAdmin「智数」BBS社区插件的前端模板标签使用规范,包括基础输出、布局片段、条件循环、过滤器、助手函数、JSON输出等核心功能,重点强调了模板语法常见坑与解决方案,如避免未转义花括号、慎用raw过滤器等,
本站前台(社区插件等)使用 ThinkPHP 模板引擎(think-template)。模板目录主要在:
plugins/community/view/front/- 主题覆盖:
themes//community/(若启用)
编译缓存:runtime/temp/。改模板后若异常,可清缓存或后台「清理缓存」。
1. 基础输出
| 写法 | 说明 |
|---|---|
{$name} | 输出变量(自动转义 HTML) |
{$user.nickname} | 数组 / 对象属性 |
{$a.b.c} | 多级属性 |
| `{$name\ | raw}` |
| `{$title\ | default='未命名'}` |
| `{$n\ | default=0}` |
{$compose_title|default='发布新帖'}
{$topic.content|raw}函数调用输出
{:community_url('topic', ['id' => $item.id])}
{:hook_slot('plaza_feed_top')}{: ... } 内写 PHP 表达式,返回值直接输出。
2. 布局与片段
继承布局
{extend name="layout" /}
{block name="title"}页面标题{/block}
{block name="css"}...{/block}
{block name="content"}...{/block}
{block name="js"}...{/block}引入片段
{include file="_plaza_left" /}
{include file="_captcha_field" /}相对当前 view/front/;以下划线 _ 开头的一般为局部片段。
3. 条件与循环
if / else / elseif
{if $edit_mode}
编辑
{elseif !empty($lock_compose_type)}
锁定类型
{else /}
新建
{/if}注意:else / elseif 后常带空格与 /,写成 {else /}、{elseif ...}。
{if ($edit_mode && $topic.category_id==$c.id) || (!$edit_mode && $pre_category_id==$c.id)}on{/if}空判断
{empty name="replies"}暂无回复{/empty}
{notempty name="user"}已登录{/notempty}volist(推荐列表)
{volist name="categories" id="c"}
{$c.name}
{/volist}| 属性 | 说明 |
|---|---|
name | 数据集变量名 |
id | 循环项变量 |
key | 可选,下标变量名 |
offset / length | 可选切片 |
foreach
{foreach $list as $key => $item}
{$key}: {$item.title}
{/foreach}4. 修饰符(过滤器)
常用:
| 修饰符 | 示例 | 说明 |
|---|---|---|
default | `{$x\ | default=''}` |
raw | `{$json\ | raw}` |
date | `{$time\ | date='Y-m-d'}` |
可串联:{$html|default=''|raw}(慎用;raw 一般放最后)。
5. 本站助手函数
在模板里用 {:函数名(...)} 调用。定义位置见括号。
路由 / 链接
| 函数 | 定义 | 用法 |
|---|---|---|
community_url | plugins/community/helpers.php | {:community_url('topic', ['id' => $id])} |
message_url | 同上 / message 插件 | {:messageurl('messagesend')} |
payment_url | payment 插件 | {:payment_url('recharge')} |
community_url 常用路由名(可被后台「路由」配置改写):
| 名称 | 默认路径含义 |
|---|---|
plaza | 广场首页 |
boards | 版块列表 |
category | 版块 ['id'=>…] |
topic | 帖子详情 ['id'=>…] |
topic_create | 发帖 ['type'=>'article'] |
topic_edit | 编辑 ['id'=>…] |
topic_save | 保存(POST) |
articles / questions / topics … | 各内容模型聚合页 |
member / login / register | 会员与登录 |
page | 单页 ['slug'=>…] |
tag | 标签 ['id'=>…] |
user | 主页 ['type'=>'user','id'=>…] |
插槽 / 资源
| 函数 | 定义 | 说明 |
|---|---|---|
hook_slot | app/common.php | 插件插槽 HTML |
plugin_assets | 同上 | 已装插件的前台 CSS/JS |
{:hook_slot('compose_body', ['content' => '', 'required' => true])}
{:hook_slot('compose_extra', ['edit_mode' => false, 'topic_id' => 0])}
{:plugin_assets()}常见插槽名:composebody、composeextra、composeassets、plazafeedtop、topicauthorbadges、afteruser_level 等(由各插件注册)。
UI 组件
| 函数 | 说明 |
|---|---|
ucavatarhtml([...]) | 头像 + 等级环/角标 |
levelprogresshtml($progress) | 等级进度条 |
communitycaticon_html($icon) | 版块 Remix(Remix 或图片) |
communitymediaurl($url) | 媒体 URL 规范化 |
adsboot / adsafter_section | 广告位(未装 ads 插件时返回空) |
头像示例:
{:uc_avatar_html([
'src' => $author.avatar,
'color' => $author.user_level_color,
'badge' => $author.user_level_badge,
'size' => 'sm',
'href' => $author.profile_url,
'alt' => $author.nickname
])}size:xs / sm / md / lg / xl。
货币文案
| 函数 | 说明 |
|---|---|
paymentcoinname() | 积分名 |
paymentgoldname() | 金币名 |
paymentcurrencylabel($c) | 按币种返回文案 |
模板里也常用控制器下发的 {$coinname}、{$goldname}。
6. 在模板里输出 JSON 给 JS
推荐(控制器已保证有值):
try {
var map = JSON.parse('{$model_fields_map_json|raw}') || {};
} catch (e) {
var map = {};
}
对象字面量直接嵌入(已是合法 JS):
guangyaDirect: {$guangya_direct_json|raw},控制器侧请用 jsonencode(..., JSONUNESCAPEDUNICODE | JSONHEXTAG | JSONHEXAPOS | JSONHEXQUOT | JSONHEX_AMP),避免 XSS。
7. 重要坑(必读)
7.1 标签内禁止未转义的 }
ThinkPHP 用 { } 定界。标签内容里再出现 } 会被当成标签结束,轻则编译失败,重则整页 HTTP 500。
错误(曾导致发帖页登录后 500):
{$model_fields_map_json|default="{}"|raw}解析到 default="{}" 的 } 即截断,报错类似:Unclosed '(' does not match '}'。
正确:
{$model_fields_map_json|raw}或默认值不要含花括号:
{$x|default='[]'|raw}
{$x|default=''}同理避免:
{if $a == "{}"}...{/if}
{$color|default='#64748b'} 颜色类默认值本站已在用 default='#64748b';若遇解析问题,改为控制器赋默认值再 {$color}。
7.2 {: } 里尽量简单
复杂三元、嵌套括号可放到控制器或助手函数,模板只调用:
{:hook_slot('compose_extra', ['topic_id' => !empty($a) ? (int)(is_object($t) ? ($t->id ?? 0) : 0) : 0])}
{:hook_slot('compose_extra', ['edit_mode' => !empty($edit_mode), 'topic_id' => (int)$compose_topic_id])}7.3 |raw 只用于可信内容
用户正文须先经 HtmlSanitizer 等净化,再 |raw。未知字符串一律默认转义输出。
7.4 未登录与已登录路径不同
部分页面未登录会 redirect,不渲染模板;登录后才编译模板。因此「只有登录后 500」往往是模板语法问题,而不是权限逻辑。
7.5 改模板后清缓存
php think clear或删除 runtime/temp/ 下相关编译文件。生产环境若存在 runtime/config.php 且含其它机器绝对路径,也需清理后重新生成。
8. 原生 PHP 片段(少用)
{php}
$ptCount = isset($post_types) ? count($post_types) : 1;
{/php}仅用于布局里临时兼容变量;新代码优先在控制器 View::assign。
9. 自定义模型发帖页约定
发帖页 create.html 关键变量(控制器 Index::create / edit):
| 变量 | 含义 |
|---|---|
$edit_mode | 是否编辑 |
$compose_type | 内容模型:discussion / article / … |
$lockcomposetype | 锁定模型(URL ?type= 或编辑时) |
$categories | 可选版块列表 |
$modelfieldsmap_json | 自定义字段定义 JSON |
$topiccustomvalues_json | 编辑时字段值 JSON |
$typetitlesjson / $typeleadsjson | 切换版块时标题文案 |
模型专属模板:后台可配 createtemplate*,解析为 create/.html(如 create/blank.html)。
10. 速查对照
{$var} {$a.b} {$var|default=''} {$html|raw} {:func()}
{extend name="layout" /}
{block name="content"}...{/block}
{include file="_partial" /}
{if}{elseif}{else /}{/if}
{volist name="list" id="item"}{/volist}
{empty name="list"}{/empty}
{:community_url('topic', ['id' => $id])}
{:hook_slot('slot_name', [...])}
{:uc_avatar_html([...])}
{:community_cat_icon_html($c.icon)}11. 相关文件
| 路径 | 内容 |
|---|---|
app/common.php | hookslot、ucavatarhtml、pluginassets |
plugins/community/helpers.php | community_url 等社区助手 |
plugins/community/view/front/layout.html | 前台主布局 |
plugins/community/view/front/create.html | 发帖页(含 JSON 输出范例) |
plugins/community/service/FrontRoute.php | 路由名与默认 path |
vendor/topthink/think-template/ | 引擎源码与官方能力 |
官方手册:ThinkPHP 模板引擎
微信客服
QQ官方交流群