[开发]右侧栏改造方案(2026-09-27)

👑Lv.11 元老 🌞 骨干会员
2026-10-26 01:56:45

本文由 FlintHub 开发文档归档发布。原始文档日期见标题前缀,来源:WWW/docs/右侧栏改造方案_2026-09-27.md。

右侧栏改造方案(2026-09-27)

状态:方案已定稿(2026-09-27),代码未动 —— 等开工指令。

需求来源:站长口述 6 条,6 项决策已全部拍板(见 §四)

涉及面:核心视图 app/Views/_components/right_sidebar.php、核心样式 assets/css/modern.css、

插件 plugins/daily_checkin/*、规范 docs/插件开发规范.md

⚠️ 本次必须改核心视图,与之前"只改 plugins"的口径不同 —— 见 §五。


〇、一句话结论

把「签到」从核心视图里彻底摘出来,改成签到插件自己挂右栏钩子输出;核心只留「个人信息 + 发帖」两个等宽按钮,

并在它们上方开一个 2 列网格的通用钩子(钩子A = right_sidebar_user_actions_above)给"日常常用操作"类插件用。

用户栏下方、同级的面板挂载点复用已有的 right_sidebar_after(决策 6 选①,零核心改动)。

改完,核心 right_sidebar.php 里不再出现 daily_checkin 任何字样。


一、现状:耦合到底长什么样(实测证据)

1.1 核心里对签到插件的 3 处硬编码

#位置内容
1app/Views/_components/right_sidebar.php:182$this->include('plugins/daily_checkin/_sidebar');
2app/Views/_components/right_sidebar.php:187-193#checkinHint 提示行(含 I18n::get('plugin.daily_checkin.msg_success_persist'))
3app/Views/_components/right_sidebar.php:191I18n::get('plugin.daily_checkin.title') / .subtitle

app/Views/home/index.php:121 也出现 daily_checkin 字样,但那是首页「插件介绍」的静态营销文案(<code>daily_checkin</code> + 中文名),不是代码耦合,本次不动。

1.2 未装 / 未启用签到插件时的两个可见症状

站点上没有 daily_checkin 目录(或 plugin.json 里 activated: false)时:

症状 A —— 按钮位空一格

right_sidebar.php:182 的 include() 走 TemplateCompiler::include()(app/Core/TemplateCompiler.php:284):

public function include($template, $extra = [])
{
    $data = array_merge($this->data, $extra);
    $r = $this->resolveTemplate($template);
    if (!$r) return;            // ← 模板不存在 → 静默 return,不报错、不写日志
    ...
}

→ 插件目录不存在时这里什么都不输出,.mn-user-actions 里只剩「个人信息」一个按钮(它带 mn-flex-1,会被拉满整行)。

症状 B —— 吐出一行键名(这才是真正的"显示问题")

right_sidebar.php:185-194 的 #checkinHint 区块完全没有 Plugin::isActivated() 门控,无条件渲染,

而它要的 i18n 键只存在于插件语言包里:

  • app/Helpers/I18n.php:58-71 mergePluginLangs() → if (empty($cfg['activated'])) continue; → 未启用插件的语言包根本不合并
  • 核心 lang/.php 里没有 plugin.daily_checkin. 任何键(已 grep 确认)
  • I18n::get()(app/Helpers/I18n.php:143-153)缺键时 return $key;("永不白屏"设计)

结果:右栏用户卡下方多出一条分隔线 + 一行灰色小字,内容是原文键名:

plugin.daily_checkin.title · plugin.daily_checkin.subtitle

1.3 两个独立机理,别混为一谈

机理触发条件表现
模板解析失败静默插件目录不存在按钮位空白(少一个按钮)
i18n 键缺失吐键名插件存在但 activated:false,或目录不存在提示行显示 plugin.daily_checkin.title · plugin.daily_checkin.subtitle

两者可单独出现、也可同时出现。解耦后两者一起消失 —— 因为未启用插件的钩子压根不执行(见 §3.1)。


二、改造总览(改前 / 改后)

改前

[用户卡]  头像 + 名字 / 加入日期
          积分 │ 主题
          [ 个人信息 ] [ 签到 ]          ← 第 2 格 = 核心硬编码 include 签到插件
          ─────────────────────────
          获得 2 积分,已连续签到 3 天     ← 无门控;未装插件时吐键名
──────────────────────────────────────
[right_sidebar_after 钩子]               ← 现被 dice / qa / quiz_duel 占用
[站点统计]
[热门标签]
[sidebar_above_friend_links 钩子]        ← 排行榜 + 最新会员
[友情链接]

改后

[用户栏 .mn-panel]  头像 + 名字 / 加入日期
                    积分 │ 主题
                    ┌─ 钩子A 常用操作(新,每行 2 列)─┐
                    │ [我的收藏] [我的帖子]           │
                    │ [消息]     [草稿箱]             │
                    └─────────────────────────────────┘
                    [ 个人信息 ] [ 发帖 ]             ← 等宽;核心写死,零插件依赖
                    ← 用户栏  结束(卡片内部到此为止)
────────────────────────────────────────────────────
[钩子B 用户栏下方 · 同级]   ← 本次新增;插件挂独立 mn-panel,与用户栏同级
[站点统计]
[热门标签]
[排行榜 + 最新会员]
[友情链接]

钩子A 与钩子B 分居用户栏内外,职责不同

- 钩子A(用户栏内部、按钮上方)→ 给"日常常用操作",核心强制 2 列网格,保证整齐。

- 钩子B(用户栏外部、与用户栏同级)→ 给"独立面板",插件自己输出完整 <div class="mn-panel">,形态与排行榜 / 最新会员 / 站点统计一致。

✅ 决策 6 已定:钩子B 复用已有的 right_sidebar_after(right_sidebar.php:210,规范 §9 #14,

注释原文"右栏通用钩子:用户信息面板之后,供插件注入侧栏面板"),不新增钩子位。

现有占用者 dice(停用)/ qa(启用,只认 /qa*)/ quiz_duel(停用)→ 实际零冲突;

先后顺序由各插件 plugin.json 的 sort_order 控制。


三、逐条方案

需求① 把右侧栏的签到解耦

核心侧(删)

  • 删 right_sidebar.php:182 —— $this->include('plugins/daily_checkin/_sidebar');
  • 删 right_sidebar.php:185-194 —— 整个 #checkinHint 区块(含外层 if (!$isBlogPage))

插件侧(加)

  • 新增 plugins/daily_checkin/hook/right_sidebar_after.php
  • plugin.json 的 hooks 增 "right_sidebar_after": "hook/right_sidebar_after.php"(按需加 sort_order)

为什么选 right_sidebar_after

  • 钩子 #14(docs/插件开发规范.md:674),触发点 right_sidebar.php:210,无参数、单触发、PC 右栏;

位置正好在用户面板之后、站点统计之前 → 就是"用户信息栏的下方"。

  • Plugin::hook()(app/Helpers/Plugin.php:604-658)第 609 行 if (empty($config['activated'])) continue;

→ 未启用插件的钩子根本不执行 → 未装/未启用时零输出,§1.2 两个症状一起消失。

  • 模板解析失败静默(if (!$r) return;)这条也顺带被绕开了 —— 因为核心不再 include 插件模板。

副作用(要认)

:210 在 <?php endif; ?>(:206)之后 → 帖子/博客详情页也会触发。

现状是详情页没有签到入口,解耦后会多一个 → 属功能新增,不是回归。→ 见 §四 决策 2。

钩子占用情况(无实际冲突)

插件状态行为
diceactivated:false不执行
qaactivated:true只认 /qa 前缀,其他页 return
quiz_duelactivated:false不执行

✅ 与需求⑥ 的联动已定:需求⑥ 要的"用户栏下方、同级"挂载点就是 right_sidebar_after。

决策 6 选①(复用)→ 本需求的周视图面板维持挂 right_sidebar_after,位置在 :210,不改。

如需固定顺序,给 plugin.json 加 sort_order(Plugin::sortPlugins() 按 sort_order → seq 排;

实测 new_members 落 index 37、leaderboard 15 → sort_order 强于字母序)。


需求② 用户信息栏下方新增「本周签到」面板

数据源(复用现有查询,不增加查询数)

hook/controller_view_before.php 现在查的是"今天"这一行。改成查"本周"这一区间,一次查询喂两个用途:

$weekStart = date('Y-m-d', strtotime('monday this week'));
$weekEnd   = date('Y-m-d', strtotime('sunday this week'));
// SELECT checkin_date, points, consecutive_days FROM daily_checkin
// WHERE user_id = :uid AND checkin_date BETWEEN :s AND :e

  • checkin_today = 结果里是否含今天(原来那次"今日"查询就省了)
  • checkin_consecutive = 今日行的 consecutive_days(今日未签到则为 0)
  • 新增 week_days = 7 项 ['label'=>'一','date'=>'2026-09-21','checked'=>bool,'is_today'=>bool,'is_future'=>bool]

面板结构(对齐右栏其他面板:.mn-panel + .mn-panel-title)

每日签到 ›

一 ✓
✓ 今日已签到
明天见

视觉映射(严格只用既有 --mn-* 变量,已脚本核对 9/9 主题全覆盖)

参考图元素本站实现变量
卡片.mn-panel--mn-bg-card / --mn-border / --mn-shadow-sm
标题 + 右箭头.mn-panel-title + mn-ml-auto 的 <a>—
7 列字母新增 .dc-week-label--mn-text-muted
空格圆圈新增 .dc-week-dotborder: 1px solid var(--mn-border)
已签到填充.dc-week-dot.is-checkedbackground: var(--mn-primary) + 勾用 --mn-text-inverse
绿色胶囊复用核心 .mn-alert.mn-alert-success--mn-alert-success-bg/-text/-border
底部灰字mn-fs-12 mn-text-muted—
未签到状态复用现有 htmx 表单 → .mn-btn.mn-btn-primary.mn-btn-sm--mn-primary

已核对的变量覆盖(9/9 主题):--mn-primary --mn-primary-light --mn-primary-hover --mn-primary-subtle

--mn-text --mn-text-secondary --mn-text-inverse --mn-text-muted --mn-border --mn-border-light

--mn-bg --mn-bg-body --mn-bg-card --mn-success --mn-alert-success-bg/-text/-border --mn-shadow-sm。

⚠️ 已知不可用:--mn-bg-hover(0/9)、--mn-text-success(0/9)、--mn-radius(0/9)。

⚠️ 两处不能踩

  1. 核心没有 .mn-alert-warning(只有 success / error,9 套主题也只定义了这两组变量)

→ "还没签到"不要用 warning 语义,用中性灰字 + 主色按钮。

  1. 新增 CSS 一律写在插件自己的 assets/style.css(前缀 dc-week-*),核心 modern.css 一个字都不加。

交互(htmx,沿用现有紧凑回包机制)

  • 面板 id 由 #checkinSidebar 改为 #checkinWeek
  • 未签到 → 表单 hx-post="/checkin" + hx-target="#checkinWeek" + hx-swap="outerHTML",

隐藏字段 widget=sidebar(CheckinController::doCheckin() 靠它走紧凑回包)

  • 回包模板即面板本身 → 原地变成"已签到"态

周起始日(决策 3 已定 = 周一起)

  • 周视图按 周一 ~ 周日 排列,表头沿用既有 i18n 键 week_mon … week_sun(已存在于三语包)
  • 区间算法:date('monday this week') ~ date('sunday this week')
  • ⚠️ 与站内既有日历不一致:views/_area.php:96 的月份日历表头是 日一二三四五六(周日起)。

_area.php 本次不动,两处起始日不同属已知差异 → 会在插件 说明.md 里注明,避免以后当成 bug。

模板入口的关键坑(实现时必踩,先记下)

同一份模板会被两条路径加载,取数方式不同:

入口路径`$this->getData()` 可用?普通变量可用?
htmx 回包doCheckin() → viewRaw('plugins/daily_checkin/_sidebar', $data) → TemplateCompiler::display()(:197-200 会 extract())✅✅
右栏钩子Plugin::hook() → 闭包作用域(Plugin.php:644)$this 不可用❌✅(经 $extra)

  • 钩子里不能写 $this->include() → 要 $view = $GLOBALS['__view'](app/init.php:97 已设),

再 $view->include('plugins/daily_checkin/_sidebar', $extra);此时 $this 在 require 作用域内可用。

  • ⚠️ include($tpl, $extra)(TemplateCompiler.php:284-296)是 array_merge($this->data, $extra) 后 extract,

不会把 $extra 写回 $this->data → 走钩子路径时 $this->getData('week_days') 取不到。

结论:模板里取数据一律用普通变量($week_days / $checkin_today),禁止 $this->getData()。

$this->e() / $this->t() / $this->url() / $this->icon() 照常可用。


需求③ 用户栏的签到位 → 改发帖按钮

right_sidebar.php:179-183:

<?php if ($isBlogPage): ?>
…blog.new…
<?php else: ?>
<?php $this->include('plugins/daily_checkin/_sidebar'); ?>     ← 换成发帖按钮
<?php endif; ?>

改为:

<?php if ($isBlogPage): ?>
<?php echo $this->icon('write', 12); ?> <?php echo $this->t('blog.new'); ?>
<?php else: ?>
<?php echo $this->icon('new-post', 12); ?> <?php echo $this->t('forum.new_thread'); ?>
<?php endif; ?>

  • 落点 /post/new、文案 forum.new_thread、图标 new-post —— 与详情页发帖人卡(right_sidebar.php:96)完全一致,零新文案
  • 博客页保持 /blog/new(blog.new)不变

需求④ 个人信息 / 发帖按钮 平均分布宽度

现状 .mn-user-actions(assets/css/modern.css:1206)= display:flex; gap:6px;,

两个按钮各带 mn-flex-1(flex:1; min-width:0)→ 天然 50 / 50。

  • 「个人信息」按钮 :178 已有 mn-flex-1
  • 新的发帖按钮按 §3.3 写法也带 mn-flex-1

→ 无需新增 CSS。这条本质是"确认现状 + 保证新按钮不掉类"。文字长短不影响等宽。


需求⑤ 用户栏「个人信息 / 发帖按钮」上方新增常用操作钩子(钩子A,每行 2 列)

核心改动:在 .mn-user-stats(:167-176)之后、.mn-user-actions(:177)之前插入

<?php
ob_start();
\app\Helpers\Plugin::hook('right_sidebar_user_actions_above');
$quickActions = ob_get_clean();
?>
<?php if (trim($quickActions) !== ''): ?>
<?php echo $quickActions; ?>
<?php endif; ?>

  • 只在已登录分支内($isLoggedIn && $currentUser)→ 游客不触发
  • ⚠️ 用 ob_start + trim() !== '' 判空,不要用 CSS :empty —— PHP 会输出换行/缩进空白,

:empty 会失效,空 div 白留 12px 高度

  • ⚠️ 渲染钩子异常被 Plugin::hook() 内部 try/catch 吞掉(Plugin.php:652)

→ 出问题时表现是"这块不显示",只在 protected/error.log 留一行

核心 CSS(modern.css 新增,约 4 行)

.mn-user-quick { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; margin-top: 12px; }

(2 列等宽,间距与 .mn-user-actions 的 gap:6px 对齐)

钩子契约:插件在这个钩子里只输出裸条目(如 <a class="mn-btn mn-btn-sm">…</a>),

不要自己包容器/网格 —— 网格由核心提供,才能保证"每行两列"。

命名候选(→ §四 决策 4)

  • right_sidebar_user_actions_above —— 与 sidebar_above_friend_links 同构,语义直白(推荐)
  • right_sidebar_user_quick —— 更短,但语义模糊

风格三选(→ §四 决策 1,就是站长问的那个)

方案长什么样代价
① 与个人信息/发帖按钮一致每格一个 mn-btn mn-btn-sm(带边框圆角)视觉最统一、零新增 CSS;但 4 个操作 = 2 行实心按钮,整卡偏高
② 单纯图标 + 文字每格「图标 + 文字」一行,无边框,hover 才出浅底最紧凑(高度约按钮的 6 成)、最"极简";但与下方按钮风格断层,紧挨着会显得两块不像一家人
③ 混合(无边框小按钮)结构同 mn-btn-sm,但透明底 + 无边框,hover 出底兼顾统一与紧凑;需插件自带类,或核心加一个 mn-btn-ghost 变体(多一处核心改动)

容量与视觉边界(实测尺寸,别拍脑袋)

右栏 --mn-right-width: 260px(modern.css:2655);.mn-panel padding 16px + border 1px

→ 卡片内容宽 226px;钩子A 2 列 + gap 6px → 每格 110px;

.mn-btn-sm padding 5px 12px → 文字可用宽 84px → 12px 字号下每格 ≈ 图标 + 5 个中文字。

项数值
每格宽度110px(文字可用 84px)
每行高度≈ 29px(12px×1.4 + padding 5×2 + border 1×2)
行间距6px(与 .mn-user-actions 对齐)
4 项2 行 ≈ 64px
6 项3 行 ≈ 99px
8 项4 行 ≈ 134px

数量没有硬上限 —— grid-template-columns: 1fr 1fr 会自动换行,N 项 = ⌈N/2⌉ 行,高度自适应。

但有 4 个真实边界:

  1. ⚠️ 奇数项会留半格空:CSS grid 不会拉伸最后一项 → 5 项 = 3 行,最后一行右边空着。

→ 要么接受(推荐,最简单),要么让某一项 grid-column: span 2 独占整行(需插件自带类)。

  1. ⚠️ 栏目名必须短:每格只有约 5 个中文字的余量。"我的收藏""我的帖子""草稿箱""消息"都放得下;

"个人资料设置"(6 字)会挤。建议 ≤5 字。

  1. ⚠️ 高度会顶穿:8 项 ≈ 134px;用户卡本身还有 44px 头像 + 2 个统计格 + 按钮行 ≈ 190px

→ 整卡约 330px,右栏首屏基本被它占满。建议 ≤6 项。

  1. ⚠️⚠️ 只在桌面端可见:.mn-right { display: none } 在 @media (max-width: 1024px)(modern.css:2121-2124)

→ ≤1024px 右栏整体消失(是 1024px,不是 768px;768px 那档是 .mn-mobile-sidebar 才出来)。

→ 钩子A 里的栏目在平板/手机上完全看不到,不要往里放"只有这里能进"的功能入口。

不渲染的三种情况

  • 未登录 → 钩子在已登录分支内,不触发
  • 一个插件都没挂 → ob_start 判空 → 容器整块不输出
  • ≤1024px → 随右栏一起消失

跨插件顺序:由各自 plugin.json 的 sort_order 决定(Plugin::sortPlugins() 按 sort_order → seq);

插件内部的项序自己控。要固定顺序,就得给每个插件配 sort_order。

容量建议

预计项数建议
≤4 项方案①(带边框按钮),2 行以内,零新增 CSS
5~6 项方案③(无边框小按钮)压高度;或方案① 但接受 3 行
>6 项别都堆这儿 → 另开一个带标题的独立面板走钩子B(可分类、可折叠,且不受 110px 窄格限制)

规格同步:docs/插件开发规范.md §9 钩子表新增第 42 行(当前 41 个),

并在 §11 补一条"右栏常用操作钩子的容器契约(只输出裸条目,不包容器)"

+ "每格约 110px / 栏目名 ≤5 字 / 建议 ≤6 项"。


需求⑥ 用户栏下方(同级)新增钩子(钩子B)

要什么:在用户栏面板外面、与用户栏同级的位置,加一个供插件挂独立面板的挂载点 ——

形态与排行榜 / 最新会员 / 站点统计一致(插件自己输出 <div class="mn-panel">…</div>)。

⚠️ 关键事实:这个位置已经有钩子了。

项值
钩子名right_sidebar_after
编号规范 §9 #14
触发点app/Views/_components/right_sidebar.php:210
位置用户面板 <?php endif; ?>(:206)之后、站点统计(:213)之前 —— 正是"用户栏下方、同级"
参数无
触发次数单触发(PC 右栏;mobile_sidebar.php 里没有它)
核心注释原文"右栏通用钩子:用户信息面板之后,供插件注入侧栏面板"
现有占用dice(停用)/ qa(启用,只认 /qa*)/ quiz_duel(停用)

✅ 决策 6 已定:选路径 1(复用 right_sidebar_after),零核心改动。

✅ 采用 · 路径 1:复用 right_sidebar_after,零核心改动

  • 什么都不用加,位置天然正确。
  • 先后顺序由 plugin.json 的 sort_order 控制(Plugin::sortPlugins() 按 sort_order → seq 排;

实测 new_members 落 index 37、leaderboard 15 → sort_order 强于字母序)。

  • 代价:与 dice / qa / quiz_duel 共享同一个钩子位。实际不冲突(两个停用、qa 只认 /qa*),

且按站长判断语义足够干净,接受共享。

❌ 未采纳 · 路径 2:新增专用钩子 right_sidebar_user_below(留档备查)

  • 原方案:插在 right_sidebar.php:206(<?php endif; ?>)与 :210 之间。
  • 好处:语义明确、顺序稳定、不受其他插件干扰。
  • 未采纳原因:与 right_sidebar_after 位置/语义高度重叠,属重复建设;且会让规范 §9 从 41 → 43 个钩子,

后人容易挂错。若将来真的需要,再单独开一项。

钩子契约(两条路径通用)

  • 插件输出完整面板:<div class="mn-panel"><h3 class="mn-panel-title">…</h3>…</div>
  • 无数据一律 return,不要输出空面板占位(站内通例:① 满站刷屏;② 会造出死按钮)
  • 渲染钩子在闭包作用域 → $this 不可用,一律用 htmlspecialchars($s, ENT_QUOTES, 'UTF-8') + Csrf::token()
  • ⚠️ 若将来该钩子要进移动端,需同步加进 mobile_sidebar.php → 钩子从"单触发"变"双触发",

必须同步改规范 §9,并回归 dice / qa / quiz_duel

对本方案的影响(已定):需求② 的「本周签到面板」维持挂 right_sidebar_after + sort_order,不改动。


四、决策(已定稿 · 2026-09-27 站长拍板)

#决策选项✅ 决定
1钩子A 的视觉风格①与按钮一致 / ②纯图标+文字 / ③混合① 与按钮一致,先按 ≤4 项设计
2详情页是否也显示「本周签到」面板①全站显示 / ②仅非详情页① 全站显示
3周视图起始日①周一起 / ②周日起① 周一起(M T W T F S S)
4钩子A 命名①right_sidebar_user_actions_above / ②right_sidebar_user_quick① right_sidebar_user_actions_above
5移动端是否同步①本次不动 / ②给 mobile_sidebar.php 也加① 本次不动
6用户栏下方钩子(钩子B)①复用 right_sidebar_after / ②新开 right_sidebar_user_below① 复用 right_sidebar_after

决策带来的三个简化(都朝"更少改动"方向)

  1. 决策 6 选① → 钩子B 零核心改动:right_sidebar_after 已存在(:210),不新增钩子位。

→ 规范 §9 钩子表只 +1 行(钩子A),不是 +2;需求② 的周视图面板维持挂 right_sidebar_after。

  1. 决策 1 选① + ≤4 项 → 钩子A 零新增组件样式:直接复用 .mn-btn.mn-btn-sm;

modern.css 只需加 .mn-user-quick(2 列网格容器)那 4 行,不需要 mn-btn-ghost 之类的变体。

  1. 决策 5 选① → 钩子触发次数不变:right_sidebar_after 保持单触发,

不用改规范 §9 的"触发次数"列,也不用回归 dice / qa / quiz_duel 的双触发行为。

实施时需要一并落实的(来自决策的推论)

  • 决策 1「先按 ≤4 项设计」 → .mn-user-quick 就用 grid-template-columns: 1fr 1fr + gap: 6px,

不做 span 2、不做奇数项补齐。将来项数涨了再议(§3.5 容量建议:>6 项改走钩子B)。

  • 决策 2「全站显示」 → 周视图面板的钩子 right_sidebar_after 不加任何 URI 白名单,

与 leaderboard / new_members 的处理一致(它们也不做模板白名单)。

  • 决策 3「周一起」 → date('monday this week') ~ date('sunday this week');

_area.php 的月份日历表头(日一二三四五六)不动,两处起始日不同属已知差异,会在插件 说明.md 注明。

容量依据(§3.5 实测):每格仅 110px(约 5 个中文字)、每行 ≈ 29px。

站长已确认先按 ≤4 项设计;若将来涨到 5~6 项,建议改用无边框小按钮压高度;

>6 项则改走钩子B 的独立面板。


五、改动文件清单(定稿)

核心(本次无法避开)

文件改动
app/Views/_components/right_sidebar.php删 2 处(:182、:185-194);:179-183 换发帖按钮;:176/:177 之间插入钩子A 容器(right_sidebar_user_actions_above)。钩子B 复用已有 :210,本文件该处不动
assets/css/modern.css新增 .mn-user-quick(约 4 行)
docs/插件开发规范.md§9 钩子表 +1 行(钩子A right_sidebar_user_actions_above,总 41 → 42);§11 补容器契约 + 容量约束(每格 110px / 栏目名 ≤5 字 / 建议 ≤6 项)

插件 daily_checkin

文件改动
plugin.jsonhooks 增 right_sidebar_after;加 sort_order 固定位置
hook/right_sidebar_after.php新增 —— 输出周视图面板($GLOBALS['__view']->include() 复用模板)
hook/controller_view_before.php查询由"今日"改"本周",注入 week_days / checkin_today / checkin_consecutive
views/_sidebar.php重写为周视图面板(钩子 + htmx 回包共用)
CheckinController.phpcompact 回包模板名不变(仍 _sidebar);若换名需同步
assets/style.css新增 dc-week-* 样式
lang/{zh,zh_tw,en}.php新增键(msg_tomorrow 等);三语必须同键集合(基线:三语各 1343 键、零差异)
说明.md更新挂载点与视图说明

⚠️ daily_checkin 目录名含下划线 → Plugin.php 末尾必须有

class_alias(Plugin::class, 'Plugin\daily_checkin\Plugin', false),

否则生命周期静默跳过(建表/卸载都会出问题)。实施前先核一遍现状。


六、验证方式(我跑逻辑,界面你看)

静态

  • php -l 全部改动文件
  • i18n 引用键 ↔ 三语字典全量比对(判据 = 键集合零差异,不是"值非空")
  • 核心 right_sidebar.php grep daily_checkin → 必须 0 命中
  • 新增 CSS 变量脚本核对 9 套主题覆盖(本次已预核,见 §3.2)

逻辑(HTTP 冒烟,php -S,启动 + curl + kill 同一个 Bash 调用)

场景期望
停用 daily_checkin,登录态右栏无签到痕迹;用户卡 = 个人信息 + 发帖两按钮等宽;整页无 plugin.daily_checkin 字样
未登录钩子A 不触发;显示登录 / 注册
启用 daily_checkin,登录且今日未签到周视图 7 格、今日格高亮;按钮可点;htmx POST 后原地变"已签到"
已签到绿胶囊 + "明天见"
无常用操作插件钩子A 的 .mn-user-quick 容器不输出(不是空 div)
无挂钩子B 的插件用户栏下方不出现空面板 / 占位块,站点统计紧接用户栏
详情页(/thread/{id}、/blog/{id})周视图面板照常显示(决策 2 = 全站显示,钩子无 URI 白名单)
右栏宽 ≤1024px右栏整体 display:none → 钩子A / 钩子B 内容都不出现(预期行为,非缺陷)

回归:排行榜 / 最新会员 / qa 侧栏(/qa*)三个占用侧栏钩子的插件不回归;

另外确认 dice / qa / quiz_duel 的 right_sidebar_after 输出未受影响(钩子B 复用它,不新增钩子位);

改完清一次前台页面缓存(/、/forum、/forum/category/N 有前置缓存,仅游客)后复测。


七、风险与回滚

风险说明对策
核心视图改动影响全站右栏right_sidebar.php 被 main.php:341 无条件 include改动点少且局部;改前先存快照,改后比对
钩子在闭包作用域($this 不可用)误用 $this->e() → fatal 被 try/catch 吞成"面板整块不显示"、HTTP 仍 200钩子内一律 htmlspecialchars() + Csrf::token();发真实 HTTP 并看 protected/error.log
模板双入口取数方式不同$this->getData() 在钩子路径取不到模板统一用普通变量(§3.2)
未启用插件语言包不合并新键若只在插件包 → 未启用时吐键名面板整块由钩子输出(未启用 = 不执行),不会吐键名
页面缓存/、/forum、/forum/category/N 有前置缓存改完走后台「维护 → 清理缓存」

回滚:全部改动可逆向(删新增文件 + 还原 3 个被改文件)。改前先存

right_sidebar.php / modern.css 快照 + sha256 基线。


八、实施计划(分 3 阶段,每阶段末暂停确认)

原则:先动核心、后动插件;每阶段独立可验证;阶段末停下来汇报,等确认再进下一阶段。

阶段 1 —— 核心视图解耦 + 发帖按钮 + 钩子A(改动最小、可独立验证)

  1. 存 right_sidebar.php / modern.css 快照 + sha256 基线
  2. 删 right_sidebar.php:182、:185-194(解耦)
  3. :179-183 换成发帖按钮(/post/new + forum.new_thread)
  4. :176/:177 之间插入钩子A 容器(ob_start 判空)
  5. modern.css 新增 .mn-user-quick(4 行)
  6. 验证:php -l;grep daily_checkin = 0 命中;HTTP 冒烟(登录 / 未登录两态,确认无键名泄漏、两按钮等宽、无钩子插件时容器不输出)
  7. 暂停汇报 —— 此时签到功能会短暂消失(插件还没挂钩子),属预期

阶段 2 —— 签到插件周视图面板

  1. hook/controller_view_before.php:查询由"今日"改"本周",注入 week_days / checkin_today / checkin_consecutive
  2. views/_sidebar.php 重写为周视图面板(周一~周日 7 格,模板内只用普通变量)
  3. 新增 hook/right_sidebar_after.php($GLOBALS['__view']->include() 复用模板)
  4. plugin.json 加 right_sidebar_after 钩子 + sort_order
  5. assets/style.css 新增 dc-week-*
  6. lang/{zh,zh_tw,en}.php 同步加键(msg_tomorrow 等)—— 三语键集合必须零差异
  7. 说明.md 更新(含"周一起 vs _area.php 周日起"的已知差异)
  8. 验证:三语键集合比对;HTTP 冒烟(未签到 / 已签到 / htmx POST 原地刷新 / 详情页也显示);看 protected/error.log 无新增
  9. 暂停汇报

阶段 3 —— 规范同步 + 回归 + 打包

  1. docs/插件开发规范.md:§9 钩子表 +1 行(钩子A,总 41 → 42);§11 补容器契约 + 容量约束
  2. 回归:排行榜 / 最新会员 / qa 侧栏 / dice / quiz_duel
  3. 清前台页面缓存(后台「维护 → 清理缓存」)
  4. 打包 update/39(含 version.php + 改动说明.md 六节体例)
  5. 暂停汇报

九、遗留(与本次无关,等你一句话)

  1. update/38 已交付,但站点根 version.php 仍是 V1.0.31(包内写的是 V1.0.38)→ 是否顺手升?
  2. update/38 只有目录、没有 zip → 要不要补一个?
轻量级、高性能、零 MySQL 依赖的PHP社区系统。
| 瀏覽 6 次 | 回覆 0 次

全部回覆 (0)

暫無回覆

請 登入