官方不提供现金交易,线下交易风险自担,请仔细鉴别!
xnx_private_reply 楼主可见插件
> 楼主可在发帖时一键开启"回复仅楼主可见",开启后只有楼主、回复作者本人、管理员/版主能看到回复内容。
功能特性
- 发帖页开关注入:在发主题帖页右侧栏注入"回复仅楼主可见"开关(仅在
thread-create路由显示,回帖/编辑场景不显示) - 角色化可见性过滤(精准私信式):
- 管理员/版主(admin_bypass=1 时):可见全部回复 - 已登录非特权用户: - 一级评论(postlist):仅可见自己发的(楼主的一级评论对他人不可见) - 楼中楼(reply_map):可见「自己发的」+「楼主针对自己的回复」(reply.uid === 楼主 && reply.reply_to_uid === 自己),形成私信式双向对话 - 其他用户之间的回复一律不可见 - 游客:回复列表清空,显示"该帖回复仅楼主可见"提示卡片
> 设计动机:开启「回复仅楼主可见」后,若楼主回复某用户但该用户看不到,对话完全断开。精准私信式让被回复者能看到楼主针对自己的回应,既保持"用户之间回复互不可见"的核心目的,又让楼主与回复者的对话有意义。
- 回复计数保留:
$thread['posts']保持真实值不变,仅前端列表过滤 - 多视图徽章:帖子列表 4 视图(默认 / masonry / timeline / card)显示"楼主可见"徽章
- 删帖级联清理:删除主题时自动清理
bbs_xnx_private_reply记录 - N+1 防护:列表页徽章使用
static缓存 + 批量查询,单页仅 1 次 IN 查询 - 缓存策略:单帖开关状态走
CacheHelper::remember,TTL 86400 秒,写操作清整个插件前缀
环境要求
- Xiuno X
bbs_version: 1.1 - PHP 7.2+(需支持闭包)
- MySQL 5.7+ / MariaDB 10.3+
- 依赖核心
CacheHelper类(可选,不可用时回退直查)
安装与卸载
安装
- 将本目录上传至
plugin/xnx_private_reply/ - 后台 → 插件管理 → 找到「楼主可见」→ 点击「安装」
- 安装脚本会自动:
bbs_xnx_private_reply
- 写入默认设置到 setting_get('xnx_private_reply')
卸载
后台 → 插件管理 → 「楼主可见」→ 「卸载」,将自动:
- 删除
bbs_xnx_private_reply数据表 - 删除
xnx_private_reply设置项
> 卸载不会删除已发布的主题帖,仅清理开关记录与设置。
后台设置
访问路径:admin/?plugin-setting-xnx_private_reply.htm
权限要求:gid IN (1, 2)(管理员 / 超级版主)
| 配置项 | 字段名 | 默认值 | 说明 | |---|---|---|---| | 启用楼主可见功能 | enabled | 1 | 全局开关,关闭后发帖页不显示开关 | | 管理员/版主可见全部回复 | admin_bypass | 1 | 开启后管理员和版主不受楼主可见限制 | | 默认开启 | default_on | 0 | 开启后发帖页开关默认勾选 | | 在帖子列表显示徽章 | show_list_badge | 1 | 开启后帖子列表显示"楼主可见"徽章 | | 允许开启的用户组 | allow_groups | [] | 多选;空表示所有用户组均可开启 |
> 管理员(gid=1)和超级版主(gid=2)始终允许开启,不受 allow_groups 限制。
数据结构
数据表 bbs_xnx_private_reply
| 字段 | 类型 | 说明 | |---|---|---| | id | int unsigned PK AUTO_INCREMENT | 主键 | | tid | int unsigned UNIQUE | 主题 tid,每主题一条记录 | | author_uid | int unsigned | 楼主 uid(索引) | | created | int unsigned | 开启时间戳 |
设置存储
- 键名:
xnx_private_reply - 存储:
setting_get('xnx_private_reply')返回数组
缓存键
- 单帖开关状态:
p_xnx_private_reply_enabled_{tid}(TTL 86400 秒) - 清理:写操作调用
CacheHelper::pluginDeletePrefix('xnx_private_reply')清整个插件前缀
文件结构
xnx_private_reply/
├── conf.json # 插件元信息
├── icon.png # 插件图标
├── install.php # 安装脚本(建表 + 默认设置)
├── uninstall.php # 卸载脚本(删表 + 删设置)
├── setting.php # 后台设置页路由
├── update.md # 更新日志
├── README.md # 本文档
├── hook/ # Hook 文件(13 个)
│ ├── model_inc_file.php # 注册 Service 到 model 加载列表
│ ├── post_ref_thread_after.htm # 发帖页右侧栏开关注入
│ ├── thread_create_thread_end.php # 创建主题后保存开关状态
│ ├── thread_info_end.php # 详情页过滤回复可见性
│ ├── post_list_inc_start.htm # 详情页"仅楼主可见"提示卡片
│ ├── thread_list_inc_subject_after.htm # 默认列表视图徽章
│ ├── thread_list_masonry_subject_after.htm # masonry 视图徽章(预留)
│ ├── thread_list_timeline_subject_after.htm # timeline 视图徽章(预留)
│ ├── thread_list_card_subject_after.htm # card 视图徽章(预留)
│ ├── model_thread_delete_end.php # 删帖级联清理
│ ├── lang_zh_cn_bbs.php # 简体中文语言包
│ ├── lang_zh_tw_bbs.php # 繁体中文语言包
│ └── lang_en_us_bbs.php # 英文语言包
├── model/
│ └── PrivateReplyService.php # 核心服务类
└── view/htm/
└── setting.htm # 后台设置页模板
Hook 列表
| Hook 文件 | 类型 | 宿主 | 作用 | |---|---|---|---| | model_inc_file.php | model 层 | model.inc.php | 注册 PrivateReplyService 到 _include() 加载列表 | | post_ref_thread_after.htm | 视图层 | post.htm | 发帖页右侧栏注入开关卡片 | | thread_create_thread_end.php | 路由层 | route/thread.php | 创建主题后保存开关状态 | | thread_info_end.php | 路由层 | route/thread.php | 详情页过滤 postlist 与 reply_map | | post_list_inc_start.htm | 视图层 | post_list.inc.htm | 评论区前显示"仅楼主可见"提示卡片 | | thread_list_inc_subject_after.htm | 视图层 | thread_list.inc.htm | 默认列表视图徽章(带 static 批量预加载) | | thread_list_masonry_subject_after.htm | 视图层 | masonry 视图 | masonry 视图徽章(预留,核心暂无此 hook 标记) | | thread_list_timeline_subject_after.htm | 视图层 | timeline 视图 | timeline 视图徽章(预留) | | thread_list_card_subject_after.htm | 视图层 | card 视图 | card 视图徽章(预留) | | model_thread_delete_end.php | model 层 | thread.func.php | 删除主题时级联清理开关记录 | | lang_zh_cn_bbs.php | 语言 | lang/zh-cn/bbs.php | 简体中文 | | lang_zh_tw_bbs.php | 语言 | lang/zh-tw/bbs.php | 繁体中文 | | lang_en_us_bbs.php | 语言 | lang/en-us/bbs.php | 英文 |
Service API
PrivateReplyService 提供以下静态方法:
| 方法 | 说明 | |---|---| | getSettings() | 读取插件设置(带旧配置兼容与 allow_groups 类型规范化) | | saveSettings(array $arr) | 保存设置并清缓存 | | isEnabledForThread(int $tid) | 判断 tid 是否开启楼主可见(带缓存) | | getEnabledTids(array $tids) | 批量查询开启楼主可见的 tid 列表(列表页徽章用) | | enableForThread(int $tid, int $uid) | 开启楼主可见(幂等) | | deleteByTid(int $tid) | 删除楼主可见开关 | | canUserEnable(int $uid, int $gid) | 判断用户是否允许在发帖时开启 | | canViewAllReplies(array $thread, int $uid, int $gid) | 判断当前访问者是否可见全部回复 | | filterPostlist(&$postlist, &$reply_map, $thread, $uid, $gid) | 按引用过滤回复列表 | | clearAllCache() | 清理本插件全部缓存 | | clearThreadCache(int $tid) | 清理某 tid 的开关缓存 |
设计决策
| 决策点 | 选择 | 理由 | |---|---|---| | 开关粒度 | 主题级 | 用户需求明确,简化实现 | | 可见范围 | 楼主 + 回复作者 + 管理员/版主 + 被楼主回复的用户 | 与 xnx_hidden 一致 + 私信式对话闭环 | | 楼主回复可见性 | 精准私信式 | 楼主针对某用户的回复只让该用户可见,避免无差别披露 | | 楼主一级评论 | 仅楼主自己和管理员可见 | 一级评论无明确 reply_to_uid,按最严格披露原则 | | 父级 post 不可见时 | reply_map 整组丢弃 | 依附渲染结构(reply_map[父pid]),父级不显示则子级无法渲染 | | 回复计数 | 保持真实值 | 满足"回复计数正常显示"需求 | | 列表徽章 | 4 视图注册(含预留) | 与 xnx_hidden 一致,未来核心添加视图自动生效 | | 过滤点 | thread_info_end.php | postlist 与 reply_map 均已就绪 | | 提示卡片位置 | post_list_inc_start.htm | 评论区 <ul> 内首行,比 thread_end.htm(layout 之后)更合理 |
Non-Goals(v1 不做)
- 不支持回复级开关(仅主题级)
- 不支持指定用户可见
- 不集成通知系统(复用核心通知即可)
- 不处理搜索 / RSS 权限过滤
兼容性
- 与
xnx_hidden(回复隐藏)插件无冲突:本插件在thread_info_end.php过滤回复,xnx_hidden 在post_format阶段过滤,两者互不影响 - 与
xnx_status、xnx_feeds等动态类插件无冲突:本插件不修改帖子内容,仅过滤回复列表 - 列表页徽章使用
static批量预加载,对帖子列表性能无显著影响
开发约定
- 所有 hook 文件禁止使用
return;(hook 内联编译到宿主,return会终止宿主);终止性操作允许exit但必须注释说明 - Service 类通过
hook/model_inc_file.php注册到_include()编译加载,确保// hook标记能被识别 - 修改
hook/*.htm后需清tmp/view_htm_<宿主视图名>.htm编译缓存 - 修改
hook/*.php后需清tmp/route_<宿主>.php或tmp/model_<宿主>.func.php编译缓存 - 批量清理:
rm -f tmp/route_.php tmp/model_.func.php tmp/view_htm_*.htm
版本
- 当前版本:
1.0.0 - 兼容 Xiuno X:
1.1 - 作者:twelve
更新日志详见 update.md。
版本 1.0.0 | 兼容 Xiuno 1.1+