【XIUNOX插件】相关帖子 v1.0.0

管理员组

xnx_related 相关帖子

在帖子详情页展示相关帖子推荐,支持标签匹配(软依赖 xnx_tag)与标题关键词降级匹配。纯读操作不建表,结果通过 CacheHelper 缓存。Bootstrap 5 + 原生 PHP,无 jQuery 依赖。

功能特性

  • 双匹配策略:标签优先降级标题(默认)或仅标题关键词,可在后台切换
  • 标签匹配:软依赖 xnx_tag,存在时通过 TagService::findByTid() 取标签,再查 xnx_thread_tag 关联表找同标签帖
  • 标题关键词降级:标签不足或无 xnx_tag 时,从标题提取关键词做 LIKE 匹配,候选帖按命中数降序排序
  • 三种展示位置:正文与评论区之间(全宽卡片)/ 右侧栏(紧凑卡片)/ 两者都显示
  • 两种推荐范围:当前版块 / 全站
  • 三种排序:发布时间(tid 倒序)/ 回复数 / 查看数
  • 权限过滤:调用 thread_list_access_filter() 按用户组过滤版块访问权限与待审/驳回帖
  • 缓存隔离:缓存键含 gid,避免高权限用户缓存被低权限复用导致信息泄露
  • 删帖级联:删帖后自动清全量推荐缓存
  • 三语支持:zh_cn / zh_tw / en_us

安装说明

  1. 将插件目录放入 plugin/xnx_related/
  2. 进入后台「插件管理」找到「相关帖子」点击安装,自动初始化默认配置(不建表)
  3. 安装后默认启用,可在后台「插件设置」中调整

软依赖 xnx_tag

本插件对 xnx_tag 为软依赖(非强制):

  • conf.jsondependencies 为空,安装时不强制要求 xnx_tag
  • 运行时通过 class_exists('TagService', false) 检测,存在才启用标签匹配
  • 未安装 xnx_tag 或帖子无标签时,自动降级到标题关键词匹配,功能不中断
  • 标签匹配读取 xnx_tag 创建的 xnx_thread_tag 关联表

使用指南

后台配置

访问 /admin/plugin-setting-xnx_related,仅管理员组(gid=1,2)可访问,所有 POST 操作经 CsrfService::check() 校验。

| 配置项 | 字段 | 取值范围 | 默认值 | 说明 | |---|---|---|---|---| | 启用相关帖子 | enabled | 0/1 | 1 | 全局开关 | | 推荐数量 | count | 1-20 | 6 | 最终展示条数 | | 展示位置 | position | 1/2/3 | 3 | 1=正文与评论区之间 2=右侧栏 3=两者都显示 | | 推荐范围 | scope | 1/2 | 2 | 1=当前版块 2=全站 | | 匹配方式 | match_method | 1/2 | 1 | 1=标签优先降级标题 2=仅标题关键词 | | 排序方式 | sort_order | 1/2/3 | 1 | 1=发布时间 2=回复数 3=查看数 | | 新窗口打开 | new_window | 0/1 | 1 | 帖子链接 target="_blank" | | 显示版块名称 | show_forum | 0/1 | 1 | 帖子项展示所属版块(可点击跳转) | | 显示回复/查看统计 | show_stats | 0/1 | 1 | 帖子项展示回复数 | | 缓存时间 | cache_ttl | 60-86400 秒 | 3600 | 推荐结果缓存存活秒数 |

保存设置后自动清旧缓存,新配置即时生效。

前台展示

通过两个 hook 注入帖子详情页:

  • thread_postlist_before.htm:位置一,正文与评论区之间(position=13 时渲染),全宽卡片样式
  • thread_user_after.htm:位置二,右侧栏末尾(position=23 时渲染),紧凑卡片样式

卡片内每条帖子项包含:发帖人头像(调用 avatar_component_from_data,与头像组件兼容)、帖子标题(2 行截断)、用户名、版块名(可点击)、回复数。无推荐结果时不输出卡片。

技术细节

匹配算法

RelatedService::getRelated($tid, $fid, $gid) 主入口,按 match_method 分流:

1. 标签优先降级标题(match_method=1)

  • TagService::findByTid($tid) 取当前帖标签
  • findByTags() 按 tagIds 查 xnx_thread_tag 关联表(预取 limit*5 冗余),排除当前帖,scope=1 时过滤非当前版块,按 sort_order 排序
  • 结果不足 count 条时,降级到标题关键词匹配补足
  • 合并去重:标签结果优先,标题结果按 tid 去重后追加

2. 仅标题关键词(match_method=2)

  • extractKeywords() 从标题提取关键词(最多 3 个)
- 中文:正则 [\x{4e00}-\x{9fa5}]{2,} 匹配连续 2+ 汉字为一词

- 英文:正则 [a-zA-Z][a-zA-Z0-9]{2,} 匹配 3+ 字符英文词 - 过滤内置停用词表(中英文常见虚词)

  • findByKeyword() 每个关键词做一次 subject LIKE '%kw%' 查询(无法走索引)
  • 候选数达到预取量时提前退出,多数情况只查 1-2 次
  • 批量 user_preload() 预加载用户数据消除 N+1
  • 候选帖先按命中关键词数降序,再按 sort_order 排序

> 朴素分词说明:extractKeywords 是正则分词,非真正中文分词(无词典无 HMM),帖子标题这类短文本足够用;长文本或专业领域需 jieba/scws。LIKE 匹配适合 BBS 中小流量场景,复杂场景需 MySQL 全文索引或 Elasticsearch。

预取与截断

预取量 preload = count * 3,预留冗余给后续权限过滤缩减,过滤后 array_slice 截断到 count

缓存策略

  • 使用 CacheHelper(存在时启用),缓存键注册:thread_* => 3600
  • 缓存键格式 thread_{tid}_{gid},含 gid 做权限隔离
  • TTL 取配置 cache_ttl(已 clamp 到 60-86400)
  • 清缓存时机:保存设置(saveSettings)、删帖(onThreadDelete)、卸载(uninstall.php
  • 删帖采用全量清前缀策略:删帖影响所有包含该帖的推荐列表,按 tid 精确清理成本高于全量清前缀,直接全量清最简

Hook 注入点

| Hook 文件 | 作用 | |---|---| | model_inc_file.php | 注册 model/RelatedService.php 到自动加载 | | lang_zh_cn_bbs.php / lang_zh_tw_bbs.php / lang_en_us_bbs.php | 三语语言包 | | thread_postlist_before.htm | 位置一渲染(正文与评论区之间) | | thread_user_after.htm | 位置二渲染(右侧栏) | | model_thread_delete_end.php | 删帖后清缓存 |

数据表

本插件为纯读操作插件,不创建任何数据表,仅写入 setting 表的 xnx_related 配置项。

标签匹配时读取 xnx_tag 插件创建的 xnx_thread_tag(标签-帖子关联表),无独立持久化存储。

兼容性

  • Xiuno X 1.1+(bbs_version 1.1)
  • PHP 8.x(全局数组访问已加 isset 兜底)
  • Bootstrap 5(卡片、栅格、表单组件)
  • 无 jQuery 依赖
  • 软依赖 xnx_tag:未安装时自动降级为标题关键词匹配
  • 依赖 CacheHelper(存在时启用缓存,不存在时每次实时计算)

版本历史

  • 1.0.0 (2026-07-18):初始版本。支持标签匹配(软依赖 xnx_tag)与标题关键词降级匹配;三种展示位置;当前版块/全站两种范围;发布时间/回复数/查看数三种排序;CacheHelper 缓存(gid 隔离防权限泄露);三语支持;删帖级联清缓存

版本 1.0.0 | 兼容 Xiuno 1.1+



版本:v1.0.0
适用版本:1.1
开发者:Twelve

请登录后查看此内容
最新回复

请先登录后再回复 登录