这是一个非常常见的需求,尤其是在制作动态导航栏、面包屑导航或者需要根据不同栏目调用内容的时候。

核心问题:为什么需要用变量?
在 DedeCMS 的模板文件(.htm)中,{dede:type} 标签的 typeid 属性通常需要一个固定的栏目ID。
{dede:type typeid='1'}
<a href="[field:typelink/]">[field:typename/]</a>
{/dede:type}
这段代码会固定调用 ID 为 1 的栏目。
在很多场景下,我们希望 typeid 是动态的,而不是写死的。
- 当前栏目:获取当前正在浏览的栏目的ID。
- 上级栏目:获取当前栏目的上一级栏目的ID。
- 顶级栏目:获取当前栏目所属的顶级栏目的ID。
- 从URL获取:从网址的参数中获取栏目ID(
index.php?cid=5)。
DedeCMS 提供了多种方式来实现这些动态效果。

使用 DedeCMS 全局变量(最常用)
DedeCMS 在解析模板时,会自动将一些常用信息存入全局变量 $this 中,我们可以通过 typeid、topid 等属性来获取这些动态ID。
获取当前栏目的ID ($this->typeid)
这是最常用的一种,当用户访问一个栏目页面时,$this->typeid 的值就是当前栏目的ID。
应用场景:制作当前栏目高亮的导航栏。
示例代码:
假设你的导航栏需要循环调用所有顶级栏目,但需要判断哪个是当前栏目,并给它一个高亮样式(class="current")。

<ul id="nav">
{dede:channel type='top' currentstyle="<li class='current'><a href='~typelink~'>~typename~</a></li>"}
<li><a href="[field:typelink/]">[field:typename/]</a></li>
{/dede:channel}
</ul>
上面的代码使用了 currentstyle,这是 dede:channel 标签自带的功能,如果你想在 {dede:type} 中使用,可以这样:
{dede:sql sql='SELECT id,typename,typedir FROM `dede_arctype` WHERE reid=0 ORDER BY sortrank'}
{if $this->typeid == $fields['id']}
<a href="[field:typedir function='str_replace("{cmspath}","",@me)'/]" class="current">[field:typename/]</a>
{else}
<a href="[field:typedir function='str_replace("{cmspath}","",@me)'/]">[field:typename/]</a>
{/if}
{/dede:sql}
{dede:sql}: 执行自定义SQL查询,这里查询所有顶级栏目 (reid=0)。$this->typeid: 获取当前页面的栏目ID。$fields['id']: 循环中当前栏目的ID。function='str_replace("{cmspath}","",@me)': 这是一个常用的函数,用于去除栏目链接中的{cmspath}占位符,生成正确的URL。
获取顶级栏目的ID ($this->topid)
$this->topid 存储的是当前栏目所属的顶级栏目的ID,这在制作面包屑导航或者调用顶级栏目下的所有子栏目时非常有用。
应用场景:面包屑导航。
示例代码:
面包屑导航通常需要显示 首页 > 顶级栏目 > 二级栏目 > ... 的形式。
<div class="breadcrumb">
<a href="/">首页</a>
{dede:field name='position'/>
</div>
{dede:field name='position'} 是 DedeCMS 自带的面包屑标签,它会自动根据 $this->typeid 和 $this->topid 来生成路径。
如果你想手动构建,可以这样:
<a href="/">首页</a> >
{dede:type typeid='$this->topid'}
<a href="[field:typelink/]">[field:typename/]</a>
{/dede:type} >
{dede:type typeid='$this->typeid'}
<span>[field:typename/]</span>
{/dede:type}
- 这里我们直接在
typeid属性里写变量$this->topid,DedeCMS 的模板引擎会自动解析它。 - 第一个
{dede:type}获取顶级栏目,第二个获取当前栏目。
通过PHP代码获取(最灵活)
当内置变量无法满足你的需求时,你可以在模板文件中直接嵌入PHP代码,这需要你的模板文件是 .php 后缀,或者在模板文件开头使用 <?php ?> 标签(需要服务器配置支持)。
应用场景:从URL参数获取ID,或者进行更复杂的逻辑判断。
示例场景:假设你的网址是 list.php?cid=5,你想获取这个 cid 的值。
示例代码:
<?php
// 从GET请求中获取cid参数,并做安全处理(非常重要!)
$typeid_from_url = isset($_GET['cid']) ? (int)$_GET['cid'] : 0;
// 如果获取到的ID大于0,则使用它
if ($typeid_from_url > 0) {
$target_typeid = $typeid_from_url;
} else {
// 否则,默认使用当前栏目ID
$target_typeid = $this->typeid;
}
?>
<!-- 使用PHP变量来赋值给typeid -->
{dede:type typeid='<?php echo $target_typeid; ?>'}
<h1>[field:typename/]</h1>
<p>这是栏目ID为 [field:id/] 的栏目页面。</p>
{/dede:type}
isset($_GET['cid']): 检查URL中是否存在cid参数。(int)$_GET['cid']: 将参数值强制转换为整数,这是防止SQL注入等安全问题的关键一步。<?php echo $target_typeid; ?>: 将PHP变量输出到模板标签中。
使用自定义函数(可复用)
如果你在多个地方都需要使用同一种逻辑来获取 typeid,可以将其封装成一个自定义函数,然后在模板中调用。
应用场景:统一处理某个来源的ID,方便后期维护。
示例步骤:
-
找到并修改
include/extend.func.php文件。 在这个文件中添加你的自定义函数:// 函数名:get_target_typeid // 功能:根据优先级获取目标栏目ID function get_target_typeid() { // 1. 优先从URL参数获取 if (isset($_GET['cid']) && (int)$_GET['cid'] > 0) { return (int)$_GET['cid']; } // 2. 其次从当前页面获取 global $dsql; $typeid = isset($dsql->typeid) ? $dsql->typeid : 0; if ($typeid > 0) { return $typeid; } // 3. 默认返回0或其他值 return 0; } -
在模板文件中调用这个函数:
{dede:type typeid='{dede:get_target_typeid()/}'} <a href="[field:typelink/]">[field:typename/]</a> {/dede:type}{dede:get_target_typeid()/}: 这就是调用自定义函数的方式。 表示这是一个无参数的函数调用。
总结与最佳实践
| 场景 | 推荐方法 | 示例 |
|---|---|---|
| 获取当前栏目ID | 使用全局变量 $this->typeid |
typeid='$this->typeid' |
| 获取顶级栏目ID | 使用全局变量 $this->topid |
typeid='$this->topid' |
| 从URL获取ID | 使用PHP代码并做安全过滤 | typeid='<?php echo (int)$_GET["cid"]; ?>' |
| 复杂的动态逻辑 | 使用PHP代码块 | <?php ... ?> + typeid='$my_var' |
| 多处复用逻辑 | 使用自定义函数 | typeid='{dede:myfunction()/}' |
重要提示:安全!
当处理任何来自用户输入(如URL参数)的ID时,一定要进行类型转换或过滤,最简单有效的方法就是使用 (int) 将其转为整数,这样可以有效防止SQL注入等安全问题。
永远不要这样做:
<!-- 错误示例!有安全风险! -->
{dede:type typeid='$_GET["cid"]'}
...
{/dede:type}
正确的做法是使用PHP代码进行预处理。
