ThinkWo 开发文档DOCS v1.0.45
快速开始
文档首页 / 模板开发 / 标签与函数

标签与函数

前台模板只用 12 个标签 + 16 个全局函数就能拼出任何页面。这一页是完整参数手册,建议直接搜关键词。

一、标签写法规则

格式:{tw:标签名 属性="值"} … {/tw:标签名},不闭合的标签(如 {tw:seo /})直接自闭合。

属性值有三种写法,决定它怎么被解析:

写法示例含义
普通字符串limit="12"原样当字符串/数字用
以 $ 开头parent="$sort.id"当 PHP 变量用,取当前作用域的值
以 : 开头:limit="$page['limit']"当 PHP 表达式原样执行
属性值里有引号怎么办

外层用双引号时,里面写单引号:order="'id desc'"。不要套双引号,模板解析会断。

二、nav — 栏目导航

闭合标签

{tw:nav parent="0" limit="8" alias="nav" key="k"}
  <a class="nav-link {if $nav.active}is-active{/if}" href="{$nav.url}"{$nav.target|raw}>{$nav.name}</a>
{/tw:nav}
属性默认说明
parent0父栏目 ID。0 = 一级栏目;5 = ID 为 5 的子栏目;$sort.id = 当前栏目的子栏目
limit0(不限)最多取几条
aliasnav循环变量名,如填 item 就用 $item.name
keykey索引变量名

循环里可用的字段

字段说明
$nav.id栏目 ID
$nav.name / $nav.subname名称 / 副标题
$nav.url已生成好的链接(外链栏目自动用外链地址)
$nav.target外链栏目的 target="_blank" rel="noopener",输出时加 |raw
$nav.active是否当前栏目(1/0),做导航高亮
$nav.son子栏目数量,大于 0 才渲染下拉箭头
$nav.ico / $nav.pic栏目缩略图 / 栏目大图
$nav.typelist 列表 / page 单页 / link 外链

二级下拉菜单(默认主题的写法)

{tw:nav parent="0" limit="9"}
  <div class="nav-item">
    <a class="nav-link {if $nav.active}is-active{/if}" href="{$nav.url}"{$nav.target|raw}>{$nav.name}</a>
    {if $nav.son}
      <div class="nav-sub">
        {tw:nav parent="$nav.id" alias="sub" limit="12"}
          <a href="{$sub.url}">{$sub.name}</a>
        {/tw:nav}
      </div>
    {/if}
  </div>
{/tw:nav}

三、list — 内容列表

闭合标签 · 自带分页

{tw:list sort="12" limit="9" page="$tw_page" order="publish_time desc"}
  <article>
    <a href="{$list.url}"><img src="{$list.ico}" alt="{$list.title}"></a>
    <h3><a href="{$list.url}">{$list.title}</a></h3>
    <p>{$list.summary|substr=0,80}</p>
    <time>{$list.date}</time>
  </article>
{/tw:list}

{tw:pagination /}
属性默认说明
sort当前栏目"*" 全站;"12" 栏目 ID(自动包含子栏目);"products" 按 slug(只取该栏目);不写 = 当前栏目
limit12每页条数
page自动页码。列表页要显式传 page="$tw_page" 才会分页
orderpublish_time desc, id desc只允许 publish_time、id、views、sort、price,其他字段会被忽略(防注入)
attr空按推荐属性过滤:recommend / hot / new
tags空按标签过滤,如 tags="cnc"
keyword空关键词搜索(标题/摘要/标签)
exclude空排除的 ID,如 exclude="$content.id" 或 exclude="3,5,8"
alias / keylist / key循环变量名 / 索引名

循环里可用的字段

id、title、subtitle、summary、url、ico(已自动转 WebP)、date(如 Oct 30, 2026)、datetime(如 2026-10-30,给 <time datetime=""> 用)、views、price、unit、model_no、moq、attr、tags、sort_name、sort_url、sort_slug

栏目自定义字段也在循环里(v1.0.44 起)

栏目定义过自定义字段后,值存在内容的 meta 列(JSON),标签已经自动解析好,三种取法: {$list.字段键} 取单项(如 {$list.badge})、{$list.meta} 取原文、{$list.cf} 取解析后的数组。 遍历全部字段必须用 {foreach name="list.cf" item="v" key="k"}——{volist} 的 key 给的是序号 1/2/3,不是字段键。详见 栏目自定义字段。

标签会自动生成两个变量

变量内容
$page分页信息:current、last、limit、total、has_prev、has_next;不分页时为 null
$total符合条件的总条数
$page 是保留变量名

模板里别再自己起名叫 $page,会被覆盖。自己的分页参数用 $tw_page(列表页控制器已赋好这个值)。

四、attr — 推荐位内容

闭合标签

{tw:attr name="recommend" limit="8" sort="*"}
  {include file="comm/product-card" /}
{/tw:attr}
属性默认说明
namerecommend对应内容表 attr 字段:recommend 推荐 / hot 热门 / new 最新。可组合 "recommend,hot"
limit6条数
sort*限定栏目,写法同 {tw:list}
aliaslist循环变量名(和 list 一致,方便共用卡片片段)

五、sort — 栏目信息

自闭合

{tw:sort /}
<h1>{$sort.name}</h1>
<p>{$sort.description}</p>

{* 取指定栏目:alias 换个名避免覆盖当前 $sort *}
{tw:sort id="6" alias="about" /}
<h2>{$about.name}</h2>
属性默认说明
id0栏目 ID,不写取当前栏目
aliassort赋值变量名

六、content — 内容详情

自闭合

<h1>{$content.title}</h1>
<div class="body">{$content.content|html_entity_decode|raw}</div>

{* 取指定 ID 的内容 *}
{tw:content id="18" alias="news" /}
<h3>{$news.title}</h3>
属性默认说明
id0内容 ID,不写取当前内容
aliascontent赋值变量名
auto1为 1 时自动补全 url / images / tag_list

七、position — 面包屑

{tw:position /}                    {* 默认分隔符 " / " *}
{tw:position separator=" > " /}    {* 自定义分隔符 *}

输出的是完整 HTML:<nav class="tw-crumb">首页 / 产品中心 / 某某产品</nav>,最后一项自动变成 aria-current="page" 且不带链接。

八、pagination — 分页条

{tw:list sort="*" limit="12" page="$tw_page"}
  ...
{/tw:list}

{tw:pagination /}            {* 默认左右各 2 个页码 *}
{tw:pagination range="3" /}  {* 左右各 3 个 *}

输出 <nav class="tw-pager"> 结构,含 rel="prev" / rel="next"(对 SEO 有用);只有一页时不输出任何内容。

九、lang — 语言切换

<div class="lang-list">
  {tw:lang alias="item"}
    <a href="{$item.url}" class="{if $item.active}is-active{/if}">{$item.name}</a>
  {/tw:lang}
</div>

循环字段:code(如 zh-cn)、name(语言本名)、region、url(当前页面的对应语言地址,不是首页)、active。

切换语言会跳到"同一篇内容"

靠内容表的 trans_key 字段配对:两个语言的同一条内容填同一个 trans_key,切换时就跳对应版本;没配对则回落到该语言首页。

十、currency — 货币切换

闭合标签

<div class="cur-list">
  {tw:currency alias="cur"}
    <a href="javascript:;" data-cur="{$cur.code}" class="{if $cur.active}is-active{/if}">
      {$cur.symbol} {$cur.code}
    </a>
  {/tw:currency}
</div>
属性默认说明
alias / keycur / key循环变量名 / 索引名

循环里可用的字段

字段说明
$cur.code货币代码,如 USD / EUR
$cur.name / $cur.symbol名称 / 符号($、€)
$cur.active是否当前生效货币(1/0)
切换是前端做的,没有后端路由

当前货币存在 cookie tw_cur 里(Currency::current() 读它,找不到就用基准货币)。 所以模板上的货币按钮只需写 cookie 再刷新,主题的 main.js 已经封装好: document.cookie = 'tw_cur=' + code + ';path=/;max-age=31536000' 然后 location.reload()。 金额输出用 {:tw_price($list.price)},会自动按当前货币汇率换算并带上符号。

十一、seo — SEO 头部

<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
{tw:seo /}
<link rel="stylesheet" href="/template/{$theme}/css/style.css">
</head>

一行输出全部:<title>、description、keywords、canonical、hreflang(含 x-default)、og:、twitter:、JSON-LD 结构化数据、robots。具体逻辑见 SEO 运维。

十二、slide — 幻灯片

闭合标签

{tw:slide group="home" limit="5"}
  <div class="slide{if $slide.first} is-first{/if}">
    {if $slide.has_video}
      <video src="{$slide.video}" muted loop playsinline></video>
    {else /}
      <img src="{$slide.image}" alt="{$slide.title}"{if $slide.mobile_image} data-mobile="{$slide.mobile_image}"{/if}>
    {/if}
    <h2>{$slide.title}</h2>
    <p>{$slide.subtitle}</p>
    {if $slide.url}<a href="{$slide.url}"{$slide.target_attr|raw}>{$slide.btn_text|default='了解更多'}</a>{/if}
  </div>
{/tw:slide}
属性默认说明
group当前栏目绑定的分组分组 code(如 home)或 id;不写就取栏目表单里的「幻灯片分组」,栏目没绑则输出空
limit0(不限)最多几张
ordersort asc, id asc只允许字母/数字/下划线/逗号/点/空格,其他字符会被过滤
lang当前语言指定取哪种语言的图
alias / keyslide / key循环变量名 / 索引名

循环里可用的字段

字段说明
$slide.id / $slide.title / $slide.subtitleID / 主标题 / 副标题
$slide.summary描述文字
$slide.image / $slide.image_url电脑图(两者同值,image_url 是旧主题兼容名)
$slide.image_mobile / $slide.mobile_image手机图(同上)
$slide.video / $slide.has_video / $slide.has_image视频地址 / 有没有视频 / 有没有图(1 或 0)
$slide.url / $slide.btn_text跳转链接 / 按钮文字
$slide.target_attr已拼好的 target="_blank" rel="noopener",输出时加 |raw
$slide.index / $slide.first / $slide.last第几张(从 1 起)/ 是否第一张 / 是否最后一张
两个自动行为

① 多语言回退:当前语言下这个分组没有启用的图,整组回退默认语言——只有一个语言的站不用为每种语言重复上传同一张图。
② 定时上下线:条目上的 start_time / end_time 非 0 时按当前时间过滤,过期自动消失,不用手动下架。

十三、slidegroup — 幻灯片分组信息

可自闭合,也可闭合

{* 取分组信息,判断有没有图再渲染容器 *}
{tw:slidegroup code="home" alias="g" /}
{if $g.count}
  <section class="hero" data-count="{$g.count}" data-w="{$g.width}">
    {tw:slide group="home"}
      ... 单张 ...
    {/tw:slide}
  </section>
{/if}

{* 也支持闭合写法,一次输出一段文案 *}
{tw:slidegroup code="home" alias="g"}{$g.name} 共 {$g.count} 张{/tw:slidegroup}
属性默认说明
code空分组 code,如 home;不写则取当前栏目绑定的分组
aliasg赋值变量名

可用字段:$g.id、$g.name、$g.code、$g.width、$g.height、$g.remark、$g.count(该分组当前语言下的图片数量)。分组不存在时返回各字段为空、count=0 的默认数组,模板不会报未定义变量。

十四、全局函数

函数说明
tw_setting('phone')取任意站点设置项,第二参数可给默认值
tw_url('sort', ['sort'=>12])生成链接。name 可取 home / sort / detail / search / message
tw_asset('css/style.css')主题资源地址,等价于 /template/{当前主题}/css/style.css
tw_seo()输出 SEO head(同 {tw:seo /})
tw_lang()当前语言代码
__tw('products')取语言包文案,模板里写 {:__tw('products')};支持占位符 __tw('hello', ['name'=>'Tom'])
tw_e($str)HTML 转义输出,防 XSS
tw_slug('CNC 加工')生成 URL 别名(拼音/英文小写连字符)
tw_date($ts)时间戳格式化,默认 M d, Y,第二参数可自定义格式
tw_cut($html, 160)按纯文本截取(先去标签),适合生成摘要与 meta description
tw_price(4800)金额格式化:按当前货币汇率换算并带符号(¥4,800.00 / $672.00),第二参数是单位
tw_currency()当前货币代码,常用于货币按钮上显示 USD ▾
tw_dict_json(['k1','k2'])输出 window.TW_DICT 脚本,把指定词条注入前端 JS(只注入列出的键,别整包输出)
tw_brand_url() / tw_brand_name() / tw_brand_link()品牌官网地址 / 名称 / 版权徽标链接(页脚用,自动读 config/tw.php 的 brand 段)

模板里怎么调函数

{:__tw('contact_us')}
{:tw_setting('email')}
{:date('Y', $content.publish_time)}
{:count($content['images'])}
{:number_format($content.price, 2)}

规则:{:表达式},冒号后写 PHP 表达式,前面不加 echo。

十五、常用配方

相关产品(同栏目,排除自己,取 4 条)

{tw:list sort="$sort.id" limit="4" exclude="$content.id"}
  {include file="comm/product-card" /}
{/tw:list}

最新新闻(限定 news 栏目)

{tw:list sort="news" limit="6" order="publish_time desc"}
  <li><a href="{$list.url}">{$list.title}</a><span>{$list.date}</span></li>
{/tw:list}

按标签取内容

{tw:list sort="*" tags="anodizing" limit="6"}
  <a href="{$list.url}">{$list.title}</a>
{/tw:list}

按浏览量排序(热门)

{tw:list sort="*" order="views desc" limit="5"}
  <a href="{$list.url}">{$list.title}({$list.views})</a>
{/tw:list}

首页调「关于我们」单页正文

{tw:sort id="6" alias="about" /}
<h2>{$about.name}</h2>
<p>{$about.description}</p>

十六、排查清单

现象原因
标签原样输出在页面上(能看到 {tw:list} 文字)标签库没注册成功,检查 config/view.php 的 taglib_pre_load 是否为 app\common\taglib\Tw
循环体空白该栏目下没有已发布内容;或语言不匹配(英文栏目只能取到 en 的内容)
列表带不出子栏目内容用的是 slug(sort="products")只取本栏目,改写成栏目 ID 才会自动包含子栏目
分页不显示{tw:list} 没写 page="$tw_page",或结果不足一页
图片是破图内容是老数据、ico 存的是绝对路径;检查上传目录是否可访问
{if} 里报语法错条件里用了过滤器(如 |count),改成函数写法 count($arr)
ThinkWo CMS v1.0.45 开发文档 · 基于 ThinkPHP 8.1.4 + LayUI 2.12 · 文档随代码更新