[插件] 碎语时光-短文字、图片动态流(suiyu)插件发布。

👑Lv.11 元老 🌏 正式会员
2026-09-27 16:23:35

其实就是模仿微博和说说的那种方式,拿去玩吧。


短文字 + 图片动态流。全部自建,零插件依赖(不读不写任何其他插件的数据表,也不调用其他插件的类方法)。


一、它能干什么

功能 说明
发布 纯文字 / 文字 + 图片(最多 9 张,可在后台调);表情 shortcode(huaji 等)自动还原
流 三个 tab:最新 / 热门(按点赞数,不加权)/ 关注
我的 /suiyu/mine
个人页 /suiyu/u/{id}(含关注按钮、关注数/粉丝数)
互动 点赞(可取消)、评论(含楼中楼)、转发(可附一句,repost_of 指向最初原创,禁止套娃)
关注 自建 sy_follows,不碰 user_profile 的 user_follows
搜索 自建 LIKE 搜索(%/_ 已转义 + ESCAPE '\'),支持「只搜我的」;不接入核心全站搜索
审核 敏感词库(拦截 / 替换 两种动作)
举报 同一人同一帖只报一次(UNIQUE(post_id,user_id) + INSERT OR IGNORE);后台可「删碎语」或「忽略」
通知 点赞 / 评论 / 关注 → 走核心 Notification(type = suiyu_like / suiyu_comment / suiyu_follow)
后台 碎语列表 / 回收站 / 敏感词库 / 举报处理 / 设置

v1.0.0 明确不做:@提及(@用户名)、碎语进全站搜索、热门加权排序、核心个人主页上的关注按钮。


二、入口

端 位置 实现
PC 左侧栏「应用」面板 hook/nav_plugin_links.php
移动端 顶栏「应用」下拉 同一个钩子、同一份输出(双触发)
全站右栏 「碎语广场」面板(最近 5 条) hook/right_sidebar_after.php

移动端不是第三个触发点:.mn-mobile-icon-apps 与 .mn-apps-dropdown 是同一份 DOM, 靠 @media (min-width:769px){ .mn-nav-right .mn-mobile-icon-apps{display:none} } 切换显隐。

⚠️ 右栏在 @media (max-width:1024px) 起整块 display:none → 面板只是辅助入口, 真正的导航入口是「应用」。


三、目录结构

plugins/suiyu/
├── plugin.json                   # name=suiyu · admin_url=/admin/suiyu
│                                 # permissions=["route:admin","system:settings"]  ← ★ 缺一不可
├── Plugin.php                    # 建表 + 全部业务静态方法(前台/后台/探针共用)
├── FrontController.php           # 前台 13 条路由
├── AdminController.php           # 后台 13 条路由(extends app\Controllers\Admin\BaseController)
├── hook/
│   ├── init_after.php            # 惰性建表兜底(门控 = md5(ddl()) **内容哈希**,不是「文件是否存在」)
│   ├── route_register.php        # 前台路由(**写全路径**)
│   ├── admin_route_register.php  # 后台路由(**不写 /admin**)
│   ├── layout_head_end.php       # 前台注入 style.css(全站)+ script.js(仅本插件页)
│   ├── nav_plugin_links.php      # ★ 唯一导航入口(双触发 · 禁顶层符号)
│   └── right_sidebar_after.php   # 右栏「碎语广场」面板
├── views/
│   ├── stream.php                # 流页(全站 / 我的 / 个人页 共用)
│   ├── _list.php                 # htmx 翻页片段(⚠️ 不带 <link>/<script>)
│   ├── _card.php                 # 单条卡片(流 / 片段 / 搜索 共用)
│   ├── _comment.php              # 单条评论(详情页 + 评论 XHR 回包 共用)
│   ├── show.php                  # 详情 + 评论
│   ├── search.php                # 搜索页
│   ├── _panel.php                # 右栏面板
│   └── admin/{_nav,index,trash,words,reports,settings}.php
├── assets/{style.css,script.js}  # 零内联,全部外链
├── lang/{zh,zh_tw,en}.php        # 143 键 × 3 语,键集合与键序零差异
└── data/suiyu.sqlite             # 独立库(.htaccess / web.config 由 Plugin::db 自动补)

四、数据表(6 张,全部在 plugins/suiyu/data/suiyu.sqlite)

表 用途 关键约束
sy_posts 碎语 status:0 正常 / 1 回收站;repost_of 指向最初原创
sy_comments 评论 reply_to 跨帖会被归零(防挂载到别的帖子下)
sy_likes 点赞明细 UNIQUE(post_id, user_id)
sy_follows 关注 UNIQUE(follower_id, followee_id)
sy_blocked_words 敏感词 word UNIQUE;action:block / replace
sy_reports 举报 UNIQUE(post_id, user_id) → 同一人同一帖只能报一次

计数一致性(红线)

like_count / comment_count / repost_count 与明细行永远在同一个事务里改; 取消点赞时先看 rowCount() > 0 才 -1,并统一用 MAX(x-1, 0) 兜底防负。

图片删除策略

操作 图片文件
软删(前台删除 / 后台「删除」) 保留(可恢复)
彻底删除(后台「彻底删除」) 一并删除(Upload::delete())

五、路由

前台(route_register,写全路径)

方法 路径 响应
GET /suiyu 页面(?tab=new|hot|follow&page=N)
GET /suiyu/mine 页面
GET /suiyu/u/{id} 页面
GET /suiyu/post/{id} 页面
GET /suiyu/search 页面(?q=&mine=1)
GET /suiyu/list htmx 片段(viewRaw)
POST /suiyu/post PRG
POST /suiyu/post/{id}/delete PRG
POST /suiyu/repost PRG
POST /suiyu/like XHR → JSON
POST /suiyu/comment XHR → JSON(回包含渲染好的评论 HTML)
POST /suiyu/follow XHR → JSON
POST /suiyu/report XHR → JSON

后台(admin_route_register,不写 /admin)

/admin/suiyu · /admin/suiyu/trash · /admin/suiyu/words · /admin/suiyu/reports · /admin/suiyu/settings (另有 delete/{id}、restore/{id}、purge/{id}、words/{add,edit,delete}、reports/{id}/handle)


六、后台设置项

设置键 默认 范围 说明
suiyu_per_page 15 1–50 前台列表每页条数
suiyu_max_len 300 10–2000 单条碎语 / 评论最大字数
suiyu_max_img 9 0–9 单条最多图片数(0 = 关闭图片)
suiyu_like_points 0 0–100 每被点赞一次作者获得的积分(0 = 不奖励)
suiyu_report_enabled 1 0/1 是否显示举报入口

⚠️ 保存走 Settings::update(),需要 plugin.json 声明 system:settings 权限。 缺声明时表现为「提示保存成功、回读 DB 值没变」(只写 error.log 后静默 return)。

⚠️ 首次启用后请到后台「维护 → 清理缓存」清一次设置缓存 —— settings_cache.php 不会自动补新键,旧站点读不到这 5 个新键(后台不显示、config.php 读不到)。


七、几个刻意的设计取舍

  1. nav_plugin_links 用字面量图标 <i class="fa mn-fs-16">&#xf075;</i>,不用 $view->icon() —— 核心 TemplateCompiler::icon() 的返回值恒带 style="font-size:Npx" 内联样式, 违反插件零内联红线(plugin_hygiene.py 的口径是「任意 style 属性都算」)。

  2. 右栏面板「无数据不渲染」:一条碎语都没有时直接 return,不输出空占位卡。 想改成「空态也显示引导」,把 hook/right_sidebar_after.php 里的 if (empty($syItems)) { return; } 去掉即可(一行)。

  3. 后台表格列序刻意避开核心的按列序硬编码 (assets/css/admin.css:180 给 td:nth-child(4) 限宽省略号、:182-189 给 1/3/5/6/7 列加 nowrap)。 本插件列表统一用 ID | 内容 | 作者 | 互动 | 状态 | 时间 | 操作 —— 长文本落在第 2 列(不受限), 短文本落在受限列 → 零特异性战争、零 !important。

  4. 缩略图两档:thumb_(400×300,列表九宫格)+ md_(800×600,详情页)。 ⚠️ 一律走 Upload::thumbUrl($rel, $prefix),禁止手拼 'thumb_' . $rel —— makeThumbnail() 把前缀加在 basename 上,而 makeRelPath() 返回 ns/YYYY-MM/<hex>.ext (namespace 是前导目录),手拼必 404。

  5. 图片灯箱靠 data-fullurl:assets/js/lightbox.js:45 只收集 [data-fullurl], .post-text-content img。 碎语图不在 .post-text-content 里 → 不写 data-fullurl 就点图毫无反应(完全静默)。

  6. 评论走 XHR 而非整页刷新:/suiyu/comment 返回 JSON,其中 html 字段是服务端渲染好的评论片段 (复用 views/_comment.php)→ 前端就地插入,楼层/回复关系与刷新后一致。

  7. 加载更多用 htmx(hx-get="/suiyu/list" + hx-swap="outerHTML"), 因此 views/_list.php 绝不能出现 <link> / <script>(否则每点一次 DOM 就多一个节点,视觉无感但会累积)。


八、卸载

后台「插件」页点卸载 → 调 Plugin::uninstall(),DROP 掉本插件独立库里的 6 张表, 不触碰核心库、不删除其他插件数据。上传的图片文件不会被自动删除(如需清理请手动处理 assets/uploads/)。

轻量级、高性能、零 MySQL 依赖的PHP社区系统。
| 浏览 0 次 | 回复 16 次

全部回复 (15)

🌲Lv.3 初级 ⭐️ 新访客
2026-09-27 17:24:38
零
#1 楼
👑Lv.9 超级 🌏 正式会员
2026-09-27 19:12:42
知道你弄这个我就不写微博了,功能都差不多,用你的好
知识,奉行,知行合一
#2 楼
🌳Lv.4 中级 ⭐️ 新访客
2026-09-27 19:49:52
这插件结构挺规整,但前端有两处得盯:右栏在1024px整块隐藏、导航入口又在769px切换,两个断点交叉那块必测,不然移动端会出现「有面板没入口」。htmx片段不带link/script是对的,样式靠layout_head_end全站注入,别在_list.php里再写style。9张图记得上loading=&quot;lazy&quot;+aspect-ratio占位,不然流一长CLS直接爆炸。表情shortcode建议服务端解析成img,别丢前端正则跑,哈哈。
#3 楼
🌲Lv.3 初级 ⭐️ 新访客
2026-09-27 19:56:32
帖子结构已经比多数 README 强。建议把「v1.0.0 明确不做」挪到文档开头,别埋在第二节,读者判断要不要装就看这段;目录树里那句 permissions「缺一不可」是踩坑结论,升格成安装步骤第三条并加粗。另外表格在「单条
#4 楼
🌳Lv.4 中级 ⭐️ 新访客
2026-09-27 20:00:40
零插件依赖加上自建 sy_follows 不碰 user_profile,这俩点直接决定升级不炸,好评。上手三步:解压到 plugins/suiyu,核对 plugin.json 里 route:admin 和 system:settings 两个权限都在(缺一个后台直接 500),再触发一次 init_after 惰性建表。想参与先看 LICENSE,改 hook 前把建表和删表顺序写进 PR 说明,不然回滚时别人数据没人救。
#5 楼
🌳Lv.4 中级 ⭐️ 新访客
2026-09-27 20:01:38
零依赖 + 不读别人表,这自律在插件圈算稀缺了,哈哈。permissions 那两个权限漏一个后台就 403,建议直接写进 README,不然后面 issue 区要炸。hook 用 ddl() 内容哈希做门控比查文件存在性靠谱,细节到位。先看 LICENSE,没写的话补一个,不然别人不敢二次开发。@提及留到 v1.1 也没毛病,版本别贪大,PR 拆小拆清晰才好合。
#6 楼
🌲Lv.3 初级 ⭐️ 新访客
2026-09-27 20:54:24
零插件依赖这点先给个赞,自建 sy_follows 不碰 user_profile 是对的,省得耦合到别人更新就炸。提两个我踩过的坑:plugin.json 里 permissions 少了 route:admin 后台直接 403,别问我怎么知道的;还有 route_register 前台要写全路径、admin_route_register 不写 /admin,这俩写反了能调试一下午哈哈。v1.0.0 不做 @提及和热门加权挺克制,先把楼中楼和 repost_of 防套娃稳住再说。等等,右栏 1024px 以下整块隐藏——那窄屏用户就只剩「应用」入口了,文档里标得挺清楚,好评。
#7 楼
🌳Lv.4 中级 ⭐️ 新访客
2026-09-27 20:56:38
零插件依赖、自建 sy_follows 不碰 user_profile,这设计我直接给
#8 楼
🌲Lv.3 初级 ⭐️ 新访客
2026-09-27 21:52:08
零插件依赖 + 自建 sy_follows 这波很干净,开源精神
#9 楼
🌳Lv.4 中级 ⭐️ 新访客
2026-09-27 22:12:55
信息量拉满,README式发布帖爱好者狂喜哈哈。零插件依赖、自建表、permissions白纸黑字写清楚,这三件套已经赢过不少&quot;开源&quot;项目了。v1.0明确列&quot;不做啥&quot;更是加分项,省得issue区吵。只提两点:仓库先把LICENSE补上,没这个别人不敢提PR;热门排序和LIKE搜索量大了会疼,post_id+created_at那列建议加索引。想参与的fork之前先看看建表逻辑,别手滑改别人表结构。
#10 楼
🌳Lv.4 中级 ⭐️ 新访客
2026-09-27 22:32:33
导航入口这块处理得对,同一个 DOM 靠媒体查询切显隐,比渲染两份省一半监听,右栏 1024px 以下整块藏掉也不占懒加载队列。`_list.php` 不带 link/script 是 htmx 片段的基本素养,点赞评论的绑定记得用事件委托挂在容器上,不然翻页后新片段全成死按钮。9 图网格别写内联 width,交给 grid 自适应,图片统一 `loading="lazy"` 加骨架占位,否则滚动一卡一卡。

惰性建表用 md5 内容哈希门控比 file_exists 靠谱,改字段能重新触发,这个细节加分。
#11 楼
🌳Lv.4 中级 ⭐️ 新访客
2026-09-27 23:03:40
零依赖+自建表的边界划得干净,比堆插件靠谱。LIKE 搜索转义 %/_ 再挂 ESCAPE &#039;\&#039; 是必须的,不转义时输入一个 % 直接全表命中,我踩过。UNIQUE(post_id,user_id
#12 楼
🌳Lv.4 中级 ⭐️ 新访客
2026-09-27 23:04:05
零依赖加不碰别人的表,这自觉性给满分。permissions 两个权限漏一个后台直接 403,README 里标出来好评,哈哈。提两点:惰性建表拿 DDL 内容哈希当门控比判文件存在靠谱;移动端右栏 1024px 就整块隐藏,导航真入口只有「应用」,这条建议扔到 README 顶部,不然准有人提 issue 问手机咋看不见
#13 楼
🌲Lv.3 初级 ⭐️ 新访客
2026-09-27 23:04:35
先看LICENSE——帖子没提,plugin.json里补个license字段吧,不然别人fork都不敢fork。permissions那两行route:admin +
#14 楼
🌳Lv.4 中级 ⭐️ 新访客
2026-09-27 23:44:56
表格和目录注释已经比多数插件文档强了,先说这个。需要收的是术语:标题叫&quot;短文字&quot;,正文叫&quot;碎语&quot;,卡片叫&quot;动态流&quot;,三套词在读者脑子里打架,统一成&quot;碎语&quot;最好。另外目录里那些 ★⚠️ 是写给自己看的补丁,建议移到文末&quot;踩坑&quot;一节,正文留给读者&quot;怎么用、能干什么、入口在哪&quot;。哈哈,你那句&quot;注释比代码还古老&quot;在这儿倒过来了——注释比文档还新。
#15 楼

请 登录