活力39167
在线时间13434 小时
阅读权限200
管理员
自由的灵魂
- 积分
- 106811
- 主题
- 5597
- 回帖
- 26608
- 注册时间
- 2003-4-10
- 最后登录
- 2026-8-11
|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
[2026-07-09] [修复] [前台标签重复追加问题] - 修复编辑帖子时标签重复递增的Bug
1、问题缘起
论坛用户反馈,编辑帖子标签时,每次保存都会在标签列表中重复追加已有的标签。例如:
- 原标签:Editplus,查找,代码
- 第一次编辑后:EditPlus,查找,代码,EmEditor
- 第二次编辑后:EditPlus,查找,代码,EmEditor,EditPlus
- 第三次编辑后:EditPlus,查找,代码,EmEditor,EditPlus,EditPlus
每编辑一次,EditPlus 就多一个,导致标签列表越来越长。
受影响的帖子示例:tid=95930,其 dx_forum_post.tags 字段中出现了 5 次 6258,EditPlus。
2、排查过程
| 步骤 | 操作 | 结果 | | 1 | 搜索标签保存相关文件 | 定位到 forum_tag.php 和 class_tag.php | | 2 | 查看 forum_tag.php | 发现 $op == 'set' 分支调用 $class_tag->update_field() | | 3 | 查看 class_tag.php 的 update_field() | 发现逻辑是追加而非覆盖 |
关键代码定位(class_tag.php 第 55-79 行):
- public function update_field($tags, $itemid, $idtype = 'tid', $typeinfo = array()) {
- // ... 获取当前帖子已有标签 $tagstr ...
- foreach($tags as $tagid => $tagname) {
- if(empty($tagarray[$tagid])) {
- $tagstr = $tagstr.$tagid.','.$tagname."\t"; // 追加新标签
- }
- }
- // ... 删除不再使用的标签 ...
- return $tagstr;
- }
复制代码
3、解决方案
(1)简要技术分析:
Discuz! 的 update_field() 方法在更新标签时,采用了“保留旧标签 + 追加新标签”的策略,导致每次编辑都会重复写入已有标签。修复方案改为“先清空所有旧标签关联,再写入新标签列表”,实现标签的完整覆盖更新。
(2)修改文件列表:
| 操作 | 文件路径 | | 修改 | /source/class/class_tag.php |
(3)关键代码段:
修改前(update_field 方法):
- public function update_field($tags, $itemid, $idtype = 'tid', $typeinfo = array()) {
- // ... 获取已有标签 $tagstr ...
- foreach($tags as $tagid => $tagname) {
- if(empty($tagarray[$tagid])) {
- $tagstr = $tagstr.$tagid.','.$tagname."\t";
- }
- }
- foreach($tagarray as $tagid => $tagname) {
- if(!in_array($tagname, $tagarraynew)) {
- C::t('common_tagitem')->delete_tagitem($tagid, $itemid, $idtype);
- $tagstr = str_replace("$tagid,$tagname\t", '', $tagstr);
- }
- }
- return $tagstr;
- }
复制代码
修改后(完整覆盖逻辑):
- public function update_field($tags, $itemid, $idtype = 'tid', $typeinfo = array()) {
- if($idtype == 'tid') {
- $tagstr = C::t('forum_post')->fetch_threadpost_by_tid_invisible($itemid);
- $tagstr = $tagstr['tags'];
- } elseif($idtype == 'blogid') {
- $tagstr = C::t('home_blogfield')->fetch_tag_by_blogid($itemid);
- } else {
- return '';
- }
- // 删除该帖子的所有旧标签关联
- C::t('common_tagitem')->delete_tagitem(0, $itemid, $idtype);
- // 重新添加新标签
- $new_tags = $this->add_tag($tags, $itemid, $idtype, 1);
- $tagstr_new = '';
- foreach($new_tags as $tagid => $tagname) {
- $tagstr_new .= $tagid.','.$tagname."\t";
- }
- return $tagstr_new;
- }
复制代码
4、最终实现效果
| 场景 | 修改前 | 修改后 | | 编辑标签 | 每次在末尾追加已有标签 | ✅ 完整覆盖,无重复 | | dx_forum_post.tags 字段 | 不断增长 | ✅ 始终为最新标签列表 | | dx_common_tagitem 表 | 存在重复关联记录 | ✅ 无重复关联 | | 前台标签显示 | 显示重复标签 | ✅ 显示干净的唯一标签列表 |
5、重要技术沉淀
需更新到固化摘要:
- 二十六、标签重复追加修复(2026-07-09)
- 问题:编辑帖子标签时,已有标签被重复追加,导致标签列表膨胀
- 原因:update_field() 方法采用“追加”而非“覆盖”逻辑
- 解决:修改 source/class/class_tag.php 中的 update_field() 方法,先清空旧标签再写入新标签
- 涉及文件:source/class/class_tag.php
复制代码
踩坑点:
| 踩坑 | 正确做法 | | 误以为 Discuz! 标签保存是覆盖逻辑 | 实际是追加逻辑,需要修改代码 | | delete_tagitem(0, $itemid, $idtype) 参数顺序需确认 | 调用前需确认 delete_tagitem 方法的参数顺序 | | 标签字段 $tagstr 格式为 tagid,tagname\t | 重新构建时需保持相同格式,否则前台无法正确解析 |
6、进一步优化可能性
- 批量清理:编写 SQL 脚本批量清理已存在的重复标签数据
- 后台管理:在后台增加“标签去重”工具,一键清理全站重复标签
- 前端防重复:在标签输入框增加重复检测,提交前拦截重复标签
|
|