什么是“标签套用标签”?
就是在一个 DedeCMS 的标签内部,使用另一个标签作为其属性值,这允许你根据动态数据来构建查询条件,实现比单一标签更灵活、更复杂的逻辑。

(图片来源网络,侵删)
你想获取“当前栏目ID下的子栏目”中的文章列表,这就需要先获取当前栏目的ID(一个标签),然后将这个ID作为另一个“文章列表”标签的查询条件(另一个标签的套用)。
使用[field:函数] 套用[field:属性] (最常用)
这是最基础也是最常用的方法,主要用于在循环标签(如 {dede:arclist}, {dede:loop})内部,利用当前项的某个字段值,来获取更多信息。
场景示例: 在文章列表中,显示每篇文章的“所属栏目”的名称。
- 获取文章列表: 使用
{dede:arclist}- 获取栏目名称: 在
{dede:arclist}内部,使用{dede:field.typeid/}获取当前文章的栏目ID。- 套用标签: 使用
{dede:channel}标签,并将typeid属性设置为{dede:field.typeid/}。 - 获取栏目名称: 在
代码示例:

(图片来源网络,侵删)
{dede:arclist titlelen='50' row='5'}
<li>
<a href="[field:arcurl/]">[field:title/]</a>
<!-- 套用标签开始:根据[field:typeid]获取栏目名称 -->
<span>栏目:[field:typename function='GetChannelName(@me)'/]</span>
<!-- 套用标签结束 -->
</li>
{/dede:arclist}
代码解析:
{dede:arclist}: 循环输出文章列表。[field:arcurl/]和[field:title/]: 分别是文章的链接和标题。[field:typeid/]: 获取当前文章的栏目ID。[field:typename function='GetChannelName(@me)'/]: 这是关键。field:typename指的是当前项的栏目名称字段。function='GetChannelName(@me)'是一个PHP函数调用。@me是 DedeCMS 的一个特殊变量,代表当前标签的原始值(在这里就是[field:typeid/]的值,即栏目ID)。GetChannelName()是 DedeCMS 内置的一个函数,它接收一个栏目ID,并返回该栏目的名称。
更直观的写法(使用嵌套标签):
在某些版本或特定场景下,也可以这样写,虽然不如函数调用简洁,但逻辑更清晰:
{dede:arclist titlelen='50' row='5'}
<li>
<a href="[field:arcurl/]">[field:title/]</a>
<!-- 套用标签开始:使用[field:typeid]作为channel标签的typeid属性 -->
<span>栏目:
{dede:channel typeid='[field:typeid/]'}
[field:typename/]
{/dede:channel}
</span>
<!-- 套用标签结束 -->
</li>
{/dede:arclist}
这种方式在 {dede:arclist} 的每一次循环中,都会执行一次 {dede:channel} 查询,效率上可能略低于函数调用,但对于初学者来说更容易理解。

(图片来源网络,侵删)
使用PHP代码套用标签 (最灵活)
当内置标签和函数无法满足复杂需求时,可以直接在模板中使用PHP代码,这是最强大、最灵活的方法。
场景示例: 显示“当前栏目及其所有一级子栏目”下的文章列表。
- 获取当前栏目ID: 使用
{dede:field name='typeid'/}。 - 获取子栏目ID列表: 使用
GetSonIds()函数。 - 组合查询条件: 将当前栏目ID和子栏目ID用逗号连接,形成
typeid查询条件。 - 套用标签: 将组合好的条件作为
typeid属性传递给{dede:arclist}。
代码示例:
{dede:php}
// 1. 获取当前栏目ID
$typeid = $this->Fields['typeid'];
// 2. 获取当前栏目及其所有一级子栏目的ID列表
// $typeid 表示起始栏目ID
// 0 表示不获取子级子栏目(只获取一级)
// ',' 是分隔符
$sonids = GetSonIds($typeid, 0, ',');
// 3. 将当前栏目ID和子栏目ID合并,形成最终的typeid查询条件
// 如果当前栏目就是最终栏目,$typeid_in 就等于 $typeid
// 如果有子栏目,$typeid_in 就等于 "1,2,3" 这样的格式
$typeid_in = empty($sonids) ? $typeid : $typeid . ',' . $sonids;
// 4. 使用合并后的ID作为arclist标签的typeid属性
// 这里我们直接输出一个完整的arclist标签
$arclist = "
{dede:arclist typeid='$typeid_in' titlelen='50' row='8'}
<li><a href='[field:arcurl/]'>[field:title/]</a></li>
{/dede:arclist}
";
// 输出最终生成的HTML
echo $arclist;
{/dede:php}
代码解析:
{dede:php}...{/dede:php}: 在模板中执行PHP代码。$this->Fields['typeid']: 获取当前页面的栏目ID。GetSonIds(): DedeCMS 核心函数,用于获取指定栏目的子栏目ID。$typeid_in: 我们动态构建的查询条件字符串。- 我们将这个动态构建的
$typeid_in变量嵌入到{dede:arclist}标签中,实现了“标签套用标签”的高级效果。
使用SQL查询套用标签 (性能最高)
当需要的数据非常复杂,或者对性能要求极高时,可以直接在模板中执行原生SQL查询,然后循环输出结果。
场景示例: 查询并显示“评论数最多的5篇文章”。
代码示例:
{dede:sql sql='SELECT arc.id, arc.title, arc.click FROM dede_archives arc ORDER BY arc.click DESC LIMIT 0,5'}
<li>
<a href='[field:id runphp='yes'] $id = @me; @me = GetArcUrl($id); [/field:id]'>[field:title/]</a>
(点击: [field:click/])
</li>
{/dede:sql}
代码解析:
{dede:sql sql='...'}: 执行自定义的SQL语句。SELECT ... FROM dede_archives ...: 直接查询数据库表dede_archives。[field:id runphp='yes']...[/field:id]: 在SQL循环标签中,同样可以使用runphp来对字段值进行复杂处理,这里我们通过GetArcUrl()函数将文章ID转换为文章URL。
最佳实践与注意事项
-
性能优先:
- 方法一(函数套用) 性能较好,适合大多数场景。
- 方法二(PHP套用) 灵活,但如果循环次数多(如
row='100'),内部再嵌套查询,会造成严重的“N+1查询问题”,导致数据库压力巨大,页面加载缓慢。 - 方法三(SQL查询) 性能最高,因为它将所有逻辑都放在一个数据库查询中完成,应该优先考虑。
-
代码可读性:
尽量保持模板的简洁,如果PHP逻辑过于复杂,可以考虑在 DedeCMS 的核心文件中修改,或者使用自定义函数/标签类,而不是在模板里写大段PHP。
-
安全性:
- 在使用
{dede:php}和{dede:sql}时,要特别注意防止SQL注入,如果用户输入的数据(如URL参数)会拼接到SQL语句中,必须进行严格的过滤和转义,DedeCMS 的标签系统通常会处理一部分,但开发者仍需保持警惕。
- 在使用
-
调试技巧:
- 如果不确定标签套用后的结果是什么,可以在模板中临时使用
{dede:php} print_r($变量); {/dede:php}来打印出PHP变量的值,帮助调试。 - 也可以使用
{dede:field.name/}来确认当前页面能获取到哪些基础字段。
- 如果不确定标签套用后的结果是什么,可以在模板中临时使用
| 方法 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| [field:函数] | 循环标签内部,获取关联信息(如栏目名、作者名) | 简单、高效、代码清晰 | 功能相对有限,依赖内置函数 |
{dede:php} |
复杂逻辑判断、动态组合查询条件 | 极其灵活,能实现任何功能 | 可能影响性能,代码可读性差,有安全风险 |
{dede:sql} |
复杂数据统计、跨表关联查询 | 性能最高,逻辑最集中 | SQL语句复杂,不易维护,有安全风险 |
对于初学者,建议从方法一开始,逐步掌握,当遇到无法解决的复杂需求时,再考虑使用方法二和方法三,并时刻牢记性能和安全问题。
