- 修改默认的字段类型:将普通的表单字段改为联动类型。
- 自定义联动的数据源:根据你的业务需求,创建专属的联动数据。
- 在前台调用联动数据:在文章列表、内容页或搜索表单中,展示和利用这些联动数据。
下面我将分步、详细地讲解整个二次开发流程。

第一步:理解联动类别的工作原理
在开始开发前,我们先搞清楚 DedeCMS 联动类别的核心组成部分:
-
dede_sys_enum表:这是联动类别的数据表,它存储了所有联动类目的具体数据。evalue:值,如 "110000"(北京市)。ename:显示名称,如 "北京市"。eorder:排序,数字越小越靠前。enumtype:联动类别标识,这是关键!所有属于同一个联动的数据,enumtype都是一样的,所有中国省份数据的enumtype可能都是 "shengfen"。pisnull:是否为父级。0表示不是(即子级),1表示是(即父级,如省份)。
-
后台管理路径:
后台菜单 -> 核心 -> 联动类别,在这里你可以创建、编辑、删除联动类别,并为其数据,每创建一个联动类别,系统都会生成一个唯一的enumtype。 -
前台模板调用标签:
{dede:global name='listitem.linkage'/},这个标签主要用于搜索表单中,生成一个联动选择的下拉菜单。
(图片来源网络,侵删) -
数据存储:当你在模型中添加一个“联动类型”的字段(如
shengshi),提交文章后,选中的联动值(如 "110000")会存储在文章附加表(如dede_addonarticle)的对应字段中。
第二步:创建自定义联动类别(数据源)
假设我们要做一个“汽车品牌-车系”的联动。
- 登录 DedeCMS 后台。
- 进入 核心 -> 联动类别。
- 点击 [增加联动类别]。
- 类别名称:填写
汽车品牌。 - 类别目录:系统会自动生成一个英文标识,如
car_brand,这就是我们上面提到的enumtype,你可以修改,但建议使用有意义的英文。 - 是否开启:选择“是”。
- 设置项:这里可以设置每一级选择的名称,比如第一级叫“选择品牌”,第二级叫“选择车系”。
- 类别名称:填写
- 点击 [保存]。
- 现在进入 [数据管理] 标签页。
- 在“请选择类别”下拉框中,选择你刚刚创建的
汽车品牌。 - 开始添加数据:
- 第一级(品牌):
evalue:1,ename:宝马,eorder:1,pisnull:1(注意,这里是1,表示它是父级)evalue:2,ename:奔驰,eorder:2,pisnull:1
- 第二级(车系):
evalue:101,ename:3系,eorder:1,pisnull:0(注意,这里是0,表示它不是父级,并属于父级evalue为1的项)evalue:102,ename:5系,eorder:2,pisnull:0evalue:201,ename:C级,eorder:1,pisnull:0evalue:202,ename:E级,eorder:2,pisnull:0
- 第一级(品牌):
- 在“请选择类别”下拉框中,选择你刚刚创建的
- 保存数据,现在你的
dede_sys_enum表里就有了汽车品牌和车系的联动数据。
第三步:在内容模型中添加联动字段
现在我们需要让用户在发布文章时可以选择这个联动。
- 进入 后台 -> 核心 -> 内容模型管理。
- 选择你要修改的模型(通常是“文章模型”),点击 [字段管理]。
- 点击 [增加字段]。
- 字段名:
car_brand(必须为英文,与数据库字段名一致)。 - 字段标识:
汽车品牌(后台显示的名称)。 - 字段类型:联动类型。
- 联动类型:在下拉框中选择你刚刚创建的
汽车品牌。 - 是否显示在发布页:选择“是”。
- 其他选项:如默认值、是否必填等,根据需要设置。
- 字段名:
- 点击 [保存],系统会提示你更新表结构,点击“是”即可。
去发布一篇文章,你就会在表单中看到一个“汽车品牌”的联动选择了。

第四步:前台调用与显示(核心二次开发)
这是最关键的一步,分为两种情况:
在文章列表页或内容页显示已选择的联动名称
假设你在文章中选择了“宝马”的“3系”,数据库里存的是 101,但你不想显示 101,想显示 “宝马 3系”。
方法:使用自定义函数
-
编写函数: 在你网站的
include/目录下新建一个文件,my_functions.php,然后在里面写一个函数来获取联动名称。// 文件路径: /include/my_functions.php function getLinkageName($value, $enumtype) { if (empty($value) || empty($enumtype)) { return ''; } global $dsql; $row = $dsql->GetOne("SELECT ename FROM `dede_sys_enum` WHERE evalue = '{$value}' AND enumtype = '{$enumtype}'"); if (is_array($row)) { return $row['ename']; } else { return $value; // 如果没找到,就返回原始值 } } -
引入函数文件: 在你需要调用这个函数的模板文件(如
article_list.htm或article_article.htm)的最开头,加入以下代码:{dede:global name='env/include'} <script language="javascript" src="{dede:global name='cfg_phpurl'/}/img/js/jquery.js"></script> {/dede:global} {dede:include filename='my_functions.htm'/}注意:更好的做法是在
/include/common.inc.php中引入,但为了不修改核心文件,在模板中引入更安全,你需要创建一个/include/my_functions.htm文件,里面只有一行:require_once(DEDEINC.'/my_functions.php'); -
在模板中使用函数: 假设你的联动字段名是
car_brand,联动类型enumtype是car_brand,在模板中这样调用:<p> 汽车品牌:{dede:field name='car_brand' function="getLinkageName(@me, 'car_brand')"/} </p>@me是 DedeCMS 模板引擎的当前变量值,在这里就是数据库存的101。function="getLinkageName(@me, 'car_brand')"的意思是,把@me(即101) 和'car_brand'作为参数,传给getLinkageName函数。- 最终前台就会显示 “3系”,如果你需要显示父级名称(品牌),你需要写一个更复杂的函数来递归查找。
制作一个基于联动的搜索表单
你想让用户在前台通过选择“品牌”和“车系”来筛选文章。
-
准备模板: 在你的搜索表单模板(如
search.htm)中,加入以下代码:<form name="formsearch" action="{dede:global name='cfg_phpurl'/}/search.php"> <input type="hidden" name="kwtype" value="0" /> <!-- 品牌联动选择 --> <select name="car_brand" id="brand_select" onchange="GetCarSeries(this.value)"> <option value=''>请选择品牌</option> {dede:global name='listitem.linkage'/} </select> <!-- 车系联动选择,初始为空 --> <select name="car_series" id="series_select"> <option value=''>请先选择品牌</option> </select> <input type="submit" value="搜索" /> </form> -
编写 JavaScript: 你需要一个 JS 函数来实现“选择品牌后,动态加载对应车系”的效果,将这段 JS 代码放在你模板的
<head>标签内或底部。function GetCarSeries(pid) { // 如果pid为空,清空车系下拉框并返回 if (pid == '') { document.getElementById('series_select').innerHTML = '<option value="">请先选择品牌</option>'; return; } // 创建XMLHttpRequest对象 var xmlhttp = null; if (window.XMLHttpRequest) { xmlhttp = new XMLHttpRequest(); } else if (window.ActiveXObject) { xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); } if (xmlhttp != null) { // 设置回调函数 xmlhttp.onreadystatechange = function() { if (xmlhttp.readyState == 4) { // 4 = "loaded" if (xmlhttp.status == 200) { // 200 = "OK" // 将返回的HTML设置到车系下拉框中 document.getElementById('series_select').innerHTML = xmlhttp.responseText; } else { alert("Problem retrieving data:" + xmlhttp.statusText); } } }; // 发送请求 // 注意:这里 /plus/linkage.php 是DedeCMS的联动接口 // &linkageid=1 是你创建的联动类别的ID,可以在后台联动类别列表看到 // &pid= 是要查询的父级ID xmlhttp.open("GET", "/plus/linkage.php?linkageid=1&pid=" + pid, true); xmlhttp.send(null); } } -
联动接口
/plus/linkage.php: 这个文件是 DedeCMS 自带的,专门用于处理联动 AJAX 请求的,它会根据你传的linkageid和pid,返回对应子级的 HTML<option>代码。 -
修改搜索程序: 打开
/plus/search.php文件,找到处理搜索参数的地方(通常是$keyword和$typeid附近),增加对你自定义联动字段的判断。// 在 search.php 中找到类似这样的代码段 if($typeid!='') { $typeid = GetSonIds($typeid); } // 增加你的联动字段处理逻辑 $car_brand = isset($car_brand) && is_numeric($car_brand) ? $car_brand : ''; $car_series = isset($car_series) && is_numeric($car_series) ? $car_series : ''; // 然后在构建SQL查询时,将这些条件加入 $addquery = " WHERE arc.arcrank > -1 "; if ($car_series != '') { // 如果精确搜索车系 $addquery .= " AND arc.addtable LIKE '%dede_addonarticle%' AND (SELECT car_brand FROM dede_addonarticle WHERE aid=arc.id) = '{$car_series}' "; } elseif ($car_brand != '') { // 如果只搜索了品牌 $addquery .= " AND arc.addtable LIKE '%dede_addonarticle%' AND (SELECT car_brand FROM dede_addonarticle WHERE aid=arc.id) LIKE '{$car_brand}%' "; } // ... 后续的SQL构建逻辑注意:上面的SQL是示例,实际编写时要注意SQL注入风险,并确保你的附加表名和字段名正确,更健壮的方式是使用
$dsql->SetQuery()和$dsql->Execute()来构建和执行查询。
总结与注意事项
- 备份数据:在进行任何二次开发,特别是修改数据库和核心文件之前,务必备份数据库和网站文件。
- 命名规范:字段名、
enumtype等尽量使用有意义的英文,方便后期维护。 - 性能考虑:频繁查询
dede_sys_enum表可能会影响性能,对于高频访问的数据,可以考虑将联动数据缓存到数组或文件中。 - 版本差异:不同版本的 DedeCMS(如 5.7、5.8)可能在文件路径或函数细节上略有不同,请根据你的实际版本进行调整。
- 模块化开发:对于复杂的联动(如三级、四级),建议将 JS 逻辑和 PHP 逻辑封装成可复用的模块,而不是在每个地方都写一遍。
通过以上步骤,你就可以熟练地对 DedeCMS 的联动类别进行二次开发,满足各种复杂的业务需求了。
