dede商城三级筛选如何实现?

99ANYc3cd6
预计阅读时长 41 分钟
位置: 首页 DEDE建站 正文

这是一个非常经典的需求,但 DedeCMS 本身并没有内置如此精细化的多级筛选功能,我们需要通过自定义模型 + 开发的方式来实现。

dede商城类三级筛选
(图片来源网络,侵删)

核心思路是:

  1. 创建数据模型:为商品建立一个支持多级分类和自定义属性(用于筛选)的数据模型。
  2. 设计数据结构:将筛选条件(如品牌、材质、风格等)作为商品的自定义字段来存储。
  3. 修改模板:在前台模板中,用下拉菜单或复选框的形式展示这些筛选条件。
  4. 修改程序:修改列表页的 arc.listview.class.php 文件,使其能够根据筛选条件动态生成 SQL 查询语句。

下面是详细的步骤分解。


第一步:创建自定义数据模型

这是实现筛选功能的基础,我们需要创建一个专门用于商城商品的数据模型,并为其添加筛选所需的字段。

  1. 进入模型管理

    dede商城类三级筛选
    (图片来源网络,侵删)
    • 登录 DedeCMS 后台。
    • 核心 -> 内容模型管理 -> 添加新模型。
    • 模型名称:填写“商城商品”或“产品”。
    • 表前缀:可以使用默认的 dede_,也可以自定义,如 shop_,为了清晰,建议使用 shop_
    • 填写其他信息,然后提交,系统会自动创建数据表 shop_archives(文章主表)和 shop_addonxx(文章附加表,xx 是数字)。
  2. 添加筛选字段

    • 在刚刚创建的模型管理页面,点击“字段管理”。
    • 我们将为每个筛选条件添加一个字段,我们要实现“品牌 > 系列 > 型号”的三级筛选,就需要添加三个字段。

    示例:添加“品牌”字段

    • 字段名brand (必须为英文小写,无空格)
    • 字段别名品牌
    • 字段类型下拉菜单
    • 字段值品牌A,品牌B,品牌C (用英文逗号分隔,这些是后台发布商品时可以选择的品牌)
    • 是否为必填项:根据需要选择
    • 保存。

    示例:添加“系列”字段

    • 字段名series
    • 字段别名系列
    • 字段类型下拉菜单
    • 字段值系列1,系列2,系列3
    • 保存。

    示例:添加“型号”字段

    dede商城类三级筛选
    (图片来源网络,侵删)
    • 字段名model
    • 字段别名型号
    • 字段类型下拉菜单文本 (如果型号很多且不固定,文本让用户输入更灵活)
    • 保存。

    你可以添加更多筛选字段,如:

    • price (价格,类型为数字)
    • color (颜色,类型为下拉菜单)
    • material (材质,类型为下拉菜单)
    • guarantee (保修,类型为单选)
  3. 发布测试商品

    • 核心 -> 内容发布 -> 选择你刚创建的“商城商品”模型。
    • 发布几条测试商品,并为它们填写不同的筛选字段值。
      • 商品A:品牌=品牌A, 系列=系列1, 型号=X1
      • 商品B:品牌=品牌A, 系列=系列1, 型号=X2
      • 商品C:品牌=品牌B, 系列=系列2, 型号=Y1

第二步:修改列表页模板 (list_*.htm)

现在我们要在前台展示筛选控件。

  1. 找到你的列表页模板,通常位于 templets/你的默认模板/ 目录下,文件名如 list_shop.htm

  2. 开始前,添加筛选表单: 在 {dede:list} 标签之前,添加以下 HTML 代码,这里以品牌、系列、型号为例。

    <div class="filter-area">
      <form name="filterForm" action="{dede:global.cfg_cmspath/}/plus/list.php" method="get">
        <!-- 隐藏字段,指定模型ID,这个ID在模型管理里可以看到 -->
        <input type="hidden" name="tid" value="{dede:field.tid/}" />
        <!-- 隐藏字段,指定模型ID,这个ID在模型管理里可以看到 -->
        <input type="hidden" name="modelid" value="你的模型ID" /> 
        <!-- 品牌筛选 -->
        <div class="filter-item">
          <label>品牌:</label>
          <select name="brand" onchange="document.filterForm.submit()">
            <option value="">全部品牌</option>
            {dede:channel type='self' row='100'}
            <!-- 这里需要自定义SQL来获取所有品牌,下面会提供SQL示例 -->
            <!-- <option value="[field:typename/]">[field:typename/]</option> -->
            {/dede:channel}
          </select>
        </div>
        <!-- 系列筛选 (根据品牌联动) -->
        <div class="filter-item">
          <label>系列:</label>
          <select name="series" onchange="document.filterForm.submit()">
            <option value="">全部系列</option>
            <!-- 系列选项将通过JS动态加载,这里先留空 -->
          </select>
        </div>
        <!-- 型号筛选 (根据系列联动) -->
        <div class="filter-item">
          <label>型号:</label>
          <select name="model" onchange="document.filterForm.submit()">
            <option value="">全部型号</option>
            <!-- 型号选项将通过JS动态加载,这里先留空 -->
          </select>
        </div>
        <!-- 其他筛选字段,如价格 -->
        <div class="filter-item">
          <label>价格:</label>
          <input type="text" name="minprice" placeholder="最低价" size="5" />
          <span>-</span>
          <input type="text" name="maxprice" placeholder="最高价" size="5" />
          <button type="submit">筛选</button>
        </div>
      </form>
    </div>

重要说明

  • modelid:你必须在这里填入你创建的“商城商品”模型的ID。
  • {dede:channel} 标签默认用于获取栏目,不适用于获取自定义字段的值,要获取所有品牌列表,你需要自定义一个函数或使用SQL标签,一个简单的方法是在后台手动获取所有品牌值,然后硬编码到 option 中,或者使用更复杂的 dede:sql 标签(不推荐,有性能和安全风险)。

第三步:修改程序文件 (arc.listview.class.php)

这是实现筛选功能的核心逻辑,当用户选择筛选条件并提交表单后,PHP程序需要根据这些条件来修改查询商品的SQL语句。

  1. 找到文件include/arc.listview.class.php

  2. 修改 Query 方法:在这个文件中,找到 Query() 方法,这个方法负责构建最终的SQL查询,我们需要在它里面添加对筛选参数的处理。

  3. 添加筛选逻辑:在 Query() 方法内部,找到构建 where 条件的部分(通常是一个 $this->addSql = ''; 相关的逻辑),然后在后面添加你的筛选代码。

    // 在 arc.listview.class.php 的 Query() 方法中添加
    // 1. 获取筛选参数
    $brand = isset($this->refObj->Fields['brand']) ? trim($this->refObj->Fields['brand']) : '';
    $series = isset($this->refObj->Fields['series']) ? trim($this->refObj->Fields['series']) : '';
    $model = isset($this->refObj->Fields['model']) ? trim($this->refObj->Fields['model']) : '';
    $minprice = isset($this->refObj->Fields['minprice']) ? trim($this->refObj->Fields['minprice']) : '';
    $maxprice = isset($this->refObj->Fields['maxprice']) ? trim($this->refObj->Fields['maxprice']) : '';
    // 2. 构建 WHERE 条件
    $addwhere = array();
    if ($brand != '') {
        // 注意:字段名要和你自定义的字段名一致
        // 表名前缀要和你创建模型时的一致,这里是 shop_
        $addwhere[] = " (arc.addonfield LIKE '%\"{$brand}\"%') ";
    }
    if ($series != '') {
        $addwhere[] = " (arc.addonfield LIKE '%\"{$series}\"%') ";
    }
    if ($model != '') {
        $addwhere[] = " (arc.addonfield LIKE '%\"{$model}\"%') ";
    }
    if ($minprice != '') {
        $addwhere[] = " arc.price >= {$minprice} ";
    }
    if ($maxprice != '') {
        $addwhere[] = " arc.price <= {$maxprice} ";
    }
    // 3. 将条件附加到主查询
    if (count($addwhere) > 0) {
        $this->addSql = " AND " . implode(' AND ', $addwhere);
    }
    

代码解释

  • $this->refObj->Fields:用于获取通过URL传递过来的GET参数。
  • arc.addonfield:这是 DedeCMS 存储所有自定义字段值的地方,它是一个序列化的JSON字符串,所以我们需要用 LIKE 来查询。
  • 注意:这种 LIKE '%...%' 的查询方式在数据量很大时性能会很差,对于大型商城,推荐将筛选字段单独存为数据库列,并进行精确匹配 (),上面的代码是通用但低效的方案。
  • 表名arc 是默认的别名,如果你的附加表前缀是 shop_,那么附加表的实际表名是 shop_addonxx,在查询时,你可能需要直接操作 this->dsql->SetQuery() 来构建更复杂的SQL,而不是仅仅依赖 this->addSql,但为了简单,我们先使用 addSql

第四步:实现三级联动(可选但强烈推荐)

上面的筛选是静态的,用户选择品牌后,系列和型号不会自动更新,要实现联动,需要用到 JavaScript (AJAX)。

  1. 准备数据源:你需要一个PHP文件来根据父级ID返回子级数据。get_filter_options.php。 这个文件需要连接数据库,查询 shop_addonxx 表,根据 brand 字段来获取唯一的 series 列表,再根据 series 来获取 model 列表。

    get_filter_options.php 示例

    <?php
    require_once(dirname(__FILE__)."/../include/common.inc.php");
    require_once(DEDEINC."/dedetpl.class.php");
    $type = isset($_GET['type']) ? trim($_GET['type']) : '';
    $value = isset($_GET['value']) ? trim($_GET['value']) : '';
    $options = array();
    $table = '你的附加表名'; // shop_addon10
    $dsql = new DedeSql(false);
    if ($type == 'series' && $value != '') {
        // 根据品牌获取系列
        $query = "SELECT DISTINCT dede_field_serie_value FROM `{$table}` WHERE dede_field_brand_value = '{$value}'";
        // 注意:字段名 dede_field_xxx_value 是DedeCMS存储自定义字段的默认格式,需要确认你的实际字段名
        // 更稳妥的写法是查询 addonfield 字段并用JSON解析
        $query = "SELECT addonfield FROM `{$table}` WHERE addonfield LIKE '%\"brand\":\"{$value}\"%'";
        $dsql->Execute('me', $query);
        while ($row = $dsql->GetArray('me')) {
            $data = json_decode($row['addonfield'], true);
            if (isset($data['serie']) && !in_array($data['serie'], $options)) {
                $options[] = $data['serie'];
            }
        }
    } elseif ($type == 'model' && $value != '') {
        // 根据系列获取型号
        $query = "SELECT addonfield FROM `{$table}` WHERE addonfield LIKE '%\"serie\":\"{$value}\"%'";
        $dsql->Execute('me', $query);
        while ($row = $dsql->GetArray('me')) {
            $data = json_decode($row['addonfield'], true);
            if (isset($data['model']) && !in_array($data['model'], $options)) {
                $options[] = $data['model'];
            }
        }
    }
    echo json_encode($options);
    exit();
    ?>
  2. 修改模板,添加JS: 在你的 list_*.htm 模板中,添加以下JS代码。

    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script type="text/javascript">
    $(document).ready(function(){
        // 品牌改变时,加载系列
        $('select[name="brand"]').change(function(){
            var brand = $(this).val();
            var seriesSelect = $('select[name="series"]');
            seriesSelect.empty().append('<option value="">加载中...</option>');
            if(brand){
                $.ajax({
                    url: '/get_filter_options.php',
                    type: 'GET',
                    data: {type: 'series', value: brand},
                    dataType: 'json',
                    success: function(series){
                        seriesSelect.empty().append('<option value="">全部系列</option>');
                        $.each(series, function(i, item){
                            seriesSelect.append('<option value="' + item + '">' + item + '</option>');
                        });
                    }
                });
            } else {
                seriesSelect.empty().append('<option value="">全部系列</option>');
            }
        });
        // 系列改变时,加载型号
        $('select[name="series"]').change(function(){
            var series = $(this).val();
            var modelSelect = $('select[name="model"]');
            modelSelect.empty().append('<option value="">加载中...</option>');
            if(series){
                $.ajax({
                    url: '/get_filter_options.php',
                    type: 'GET',
                    data: {type: 'model', value: series},
                    dataType: 'json',
                    success: function(models){
                        modelSelect.empty().append('<option value="">全部型号</option>');
                        $.each(models, function(i, item){
                            modelSelect.append('<option value="' + item + '">' + item + '</option>');
                        });
                    }
                });
            } else {
                modelSelect.empty().append('<option value="">全部型号</option>');
            }
        });
    });
    </script>

总结与注意事项

  1. 性能问题LIKE '%...%' 查询在数据量大时是性能杀手,对于正式运行的商城,强烈建议修改数据表结构,为每个筛选字段(如 brand, series, model)建立独立的数据库列,并进行索引,这样查询效率会高几个数量级。
  2. URL美化:默认的筛选URL会很长,如 .../list.php?tid=1&brand=品牌A&series=系列1,可以使用 DedeCMS 的URL重写规则或伪静态技术来美化URL,如 .../list/goods/brand/品牌A/series/系列1.html,这需要修改 arc.listview.class.php 中的 MakeHtml()GetMakeFileRule() 方法,实现较为复杂。
  3. 调试:在修改 arc.listview.class.php 时,如果遇到问题,可以在 Query() 方法里 echo $this->addSql; exit; 来打印最终生成的SQL语句,检查是否符合预期。
  4. 版本兼容性:以上代码基于较新版本的 DedeCMS 思路,如果你使用的是非常老的版本(如 5.6),文件路径和类名可能略有不同,但核心逻辑是一致的。

通过以上四个步骤,你就可以在 DedeCMS 中实现一个功能完善的三级筛选商城了,这是一个典型的二次开发案例,考验的是对 DedeCMS 数据结构和流程的理解。

-- 展开阅读全文 --
头像
C语言open和write函数如何正确使用?
« 上一篇 02-26
dede数据库文件存放在服务器哪个目录?
下一篇 » 02-26

相关文章

取消
微信二维码
支付宝二维码

目录[+]