模板标签全量参考

标签语法   389 次阅读   更新于 2026-10-07   发布于 2026-10-07 返回开发文档
把 {list}、{if}、{each}、{include}、过滤器、分类循环和可用函数一次说全,含可直接复制的写法。

一、先弄明白模板放在哪

前台所有页面都是 application/template/模板名/pc/*.html。后台「模板设置」切换模板,改的就是模板名。 每个模板目录里固定的东西有三样:pc/ 放页面与片段、public/pc/ 放 css/js/img、 info.php 声明模板名与广告位、set.php 声明可调参数(首页模块顺序、开关、主色)。

模板第一次访问时编译成 php 存进 application/cache/,之后按源文件的修改时间自动重编译, 改完 .html 直接刷新页面就生效,不用清缓存。缓存目录不可写只会变慢,不会报错。

随包四套模板,首页、列表页、详情页的布局各不相同,不是同一套页面换配色,共用的是同一套标签、函数与变量: laoli 资源下载站风(首页特效画布 + 卡片陈列 + 详情页左右三栏,5 个广告位)、 jian 极简导航风(顶部横向频道条 + 密集表格榜单 + 一行一类的分类目录,详情页也是一行一字段,零图片零图标,4 个广告位)、 hei 极夜终端风(频道轨道 + 各频道收录数状态条 + 首页双列卡片流,详情页主内容与侧栏两栏并排 + 等宽数字,配色全走 CSS 变量,4 个广告位)、 zazhi 纸间杂志风(居中大字刊头 + 期号行 + 发丝双线 + 频道横排,首页「本期要览」导语区 + 正文边栏双栏,列表页两栏摘要流,详情页通栏大标题带题记,宋体标题配纸色底,4 个广告位)。 四套的自适应断点都是 1024 / 768 / 560 / 400。后台「模板设置」点卡片切换,数据与子系统不用动; 每套各自带一份 pc/ 根目录的公共片段(含 sub_unlock.html 积分解锁)与样式表,新增一套就是复制目录改 info.php、set.php 和样式脚本。

读参数用 {:cmspc('键名')},后台「模板设置」里保存的同名键会加 tpl_ 前缀写进配置表并覆盖 set.php 的默认值; 开关类参数配合条件标签用,例:{if cmspc('hero_kg') eq 1}…{/if}。

二、变量怎么输出

  • {$title} —— 输出路由传给模板的变量。裸变量名必须带 $,写成 {title} 是不认的。
  • {$v.name} 或 {v.name} —— 点语法取数组元素,编译成 isset 保护后的取值,取不到输出空字符串,不会报 Notice。 点可以连着写:{$user.avatar.url}。
  • {:h(guojiz('title'))} —— {:…} 里写一句 php 表达式,结果直接 echo。函数调用、拼地址、判断都靠它。
  • 所有输出默认过 h() 转义,只有加 |raw 才原样吐 HTML。正文、广告代码、统计代码这三类才需要 |raw。

三、过滤器(跟在变量后面,用竖线,可以串)

写法 {v.addtime|date=Y-m-d H:i}。竖号后面的名字如果不是内置过滤器,会当成 php 函数调用, 所以 {v.title|mb_substr=0,6} 这类系统函数也能直接用。

过滤器作用写法
raw不加 h() 转义,原样输出 HTML正文、广告位、统计代码这类本来就是 HTML 的用它
cut=值按字数截断,默认 20,中文不会截半写成 cut=…,例 {v.title|cut=10}
date=值时间戳格式化,默认 Y-m-d写成 date=…,例 {v.title|date=10}
time转成「3 分钟前」这类相对时间写成 time,例 {v.title|time}
num强转整数写成 num,例 {v.title|num}
count数组元素个数写成 count,例 {v.title|count}
htmlstrip_tags 去掉所有标签写成 html,例 {v.title|html}
upper转大写写成 upper,例 {v.title|upper}
lower转小写写成 lower,例 {v.title|lower}
json数组转 JSON 文本写成 json,例 {v.title|json}
urlencodeURL 编码,拼查询串用写成 urlencode,例 {v.title|urlencode}
urluploads 里的文件转成可访问地址写成 url,例 {v.title|url}
default=值值为空时给一个默认值写成 default=…,例 {v.title|default=10}

串联示例:{v.intro|html|cut=30}(先去标签再截断)。

四、{list}:取数据的万能循环

{list cms open=1 cat=$sort order="view desc" num=12 page=$page as v key=k}
    <a href="{:h(arcurl('cms',$v['id']))}">{v.name|cut=30}</a>
    {v.addtime|date=Y-m-d} 浏览 {v.view|num} 第 {v.i} 条
    {empty}<div class="w-empty">这一分类还没有内容</div>{/empty}
{/list}
{page}

第一个不带等号的词是「数据源」,三种写法都行:子系统标识(cms、html、doc…)、 不带前缀的表名(content_cms)、或一个 php 变量($list)。 子系统标识就是它的表名,所以后台新建一个子系统,{list 新标识 open=1} 立刻能用,模板一行都不用改。

能写的参数

参数作用
数据源(第一个不带等号的词)子系统标识(cms/doc/…)、不带前缀的表名(content_cms)或一个 $变量,必填
as=v循环变量名,默认 v,{v.title} 里的 v 就是它;嵌套循环每层换一个别名
key=k键名变量,默认 k,配合 {v.k} 用;as/key 也能写成不带等号:as v
num=10取几条,默认 10;limit 是它的别名
order=…排序,预设词或「列名 方向」,见下一节;默认 id desc
page=$page传页码即启用偏移量,配套 {page} 出分页条;不写就一次取完
cat=5 / sort=5 / sortid=5按分类取,三个是同义词,会自动把子分类的内容一起取
id=8只取这一条
not=8 / notid=8排除这一条,相关推荐里甩掉当前文章
in=1,2,3只取这几个 ID
where=status=1,uid=2一次塞多个「列=值」,等价于分开写

条件参数(不认识的一律当列名)

条件写法含义
open=1 / show=1 / status=1只取已审核上架的(status 列)
tid=0 / pid=0按 parent_id 取,分类列表用 tid=0 拿一级
sid=5按 sort_id 取,等于直接指定分类
tui=1 / top=1精选、置顶;论坛表里叫 is_essence / is_top 会自动认别名
today=1 / day=1 / month=1 / mid=1时间窗:今天或本月入库的,认 addtime / time / create_time 任一列
dai=1待审(status=0),不用自己记 0 和 1 谁是谁
keyword=词 / ks=词 / q=词在字段配置里勾了「参与搜索」的列上 LIKE
like=词只在标题列上 LIKE(要数据源写的是子系统标识,纯表名不认)
notid=8 / not=8排除某一条,做相关推荐时甩掉自己
in=1,2,3只取这几条
ids=1,2,3不要这几条(NOT IN)
列名_min=1 / 列名_max=9数值上下限,例如 in_hits_min=1 滤掉没统计过的行
任意真实列名=值直接等值匹配;值写成数组就是 IN;表里没有这一列会被静默忽略

这些条件之外,任何「真实列名=值」都会直接拼进 WHERE;列不存在时这一条被丢弃,不报错、不过滤, 所以「明明写了却没生效」先去后台字段配置里确认列名有没有拼错。

五、排序

order= 可以写预设词,也可以写「列名 方向」,多个用逗号分隔。预设词编译时先查表里有没有这一列, 论坛这类列名不同的表会自动认别名(view → views、addtime → create_time),都没有的那段丢掉。

预设词实际排序说明
newaddtime desc,id desc', /* 最新 */最新
hotview desc,id desc', /* 热门 */热门
randrand', /* 随机 */随机
besttui desc,view desc,id desc',/* 精选 */精选
toptop desc,id desc', /* 置顶优先 */置顶优先
likelikes desc,id desc', /* 点赞最多 */点赞最多
stardj desc,view desc,id desc', /* 星级最高 */星级最高
favfavorite_count desc,view desc,id desc', /* 收藏最多 */收藏最多
scorestar desc,dj desc,score desc,view desc,id desc', /* 评分最高,各子系统这一列叫法不一,表里没有的那段自动丢掉 */评分最高,各子系统这一列叫法不一,表里没有的那段自动丢掉
dayday7 desc,view desc,id desc', /* 今日浏览最多(配合 day_time_min=今天 才是今日榜) */今日浏览最多(配合 day_time_min=今天 才是今日榜)
inin_hits desc', /* 点入最多(只有开了本站跳转的站点表里有这列) */点入最多(只有开了本站跳转的站点表里有这列)
outout_hits desc', /* 点出最多(同上) */点出最多(同上)

例:{list cms open=1 order="top desc,sort asc,id desc" num=9}。

六、{each}:循环算好的数组

{each $fav_rows as r}
    <a href="{:h(arcurl($r['sys'],$r['id']))}">{r.title|cut=24}</a> 第 {r.i} 条
{empty}还没有收藏过内容{/empty}
{/each}

路由直接传给模板的数组(收藏列表、跨表拼出来的榜单)用 {each}; 传进来的是分页对象时,{page} 照样能出分页条,还会多一个 last_page 键。

七、{if} 条件

{if v.top eq 1}<span class="w-badge">置顶</span>{elseif v.tui eq 1}精选{else}普通{/if}
{if $sort gt 0}当前分类:{$sortname}{/if}
{:form_field()}{:form_trap()}

比较词只在这两个标签里转换:eq = 、neq != 、gt > 、egt >= 、 lt < 、elt <= 、heq === 、nheq !==。 注意:这些词只在 {if}/{elseif} 里转换,写在 {:…} 里不生效, 那里请直接写 php 的 !==、>。

点语法在条件里同样可用:{if v.top eq 1}、{if count(sortlist($sys,$tp['id'])) gt 0}。 {else} 与 {else /} 两种写法都认。

八、{include}、{page}、{php}、注释

  • {include head} 引入 pc/head.html,和当前页共享变量;片段可以放子目录:{include daohang/card}。
  • {include user/peer_list} 同理,用户中心的片段在 pc/user/ 下。
  • 插件自带的模板片段用 {include @plugin/插件目录名},解析到 application/plugin/插件/pc/名.html。
  • 片段不存在时整句静默跳过,不会报错也不会留空壳,所以模板可以靠可选片段做加法。
  • 但也正因为不报错,每套模板都得自己带一份 pc/sub_unlock.html(积分解锁区块,laoli、jian、hei、zazhi 各有一份,类名前缀不同); 新复制一套模板时忘了它,后台扣积分照扣,前台却看不到解锁入口。页面顶部自己放了「直达」按钮的,在引它之前写 {php $ul_nodown=1;},片段里的解锁下载地址那条就不出,隐藏内容那条照出。
  • 片段名每段只允许字母数字下划线中划线(最长 40),别用中文和斜杠穿越。
  • {page} 输出上一条带 page= 的 {list} 的分页条,地址自己带 ?page=N。
  • {php $a=1} 塞一小段 php(给片段准备数组、算个计数),里面不能再出现右花括号,多行 php 请拆成函数调用。
  • 注释写成花括号里放 星号斜杠 内容 星号斜杠 的形式,编译时整段删掉,不会输出到浏览器。

九、分类循环的三种写法

分类都存在同一张 sort 表里,按 sys 区分,parent_id=0 是一级; 内容表用 sort_id 挂到分类上。取分类有三种姿势,按页面要的效果选。

写法一:只列一级分类

{list category sys=$sys tid=0 order="sort asc,id asc" num=50 as ct}
    <a href="{:h(sorturl($sys,$ct['id']))}">{ct.name}</a>
{/list}

同一件事也能写成 php:{php $tops = sortlist($sys);} 然后 {each $tops as c}。

写法二:一级带二级,嵌套循环

外层取一级,内层用 tid=$tp.id 取它的二级。每层必须起不同的 as 别名, 判空用 sortlist() 再数一遍,比在内层套 {empty} 稳。

{list category sys=$sys tid=0 order="sort asc,id asc" num=50 as tp}
<div class="cat">
    <h3><a href="{:h(sorturl($sys,$tp['id']))}">{tp.name}</a></h3>
    {if count(sortlist($sys,$tp['id'])) gt 0}
        {list category tid=$tp.id sys=$sys status=1 order="sort asc,id asc" num=20 as sc}
            <a href="{:h(sorturl($sys,$sc['id']))}">{sc.name}</a>
        {/list}
    {/if}
    {list $sys open=1 cat=$tp.id order="sort asc,id desc" num=8 as cs}
        <a href="{:h(arcurl($sys,$cs['id']))}">{cs.title|cut=20}</a>
    {/list}
</div>
{/list}

写法三:混合 —— 把子分类的内容折进一级里

不想嵌套就别嵌套:cat=一级ID 会自动把这一级下面所有子分类的内容一起取出来, 这是最常用的写法,列表页顶部的「本页共 N 条」也是这么统计的。

{* 只要一个列表,把整棵子树的内容混在一起按时间排 *}{list $sys open=1 cat=$sort order='new' num=$per page=$page as v}
    <a href="{:h(arcurl($sys,$v['id']))}">{v.title|cut=24}</a>
{/list}
{page}

cat= 换成 tid= 就变成「只取直接挂在这一级下的内容」,两者的区别就在子分类的内容要不要混进来。 分页统计条数用的 funnum($sys,['open'=>1],['cat'=>$sort]) 也是同一套规则。

相关函数:sortlist($sys,$tid=0) 取某级的子分类数组、sort_children($sys,$id)、 sortname($sys,$id) 直接拿名字、func('category',$id) 拿一整行分类。

十、常用函数(写在 {:…} 或 {php} 里)

下面按源码里的小节顺序列出 application/inc/fun.php 的全部函数,模板里最常碰的是取数据、地址、字段和在线工具四组; 最后两组 按字段配置取值、摘要·地址与详情区块 来自 application/inc/common.php, 同样是模板在调的函数,只是和路由放在同一个文件里。

基础(13 个)

函数作用
h($v)HTML 转义,模板里所有默认输出都走它
get($k,$d='')取 GPC 参数
post($k,$d='')取 POST 参数,字符串自动 trim
gpc($k,$d='')取全部请求参数(含 GET/POST)
cookie($k,$v=null,$exp=0)cookie 读写:cookie('sn') 读,cookie('sn','x',3600) 写
siteurl($path='')站点根地址:后台「站点网址」→ config.php 的 url → 按当前请求自动推导,保证不为空
url($path='')siteurl 的短别名,模板里写 url('xxx') 也能拿到站点绝对地址
tpl($p='')模板资源地址:tpl($p) 拼出本模板 public/pc 下的文件地址
upurl($p)上传文件地址
cut($str,$len=20,$dot='…')中文安全截断
time_ago($ts)时间戳转「3 分钟前」这类相对时间,空值返回 —
num_ago($n)数字缩写:12800 → 1.28万
size_fnum($b)字节数转可读大小:1536 → 1.50 KB

配置(5 个)

函数作用
config($k=null,$d='')数据库配置(application/config.php)
guojiz($k=null,$d='')站点设置:guojiz('title')。不传参数返回全部
cmspc($k=null,$d='')模板设置:cmspc('ys1'),站点设置里 tpl_ 前缀的键可覆盖模板默认值
cmsinfo($k=null,$d='')模板信息文件(名称/作者/版本)
tpl_css()把模板配色生成 CSS 变量

页面 SEO(4 个)

函数作用
seo_set($k,$v)路由或页面自己设置当前页的 title / keywords / description
seo_title()当前页 seo 标题:页面标题在前,站点名在后
seo_keywords()当前页 seo 关键词,页面没设就回落站点设置
seo_description()当前页 seo 描述,页面没设就回落站点设置

子系统与字段(11 个)

函数作用
sys_all($force=false)全部子系统配置(sys 标识与 url 别名都能取到)
sys_get($sys)子系统配置
sys_name($sys)子系统中文名,查不到就原样返回标识
sys_builtin($sys=null)内置功能占用的子系统标识:程序自带页面与后台菜单,不在「子系统管理」里当栏目列出来
sys_own($sys=null)数据表和页面都由程序自带的子系统(论坛):在子系统管理里能改名字、地址、开关和每页条数, 但没有字段配置,内容也不走通用内容页,走它自己的菜单。 /
sys_on($sys)子系统开没开。sys_all() 只缓存 status=1 的行,分不出「登记过但停用」和「压根没登记」, 所以这里直接查库:停用返回 false,没登记过按 true 算(老库升级前后的行为要一致)。 /
fields($sys,$force=false)子系统字段配置
field($sys,$field)取单个字段的配置行,没有该字段返回空数组
field_label($sys,$field,$d='')字段标签
table_of($src)表名解析:category/sort → 分类表;nav/user/… → 同名表;子系统标识 → 内容表
columns($table)表的列清单

取数据(核心)(12 个)

函数作用
funa($src,$arg=[],$order='iddesc',$limit=10,$page=0)通用列表:funa('rj', array('open'=>1), 'id desc', 10, 1) @param string $src 子系统标识 / 表标识(category、nav、html…) @param array $arg 条件数组,键就是表里的列名,数组值自动转 IN @param string $order 排序,如 id desc / view desc / rand @param int $limit 每页条数 @param int $page 页码;传 0 只返回数组,传 >=1 返回可 ->render() 的分页对象 /
cond_of($src,$arg=[])条件解析:把 funa 的 $arg 编译成 where + 绑定参数 返回 ['table','cols','where'=>[...],'bind'=>[...]] /
funb($src,$arg=[],$sortid=0,$order='iddesc',$limit=10,$page=0)按分类取列表:funb('html', array('open'=>1), $v['id'], 'id desc', 8, 1) 自动带上该分类的子分类 /
func($src,$id)单条:func('html', $id)
funone($src,$arg=[],$order='iddesc')按条件取单条:funone('html', array('id'=>1))
funnum($src,$arg=[])条数:funnum('html', array('open'=>1))
funtj($src,$what='all')统计:每个子系统同一句函数,表里缺哪一列就自动退成能算的那个,不报错。 funtj('html','all') 总数量(含待审的) funtj('html','open') 已收录数量(站点数、软件数…) funtj('html','wait') 待审数量 funtj('html','today') 今天入库数量 funtj('html','month') 这个月入库数量 funtj('html','cat') 分类数量 模板里这样用:{:funtj('html','today')} /
key_col($cols)表的主键列:多数表是 id,会员表是 uid,收藏一类的可能是 item_id
time_col($cols)这张表用哪个列记入库时间(新老表列名不一样,认不出来就不按时间筛)
order_preset($order)排序预设:模板里写 order=hot / new / rand / best 就够了,不用记列名。 表里没有对应列时 order_sql 会把这些丢掉,最后退回主键倒序,不会报错。 /
order_alias($col,$cols)同一层意思的列各张表叫法不同(论坛用 views/create_time/is_top),排序时按别名退一步认
order_sql($order,$cols)排序白名单

分类(9 个)

函数作用
sortlist($sys='',$tid=0)分类列表(含子分类)
sortname($sys,$id)分类名
sort_children($sys,$id)子分类 ID 列表
sorturl($sys,$sort=0)分类地址
arcurl($sys,$id)内容地址
listurl($sys,$sort=0,$order='')列表页地址(可以带排序):/频道/ 是版式完全不同的频道首页,全部内容的列表页是 /频道/page-1/, 分类列表页才是 /频道/分类ID/。排序短名在这里写成 ?order=out 这种,带下划线的列名用短名才不会串。 /
sys_url($sys)子系统 url 别名
rankurl($sys='',$by='',$page=0)排行榜地址:不带子系统就是全站聚合榜,带了就是这一个子系统自己的榜。 榜型用旧站那套短名(view/day/month/new/in/out/like/fav/star/tui/hot/rand)。 /
pageurl($page='{page}')分页地址 pageurl() → 模板用的地址样式(含 {page} 占位) pageurl(3) → 第 3 页的真实地址 带查询串(搜索词、筛选条件)时自动保留,用 ?page=N 的形式 /

其它通用(7 个)

函数作用
ad_slots($dir='')这套模板自带的广告位:读模板 info.php 里的 ads(位置标识 => 位置名称)。 位置由模板自己声明,程序不内置任何位置:换一套模板就是另一套位置。 /
ad_on($slot)广告位开关:模板设置里可以逐个位置关掉,键名 ad_<位置标识>,默认开着
ad($id)广告位:ad('top') 返回当前模板这个位置全部启用广告的 html;模板没声明这个位置就不出东西
nav($tid=0)导航:nav() 返回顶级导航及其子项
nav_url($u)导航链接地址:外部网址原样,站内路径补上站点根
nav_menu($rows=null)顶部「更多」下拉:直接吃后台「导航菜单」里的数据,有子项的渲染成子下拉 模板里一句 {:nav_menu()} 就出全部,导航表为空时返回空字符串 /
links($limit=30)友情链接

首页模块(顺序与开关在模板设置里)(20 个)

函数作用
home_list()首页三栏模块清单:模板 set.php 的 home_modules 提供样式,home_order 决定顺序 后台可用站点设置里的 tpl_home_order 覆盖顺序;没排到但开关开着的子系统追加到末尾 /
home_modules()首页各子系统三栏模块 html(模板里一句 {:home_modules()} 就按后台顺序输出)
home_side()左侧悬浮锚点里跟随首页模块顺序的那一段
dingyi($sn=0,$d=0)站群标识(单站固定返回默认值)
myuser($k=null,$d='')当前登录会员:myuser() 取整行,myuser('nickname') 取某个字段
islogin()前台是否已登录会员(后台登录不算)
isadmin()是否管理员(前台判断)
json_get($v,$d=[])JSON 读取
imgs($v,$limit=0)图片列表字段(截图/多图)
tags($v,$sys='',$sep='')标签
pv_track()访问统计:每渲染一个前台页面算一次 PV,同一 IP 当天第一次算 UV。 数据存在 visit 表(day/pv/uv/ips),后台「数据统计」用它画柱状图。 /
report_mail()联系/举报邮箱:后台没填邮箱时用 QQ 号拼 qq.com
out_domain($url)外链的域名:out_domain('https://www.a.com/x') → www.a.com
tag_words($sys,$row,$limit=30)一条内容的关键词/标签词组(读该子系统所有 tags 类型字段,兼容 gjz/keywords/tags)
star_html($v,$show_num=true)星级显示:0-5 渲染成五颗星(前台列表与详情共用)
tag_plain($sys,$row,$sep='')关键词标签(详情页用的小圆角 chip)
tag_cloud($sys,$row,$num=20)3D 标签云的 a 标签:词不足时用同分类内容标题补齐
is_collected($sys,$id,$uid=0)是否已收藏(会员)
collect_num($sys,$id)收藏数
breadcrumb($sys,$sort=0)面包屑

在线工具(10 个)

函数作用
tool_type_of($sys,$row)在线工具的打开方式(其他子系统返回空串)
tool_code_plain($row)代码类型是不是「纯文本」(兼容旧站的 html / text)
tool_dir()本地工具文件放哪个目录:后台上传、贴代码保存、前台执行都只认这一个目录
tool_file_name($raw)字段里的写法五花八门(jiami.php、tool/jiami.php、uploads/tool/jiami.php、完整网址、旧站 /public/tool/jiami.php), 一律只取最后的文件名,文件名里的非法字符和不认识的扩展名直接判空,杜绝越出 uploads/tool 目录 /
tool_file_of($sys,$row)这条工具要用哪个本地文件:先看「本地工具文件」,没填再退回旧站留在「工具地址」里的路径
tool_file_path($sys,$row)本地工具文件的绝对路径;文件不存在或不在这个目录里返回空串
tool_local_url($sys,$row)本地工具文件的网址:站外 iframe 调用这一份也用得上
tool_local($sys,$row)本地文件型工具的运行区:php 就 include 出来,html 就整份读出来原样显示。 文件不在的时候不报错,给出该怎么补的说明,和旧站的内页一个意思。 /
tool_embed($sys,$row)内嵌网页型工具的 iframe;zg 是容器高度,di 是把被嵌页面自己的页头顶出去的高度
tool_target($sys,$row)直达按钮的打开方式:内嵌、本地文件和自有代码都留在本页,跳转链接开新窗口

模板取数据({list} 标签调用)(4 个)

函数作用
data($src,$where=[],$order='iddesc',$num=10,$page=0)取数据({list} 的底层):返回行数组;传了 page 则返回分页对象
datacat($src,$cat=0,$where=[],$order='iddesc',$num=10,$page=0)按分类取数据({list} 里写 cat=分类ID)
datacol($src,$field,$arg=[],$limit=30)按字段聚合取值分布:datacol('gzh','suoshudiqu',['open'=>1]) 返回 [['value'=>'四川','num'=>3],…],按数量从多到少。字段不在这张表里就返回空数组,模板不会报错。 用于地区、来源这类「不是分类但想筛选」的字段,配合 {list … 字段=$var} 用。 /
page_bar($page=null,$cls='daishen-pagination')分页条 html:{page} 用默认样式,需要换样式时 {:page_bar(null,'sousuo-pagination')}

按字段配置取值(9 个,在 application/inc/common.php 里)

函数作用
title_field($sys)标题字段(由字段配置决定,旧站多为 name)
cover_field($sys)—
body_field($sys)—
title_of($sys,$row)模板里按配置取标题/封面/正文,不需要知道每个子系统的字段名
cover_of($sys,$row)—
body_of($sys,$row)—
view_of($sys,$row)浏览数和时间:各张表叫法不一样(论坛是 views/create_time),模板里统一用这两个函数取, 免得每套模板各自写 {mi.view} 在新子系统上取到空值。 /
time_of($sys,$row)—
body_html($sys,$row)正文输出:字段配了「代码类型=纯文本」时转义并保留换行,富文本按原样输出。 没有正文就回空串,模板自己决定显示介绍。 /

摘要·地址与详情区块(11 个,在 application/inc/common.php 里)

函数作用
intro_of($sys,$row,$len=60)摘要:优先 introduce/description,没有就截正文
url_of($sys,$row)内容页地址
out_of($sys,$row)跳转地址:外链字段优先,没有就用内容页
near_row($sys,$id,$way='prev')上一篇 / 下一篇
like_rows($sys,$row,$limit=8)相关推荐:同分类优先,不足再补热门
views_days()七天趋势的列名:day1 是最早一天,day7 是今天
views_seven($table,$id,$row,$track=false)详情页取七天浏览趋势;$track 为真时顺手把这一笔浏览写进库。 记账规则:同一天只加 day7;跨天先把旧数据整体往前挪,中间断掉的天补 0,今天记 1。 老库没这几列时只返回空,模板里的趋势区块自然就不出。 /
trend_csv($trend,$key)趋势数据给模板用的逗号串(没数据时返回空串,模板据此隐藏区块)
field_html($sys,$row,$except=[])详情页字段渲染:按字段配置输出「标签:值」列表
lock_out_col($sys,$row,$field)这条内容开了扣积分又没解锁时,地址类字段不给真地址
cell_html($sys,$row,$field)列表单元格:按字段配置输出(通用列表模板用),第三个参数可传列名或整行字段配置

在线工具内页的写法

「在线工具」子系统(标识 gongju)的一条工具有四种打开方式,后台填的「打开方式」存在 tool_type 字段, 模板里别自己比对字符串,用 tool_type_of($sys,$v) 取(旧站导入的 0/1/2 也会认回中文标签)。 内页要显示的三种区块:{:tool_embed($sys,$v)} 出内嵌网页的 iframe(高度取 zg、顶部偏移取 di,自带全屏按钮), {:tool_local($sys,$v)} 执行 uploads/tool/ 里的本地工具文件(php 就 include、html 就整份输出, 都包在 .tool-local-run 里;文件不在时输出「怎么补」的提示而不是报错), 自有代码直接把正文字段 {:body_html($sys,$v)} 打出来(纯文本会自动转义并保留换行)。 三个函数返回的都是真标签,模板里必须写成 {:…} 或者给变量加 |raw, 写成 {$var} 会被转义成一段文本,工具就跑不起来。

十一、换个子系统也照用的写法

详情页兜底模板 view.html 全程不写死列名,字段由后台「字段配置」驱动:

{list fields sys=$sys in_detail=1 is_title=0 is_cover=0 is_body=0 order="sort asc,id asc" num=40 as fi}
    <li><span>{fi.label}</span>{:cell_html($sys,$v,$fi)}</li>
{/list}

于是「新建一个子系统 → 配字段 → 传模板」这条路不用改一行模板代码:tpl_list / tpl_detail 在后台子系统设置里指定版式名,没指定就回落到 lists.html / view.html。

取字段值用 field_html($sys,$row,数组)(输出 li 列表)与 cell_html($sys,$row,$字段行)(输出单个值), 图片/图集字段自动拼 upurl(),链接字段自动带 target=_blank,其余一律转义。

十二、几条踩过的坑

  • {list} / {each} 的标签头里不能出现尖括号、花括号和换行,属性值里有这些字符会被切断匹配。
  • 嵌套循环最多展开 80 层,正常页面碰不到;真的套了这么多层,说明该用函数先算好数组。
  • 循环别名会临时覆盖同名变量,循环结束后自动还原,所以详情页的 $v 不会被 as v 顶掉。
  • 条件里的 eq 只认比较词,别写 {if $a = 1};带等号的 php 赋值不是条件。
  • 列表页分页只认 page= 参数:忘了写就没有 {page},也不会报错。
  • 想要「今日热门」用 order=day 配合 day_time_min=今天零点,只写 order=day 拿到的是七天浏览量榜。
按这篇做完还是卡住,可以把报错截图发到反馈论坛,作者会补充说明。 去发帖提问 或发邮件