listsql 是 arclist 或 list 标签的一个强大功能,它允许你直接手写 SQL 查询语句,从而实现比常规调用标签更灵活、更复杂的列表数据获取,动态传参则是让这个功能变得实用的关键。

核心原理
动态传参的核心是利用 DedeCMS 的模板引擎机制,它会解析模板中的特定标签(如 {dede:field}),将 PHP 代码中定义的变量值替换掉模板中的占位符,然后再执行最终的 SQL 查询。
场景示例
假设我们要做一个文章列表页,可以根据 URL 传递过来的 typeid (栏目ID) 和 keyword (关键词) 来动态筛选文章。
目标URL示例:
http://yourdomain.com/list.php?tid=5&k=织梦(获取栏目ID为5,标题包含“织梦”的文章)http://yourdomain.com/list.php?tid=8(仅获取栏目ID为8的文章)
实现步骤
第 1 步:修改模板文件 (list_article.htm)
在你的列表模板文件中,找到调用文章列表的 arclist 或 list 标签,将它的 sql 属性(注意是 sql,不是 listsql,listsql 是 list 标签的属性,arclist 标签用的是 sql)设置为一个包含 PHP 变量的 SQL 模板。

{dede:list sql="SELECT arc.*,tp.typedir,tp.typename,tp.corank,tp.isdefault,tp.defaultname,tp.moresite,tp.siteurl,tp.sitepath
FROM `dede_archives` arc
LEFT JOIN `dede_arctype` tp ON arc.typeid=tp.id
WHERE 1=1
AND arc.arcrank > -1
[field:typeid function="GetSonIds(@me)"/]
AND arc.title LIKE '%[field:keyword]%'
ORDER BY arc.sortrank DESC LIMIT 0,10"}
<li>
<a href="[field:arcurl/]">[field:title/]</a>
<span>[field:pubdate function="MyDate('Y-m-d',@me)"/]</span>
</li>
{/dede:list}
模板代码解析:
sql="...": 我们在这里直接写 SQL 查询语句。WHERE 1=1: 这是一个常用的 SQL 技巧,方便后续添加AND条件,而不用担心第一个条件是AND还是WHERE。[field:typeid function="GetSonIds(@me)"/]: 这是动态传参的关键部分。[field:typeid]: 这是一个模板标签,它会尝试获取一个名为typeid的变量。function="GetSonIds(@me)": 这是 DedeCMS 的一个内置函数,如果传入了typeid,它会获取该栏目及其所有子栏目的 ID,并用 连接起来,5,12,13。typeid为空,这个函数会返回空字符串,这样 SQL 语句就变成了WHERE 1=1 AND (),这会报错,所以我们需要在 PHP 代码中处理这种情况。
AND arc.title LIKE '%[field:keyword]%': 同样,[field:keyword]会获取 URL 中传递的k参数的值。
注意:
list标签默认不支持调用栏目信息(如tp.typename),所以这里我们直接使用arclist标签的sql属性会更方便,如果你的模板是list标签,并且需要复杂查询,建议直接替换为arclist。
第 2 步:修改 PHP 文件 (list.php)
这是实现动态传参的核心,我们需要修改 list.php 文件,在它执行模板渲染之前,获取 URL 参数并设置给模板引擎。
打开 /plus/list.php 文件,找到类似下面的代码:
// ... require_once(dirname(__FILE__)."/../include/common.inc.php"); require_once(DEDEINC."/arc.listview.class.php"); $tid = isset($tid) && is_numeric($tid) ? $tid : 0; // ... 获取分页等其他参数 ... $lv = new ListView($tid,$typeid,$channelid,$totalresult,$keyword,$tagid,$pageno); $lv->SetTemplate($tempfile); $lv->SaveToHtml(); $lv->Display(); // ...
我们需要在 new ListView(...) 之前,处理我们的参数。
修改后的 list.php 关键代码:
<?php require_once(dirname(__FILE__)."/../include/common.inc.php"); require_once(DEDEINC."/arc.listview.class.php"); // --- 开始修改 --- // 1. 获取并处理 typeid 参数 $dynamic_typeid = isset($tid) && is_numeric($tid) ? intval($tid) : 0; // 2. 获取并处理 keyword 参数 $dynamic_keyword = isset($k) ? trim($k) : ''; // 3. 将参数传递给模板,覆盖默认的 $tid 和 $keyword // 这里的 'typeid' 和 'keyword' 必须和模板中的 [field:typeid] 和 [field:keyword] 对应 $GLOBALS['typeid'] = $dynamic_typeid; $GLOBALS['keyword'] = $dynamic_keyword; // --- 修改结束 --- // ... 后面的代码保持不变,但要注意 $typeid 变量已经被我们覆盖了 ... // 如果后续代码还需要原始的 $typeid,请使用另一个变量名保存 $tid = isset($tid) && is_numeric($tid) ? $tid : 0; // 这里的 $tid 已经是我们动态设置的值了 $typeid = $tid; // arc.listview.class.php 内部使用 $typeid,可以这样同步 // ... 获取分页等其他参数 ... $lv = new ListView($tid,$typeid,$channelid,$totalresult,$keyword,$tagid,$pageno); $lv->SetTemplate($tempfile); $lv->SaveToHtml(); $lv->Display();
PHP 代码解析:
$dynamic_typeid = isset($tid) ? ...: 从 URL 中获取tid参数,并进行安全处理(intval)。$dynamic_keyword = isset($k) ? ...: 从 URL 中获取k参数(k是keyword的简写,更美观)。$GLOBALS['typeid'] = $dynamic_typeid;: 这是最关键的一步! 我们将获取到的值赋值给一个全局变量$GLOBALS,DedeCMS 的模板引擎会自动查找$GLOBALS数组中的变量,并将其暴露给模板使用,模板中的[field:typeid]实际上就是从这里取值的。$GLOBALS['keyword'] = $dynamic_keyword;: 同理,将关键词也传递给模板。
第 3 步:优化模板 SQL 语句(防止 SQL 错误)
回到模板,我们发现如果 typeid 或 keyword 为空,SQL 语句可能会出错,我们可以用 DedeCMS 的 if 标签来优化。
{dede:list sql="SELECT arc.*,tp.typedir,tp.typename,tp.corank,tp.isdefault,tp.defaultname,tp.moresite,tp.siteurl,tp.sitepath
FROM `dede_archives` arc
LEFT JOIN `dede_arctype` tp ON arc.typeid=tp.id
WHERE 1=1
AND arc.arcrank > -1
[field:typeid runphp='yes']
if(@me != '') @me = " AND arc.typeid IN (".@me.")";
else @me = "";
[/field:typeid]
[field:keyword runphp='yes']
if(@me != '') @me = " AND arc.title LIKE '%".@me."%'";
else @me = "";
[/field:keyword]
ORDER BY arc.sortrank DESC LIMIT 0,10"}
<!-- ... 循环体 ... -->
{/dede:list}
优化后的模板代码解析:
[field:typeid runphp='yes']...[/field:typeid]: 对typeid参数进行 PHP 处理。runphp='yes': 启用 PHP 解析。if(@me != ''): 判断获取到的值是否为空。@me = " AND arc.typeid IN (".@me.")";: 如果不为空,则拼接成有效的 SQL 条件,注意这里用IN而不是 ,因为GetSonIds函数返回的是多个 ID。else @me = "";: 如果为空,则设置为空字符串,避免 SQL 语法错误。
[field:keyword runphp='yes']...[/field:keyword]: 同理,对keyword参数进行 PHP 处理,只有在有值的时候才拼接LIKE查询。
总结与最佳实践
- 模板与 PHP 分离: 模板只负责展示逻辑,PHP 负责数据准备和传递,这是现代开发的基本原则。
- 安全性: 永远不要直接信任用户输入,像示例中那样,对
intval($tid)和trim($k)进行处理,可以有效防止 SQL 注入和 XSS 攻击。 - SQL 复杂度:
listsql(或sql) 虽然强大,但写复杂的 SQL 语句容易出错,且不利于后续维护,如果查询逻辑非常复杂,可以考虑在 PHP 中先查询好数据,再通过array标签传递给模板。 - 变量命名: 为了清晰,建议在 PHP 中使用不同的变量名(如
$dynamic_typeid)来接收参数,然后统一赋值给$GLOBALS供模板使用,避免混淆。 - 性能: 直接写 SQL 通常比 DedeCMS 内置的标签解析效率更高,因为它减少了标签解析的开销,但对于简单列表,推荐使用标准的
arclist或list标签,代码更简洁,也方便后台缓存。
通过以上步骤,你就可以在 DedeCMS 中灵活地使用 listsql 并实现各种动态传参的需求了。
