下面我将通过一个详细的、可操作的例子来讲解如何实现,我们以一个常见的商品筛选为例,假设有两个筛选条件:

- 分类 (
typeid) - 品牌 (
brand)
第一步:准备工作 (修改模板和创建表单)
-
修改列表模板文件 打开你的列表页模板文件,通常位于
/templets/你的栏目目录/list_栏目ID.htm,我们需要在这个文件里添加筛选表单。 -
添加筛选表单 在模板的合适位置(通常是列表上方)添加一个表单,这个表单将包含两个下拉选择框和一个提交按钮。
<form name="searchform" action="" method="get"> <!-- 隐藏域,用于传递当前栏目ID,确保筛选后仍在当前栏目下 --> <input type="hidden" name="typeid" value="{dede:type typeid='[field:id/]'}[field:id]{/dede:type}" /> <!-- 筛选条件1:分类 --> <select name="typeid_filter"> <option value="">所有分类</option> {dede:channel type='son' currentstyle="<option value='~typeid~' selected>~typename~</option>"} <option value="[field:id/]">[field:typename/]</option> {/dede:channel} </select> <!-- 筛选条件2:品牌 --> <select name="brand"> <option value="">所有品牌</option> {dede:sql sql="SELECT DISTINCT brand FROM `dede_addonarticle` WHERE brand != '' ORDER BY brand ASC"} <option value="[field:brand/]">[field:brand/]</option> {/dede:sql} </select> <!-- 提交按钮 --> <button type="submit">筛选</button> </form>代码解释:
form的method必须是get,这样筛选条件会以 URL 参数的形式传递(.../list.php?tid=1&brand=苹果)。typeid_filter和brand是我们为两个筛选条件自定义的参数名。- 品牌的下拉框是通过
dede:sql标签直接从数据库中读取不重复的品牌列表,前提是你的自定义模型或文章模型中有一个名为brand的字段。
第二步:修改PHP文件 (处理逻辑)
这是最关键的一步,我们需要修改处理列表页的PHP文件,通常是 /include/arc.listview.class.php。强烈建议在修改前备份这个文件!

-
打开
/include/arc.listview.class.php -
找到
GetSql()方法 这个方法负责生成最终的SQL查询语句,我们需要在这里添加逻辑来处理URL参数。 -
修改
GetSql()方法 在这个方法中,找到构建where条件的部分(通常在方法的后半部分),然后添加我们的筛选逻辑。在类似这样的代码块附近进行修改:
// ... 在 GetSql() 方法中找到 $this->addSql .= " And arc.typeid in($typeid)"; 这类代码之后 ... // --- 开始添加我们的筛选逻辑 --- if (!empty($this->searchArr['typeid_filter'])) { // 如果选择了分类筛选 $this->addSql .= " And arc.typeid = '".$this->searchArr['typeid_filter']."'"; } if (!empty($this->searchArr['brand'])) { // 如果选择了品牌筛选 // 注意:这里假设你的品牌字段在附加表 dede_addonarticle 中 // 如果是其他模型,请替换为对应的附加表名,如 dede_addonshopproduct $this->addSql .= " And arc.body LIKE '%".$this->searchArr['brand']."%'"; // 使用 body 字段模糊匹配,或者直接用 addon.brand // 更精确的做法是使用 JOIN 连接附加表,这需要更复杂的SQL修改 // 对于初学者,先用 LIKE 模糊匹配是最简单的。 // 如果你为品牌设置了独立的字段,并且附加表里有这个字段,可以这样写: // $this->addSql .= " And addontable.brand = '".$this->searchArr['brand']."'"; // 但这通常需要先 JOIN 附加表。 } // --- 结束添加我们的筛选逻辑 ---重要说明:
$this->searchArr是一个数组,用来存储所有通过GET方式传递过来的URL参数。- 我们通过
!empty()判断参数是否存在,如果存在,就将其拼接到SQL的where条件中。 - 品牌匹配的SQL写法:上面的例子使用了
arc.body LIKE '%...%'',这是一种简单粗暴的模糊匹配,它会匹配文章内容中任何包含品牌名的记录。这不是最佳实践。 - 最佳实践(推荐):如果你的品牌是一个独立的、有索引的字段,你应该在附加表(如
dede_addonarticle)中操作,最规范的写法是使用JOIN,但这需要对GetSql()方法进行更深入的改造,稍显复杂,对于大多数情况,先使用LIKE可以快速实现功能。
第三步:处理分页问题 (非常重要)
直接修改 GetSql() 会导致一个问题:分页失效,因为分页时,系统会重新调用 GetSql() 方法,但此时筛选参数已经丢失了。
为了解决这个问题,我们需要在 GetSql() 方法中增加一个逻辑,让它在生成分页SQL时,也带上筛选条件。
找到 GetPageListDT() 方法(或者类似处理分页的方法),确保它在调用 GetSql() 时,能将 $this->searchArr 传递过去,或者在 GetSql() 内部能持续访问到这些参数。
arc.listview.class.php 的 GetSql() 方法本身已经可以访问 $this->searchArr,所以理论上你的修改应该已经能支持分页,但如果你发现分页后筛选条件丢失,请检查 $this->addSql 变量在每次调用 GetSql() 时是否都被正确重置和构建。
一个更稳妥的方案是,在 GetSql() 方法开始处,就先构建好所有筛选条件,而不是在后面 if 判断。
改进后的 GetSql() 逻辑片段:
// 在 GetSql() 方法中,构建 where 条件的部分
$where = " arc.arcrank > -1 ";
// ... 其他默认条件 ...
// --- 添加我们的筛选逻辑 ---
if (!empty($this->searchArr['typeid_filter'])) {
$where .= " AND arc.typeid = '".$this->searchArr['typeid_filter']."'";
}
if (!empty($this->searchArr['brand'])) {
// 假设品牌在附加表的 brand 字段
// 为了能使用 addontable.brand,我们需要先 JOIN 附加表
// 这里的写法更规范,但需要对整个SQL结构有了解
// $where .= " AND addontable.brand = '".$this->searchArr['brand']."'";
// 简单的模糊匹配方案
$where .= " AND arc.body LIKE '%".$this->searchArr['brand']."%'";
}
// 将 $where 赋值给 $this->addSql
$this->addSql = $where;
第四步:URL伪静态优化 (可选但推荐)
URL中带有 和参数名不太美观,我们可以利用DedeCMS的伪静态规则将其美化。
将:
/list.php?tid=1&typeid_filter=5&brand=苹果
美化成:
/list/tid1/typeid5/brand苹果.html
-
修改
/include/helpers/helper_channelunit.php找到GetListUrl($typeid)或类似的函数,修改生成列表URL的逻辑,使其包含所有GET参数,这通常比较复杂。 -
更简单的方法:修改
.htaccess(如果使用Apache) 在网站根目录的.htaccess文件中添加 Rewrite 规则。<IfModule mod_rewrite.c> RewriteEngine On # 将美化后的URL重写回真实的 list.php # 格式: /list/栏目ID/参数1名/参数1值/参数2名/参数2值.html RewriteRule ^list/tid([0-9]+)/(.+)\.html$ /list.php?tid=$1&$2 </IfModule>
这个规则会把
/list/tid10/typeid_filter5/brand苹果.html这样的URL解析成/list.php?tid=10&typeid_filter=5&brand=苹果。 -
修改模板中的链接 在你的列表页模板中,所有指向当前页面的链接(如分页链接、筛选后的链接)都需要手动拼接成新的伪静态格式,这通常需要修改
arc.listview.class.php中生成URL的部分,或者在模板中通过{dede:field name='phpurl'/}/list.php?tid={dede:field name='typeid'/}&{$filter_str}这样的方式动态构建,$filter_str需要你自定义变量来保存拼接好的筛选参数。
总结与最佳实践
- 功能实现:核心是 模板表单 (GET提交) -> PHP处理 (拼接SQL) -> 数据库查询。
- 性能:
LIKE '%...%'会导致全表扫描,性能较差,如果数据量大,请务必为品牌等筛选字段建立独立的数据库字段和索引,并在SQL中使用 精确匹配。 - 扩展性:如果筛选条件很多,可以考虑将
GetSql()方法中的if判断改写成循环,通过一个数组来管理所有筛选规则,这样代码会更简洁、易于维护。 - 安全性:在拼接SQL时,虽然DedeCMS底层有部分过滤,但最好还是对用户输入的参数进行转义或预处理,防止SQL注入。
dede:sql和$this->searchArr传递过来的参数通常是经过处理的。
通过以上步骤,你就可以成功实现 DedeCMS 同时选择两个筛选条件的功能了,从最简单的 LIKE 匹配开始,实现功能后,再根据性能和规范要求进行优化。
