本文由 FlintHub 开发文档归档发布。原始文档日期见标题前缀,来源:内部文档归档。
XenForo 主题适配 · 实施方案与四步实施报告
本篇由 6 篇原始文档合并去重而成:修复建议计划 + 实施方案 + Step 1~4 实施报告。
一、为什么做 XenForo 主题适配
XenForo 主题(assets/themes/Xenforo/)是 FlintHub 的目录型主题,封版于 8/21;而核心视图在 9/1~9/13 又集中改动了一批功能,主题副本没有跟着走。审计(核心视图 ↔ 主题视图逐文件 diff + ?preview_theme=XenForo 运行期取样 + CSS 类定义扫描)发现的主要问题:
- 半套主题:25 个模板里只有 4 个是 XenForo 风格版,其余 21 个仍是 8/17~8/18 的核心
mn-*旧拷贝,登录/注册/个人中心/博客/私信/发帖/标签/搜索/404 风格割裂。 - 嵌套重复目录:8/20~8/21 的完整新版被解包到了
Xenforo/Xenforo/Xenforo/嵌套子目录(22 个文件与父目录不同),未生效。 - 「踩」按钮失效:投票接口
ApiController::vote()只接受0/1(app/Controllers/ApiController.php:57),主题仍发vote=-1,点了必 400。 - 详情页缺 4 个插件钩子:收藏 / 举报 / 红包在主帖与回复上不显示。
- 缺通知铃铛与「我的收藏 /favorites」入口。
- 头像 96px 过大(核心列表/详情仅 40px);长帖折叠机制过时(旧变量已不再下发,折叠恒不触发);缺头衔/等级徽章
pmTitles/ulBadges与data-quote-uid。 - 静态缓存键不含主题维度:换主题或预览时游客仍命中旧主题缓存 HTML。
二、适配范围与总体方案
2.1 主题目录结构与机制
- 主题根目录
assets/themes/Xenforo/,含config.json、xenforo.css、images/与若干 PHP 模板子目录(layouts/、forum/、thread/、auth/、blog/、home/、profile/、tags/、search/、theme/)。 - 覆盖机制:主题内存在同名模板即覆盖
app/views/核心视图;主题没有的文件(如_components/)自动回退核心。 - CSS 组织:
xenforo.css全部使用xen-类名,在.xen-body-page上重映射整套--mn-变量(如--mn-primary:#1f4e79)换 XenForo 配色;基础变量、.thread-body折叠高度变量--thread-body-collapsed-height:600px继承自modern.css(:root),xenforo.css加载在其后。约束:**只用--mn-*变量,不写死色值**。 - JS 组织:主题零内联
on*=;交互统一走data-action+assets/js/thread.js、auth.js的全局事件委托,配合 Alpine.jsx-data/x-on。
2.2 改造原则与施工顺序
- 先整体备份再动手(
.workbuddy-ai/backup/2026-09-16_xenforo-改前/、-嵌套副本/)。 - 全部改动文件 UTF-8 无 BOM + LF,
php -l零错误,冒烟前后protected/error.log零新增告警。 - A/B 策略:高频页(forum/category、profile、search、tags、auth、blog)提升 8/20~8/21 新版;长尾页(message/、errors/404、thread/edit、post/)删副本回退核心,功能永远最新、由
xenforo.css自动上色;theme/settings.php父目录独有、保留不补。 - 顺序:Step 1 底座(结构调整)→ Step 2 视觉(只改 CSS)→ Step 3 功能对齐(逐文件)→ Step 4 缓存维度 + 回归。
2.3 哪些视图被替换 / 回退
- A 组提升 13 个:
forum/category、profile/index、search/index、tags/index、tags/show、auth/login、auth/register、auth/forgot_password、auth/reset_password、auth/message、blog/index、blog/detail、blog/edit。 - B 组删除 8 个(回退
app/views/):message/compose、message/inbox、message/sent、message/view、errors/404、thread/edit、post/create、post/edit。 - 保持不动后大改:
layouts/main.php、thread/show.php、forum/index.php、home/index.php。 - 新增 2 个:
home/index_default.php(社区态,由原home/index.php迁出)、home/index.php(XenForo 风门户页)。
2.4 关键改动文件速查
| 阶段 | 改动文件 | 要点 |
|---|---|---|
| Step 1 | A 组 13 个模板、xenforo.css、删 B 组 8 个副本、删嵌套目录、两份备份 | 结构统一、清缓存 |
| Step 2 | xenforo.css、layouts/main.php | 头像三档、空类处置、折叠遮罩、门户适配段、内联第一批 |
| Step 3 | thread/show.php、layouts/main.php、forum/index.php、forum/category.php、home/ ×2、blog/ ×3、auth/ ×5、tags/ ×2、search/index.php、profile/index.php、theme/settings.php、assets/js/thread.js、assets/js/auth.js | 删踩、补 4 钩子、铃鞭与收藏、摘要开关、内联清理 |
| Step 4 | app/Helpers/PageCache.php、app/Helpers/Theme.php、app/Controllers/Admin/ThemeController.php、lang/{zh,en,zh_tw}.php | 缓存主题维度、补 4 个三语缺键 |
三、Step 1 底座:做了什么、结果
只做结构调整,未改任何业务逻辑。
- 备份两份:嵌套副本 53 个文件、改前整目录 107 个文件(含嵌套),校验文件数一致。
- A 组提升 13 个:用嵌套 8/20~8/21 新版逐个覆盖,先出 diff 再落地(如
blog/detail.php+69/−40、search/index.php+137/−86),全部成功。 - B 组删除 8 个:删除主题副本回退核心视图,空目录
message/、errors/、post/一并清理。 - CSS 覆盖:嵌套版
xenforo.css(8/21 09:51)覆盖父目录版(8/20 20:49),多出.xen-authBox/.xen-formLabel/.xen-formHint/.xen-comment .xen-message-user{width:120px}等规则。 - 保留
theme/settings.php:3835 字节,8/20 14:19,父目录独有(缺口记入漂移清单)。 - 删除嵌套目录:
assets/themes/Xenforo/Xenforo/已不存在,主题目录现为 18 个 PHP +config.json+xenforo.css+images/。 - 清缓存:
protected/cache/templates/、data/runtime/pages/均清空。
超出计划的三处处置:新版 CSS 引入的 3 处硬编码色值(#4b5563/#1f2937)改回 var(--mn-*)(实测线上命中数 0);xenforo.css 与 config.json 的 CRLF 统一转 LF。
结果:18 个主题 PHP 文件 php -l 全绿;20 个文本文件 UTF-8 无 BOM + LF;冒烟 8 页全 200(/login 首次出现 xen-authBox×1、xen-formLabel×3;/tags、/blog、/forum/category/1 由 Modern 旧版切为 xen 版式;/nonexistent 404 呈「外框 xen + 正文核心」符合 B 组预期);error.log 31→31 零新增。遗留:登录态页面(/profile、/message 等)未测;PageCache 主题维度属 Step 4,此前预览仍可能串味。
四、Step 2 视觉:做了什么、结果
只改 2 个文件:assets/themes/Xenforo/xenforo.css、assets/themes/Xenforo/layouts/main.php。
- 头像三档(按确认口径,无
!important,靠媒体查询顺序 1024→900→600 覆盖):桌面96px/34px → 64px/22px;新增@media (max-width:1024px)下48px/17px;<900px顶栏形态保持40px/16px。.xen-message-user宽度190px → 150px。 - 8 个「只标记未定义」类处置:
xen-pageContent补min-width:0、xen-nodeList补 flex 竖排、xen-expandBtn补真规则;xen-fs-11/18/20/48、xen-gap-8补工具类;xen-message--thread补主帖用户栏浅底;xen-searchButton/xen-account仅加语义注释。顺带补.xen-dropdown-wrap。 - 长帖折叠(配合 Step 3):新增 §14c ——
.xen-expandBar+.xen-expandBtn+.thread-body--collapsed::after渐变遮罩(用--mn-bg-card);不重复造轮子,.thread-body与折叠高度变量直接继承modern.css,并删除 §11 里旧同名规则避免打架。 - 门户页适配段 §16:
.xen-portal .pr-card/.pr-hero/.pr-btn/.pr-spec-value等 11 条,全部只用--mn-*(当时无页面使用,Step 3.8 建门户页时挂容器生效)。 - 内联 style 迁移第一批:
layouts/main.php13 处 → 0 处(display:none×6 改用x-cloak;定位内联改用xen-dropdown-wrap/mn-dropdown-panel;警示横幅改用admin-warn-bar)。已知两处视觉差异:语言切换器右间距 8px→4px;警示横幅不再 sticky 通栏。 - 内联存量盘点:A 组提升后全主题内联
style=从 67 涨到 131,on*=11 处、内联<script>6 处(其中layouts/main.php的 CSRF_TOKEN / FlintHubI18n 两段为核心必需、豁免)。经拍板选 A:Step 3 收尾继续清理。
结果:php -l 通过;两文件 UTF-8 无 BOM + LF;CSS 花括号 300/300 平衡;冒烟 6 页 200、内联 display:none 归零、x-cloak ×4 正常、页内告警 0;error.log 零新增,冒烟缓存已清理。
五、Step 3 功能对齐:做了哪些功能、结果
改动 19 个主题 PHP(含 2 个新建)+ xenforo.css + assets/js/thread.js + assets/js/auth.js。
5.1 thread/show.php 帖子详情(3.1~3.4)
- 删「踩」:删除主帖与每层回复的
vote-btn vote-down … "vote":"-1"按钮,取值去掉dislikes,与核心对齐只保留赞/取消赞。 - 补 4 个插件钩子(全部正面验证):
thread_redpacket_area(主帖正文/附件后,/thread/70渲染红包卡片 ×1)、thread_operation_after(主帖收藏+举报)、post_operation_after(回复操作行,楼中楼按钮 ×15)、post_report_button(楼层号前,回复举报 ×15)。相应 CSS 补.xen-message-extra/.xen-message-report。 - 补数据与交互:顶部一次性取
$wearingMedals/$pmTitles/$ulBadges三张映射表;回复区补data-quote-uid与头衔/等级徽章;确认弹窗改 Alpinex-on:submit.prevent;附件/滚动/灯箱改data-action委托;删除整段DOMContentLoaded内联脚本。 - 正文折叠换机制:删掉死代码
_threadExcerpt/hx-get="/api/post/{id}/body",改用核心现行方案thread-body-shell+data-thread-collapse+ Alpineexpanded/hasOverflow状态,默认折叠高度 600px,按钮复用xen-btn皮肤。
5.2 layouts/main.php 布局补齐(3.5)
顶部补 Theme::layoutExcerptNavState() 与 layoutToggleUrl;PC 副导航补列表/摘要切换按钮(图标随状态切 columns/list);用户下拉补 /favorites + fav-count-badge;xen-nav-opposite 末尾 include _components/notification_bell(PC + 移动端两份,主题无 _components/ 目录自动回退核心组件);抽屉补 Plugin::hook('nav_drawer_links'),页脚补 footer_links 钩子;layout_head_end 钩子补 template 参数;补门户首页侧栏显隐判断。
5.3 论坛 / 版块 / 首页(3.6~3.8)
forum/index.php(置顶+普通两个循环)与forum/category.php:补$showExcerpt判断,有摘要时隐藏xen-threadRow-icon大头像、插入xen-threadRow-excerpt(摘要文本+缩略图)、元信息前补 18px 小头像、标题行补ulListBadges。home/index_default.php(新建):由原home/index.php复制迁出,补showExcerpt+ 同款摘要结构;home/index.php重写为门户外页,section('content')后包<div class="xen-portal">,保留portal.css与 Hero/核心特性/插件生态/富页脚四段。实测default_home_mode='community'渲染社区版,site_home_mode=portalcookie 渲染门户版且通栏,两种模式共存。
5.4 A 组 13 个文件缺口回填 + 修复 3 处真实缺陷
回填:blog/detail 补 blog_detail_operation_after/blog_comment_operation_after 钩子与 pmTitles;blog/edit 恢复封面三键 blog.cover_hint/cover_none/cover_preview + blogCategories;auth/register 补 id="regForm"、auth.captcha_refresh、data-pow-captcha;auth/login 补 id="loginForm"、allow_registration 开关、锁定倒计时改 data-lock-countdown(auth.js 接管);search/index 补 common.pinned/forum.highlighted 标签;theme/settings 改 Alpine 提交、卡片样式收敛为 xen-themeCard 系列;tags/index 改 CSS :hover。
实施中发现并修复 3 处方案未列的真缺陷:① blog/detail.php 主题版丢失整段封面图渲染块(xen-cover);② blog/detail.php+blog/edit.php 把 blogCategories 误取为 categories,分类下拉恒空;③ blog/edit.php 丢失封面模板选择 + 实时预览(cover_template/cover_preview_wrap)且 maxlength 硬编码 200。
5.5 内联清理与 JS 委托
on= 11 → 0(thread/show 5、blog/detail 3、tags/index 2、theme/settings 1,分别改 Alpine / data-action / CSS :hover);内联 <script> 6 → 3(方案点名 5 处全清,保留 layouts 豁免 2 处 + blog/edit 封面预览 1 处与核心对齐);内联 style= 74 → 14(剩余 10 处为动态色值/封面图/字号等必要动态值,4 处为 JS 直接读写 .style.display 的功能性内联;优先复用 modern.css 既有 mn- 工具类,仅新增 13 个 xen-* 类,顺带修复 xen-mb-20 未定义问题)。JS 侧:thread.js 新增 scroll-reply 委托,auth.js 新增密码强度/验证码刷新/锁定倒计时委托。
结果:19 个 PHP php -l 全过;CSS 花括号 376/376 平衡(597 行),模板所用类 100% 有定义;冒烟 10 页(三语站点页 + /thread/70 + /blog/1 + /theme-settings)全部 200、页内告警 0;error.log 50→50 零新增。
六、Step 4 缓存维度与回归:缓存怎么处理、回归结论
6.1 PageCache 主题维度(本轮唯一核心逻辑改动,无 SQL)
app/Helpers/PageCache.php 新增 themeKey(),cacheKey() 变为三层叠加 themeKey(langKey(prefKey($name))):
?preview_theme=预览模式:加_preview_{主题名}后缀,不复用缓存;- 非默认主题:加
_t{主题名}后缀;默认主题不加后缀,存量缓存零影响; serve()/render()两处调用点均改走cacheKey()。
配套失效两处:Theme::set() 切主题时、Admin\ThemeController::setDefault() 保存默认主题后,均调用 PageCache::invalidate()。
实测 /forum 三种取主题方式生成三份互不干扰的缓存:forum_0_1_e1l180.html(默认,xen=0/mn=543)、forum_0_1_e1l180_preview_Xenforo.html(xen=469)、forum_0_1_e1l180_tXenforo.html(cookie,xen=469),渲染差异全部正确。
6.2 回归结论
- 逐页冒烟:游客态
?preview_theme=XenForo10 页全部 200、无告警;/search302 为需登录的预期行为。登录态另跑 11 页(/profile、/post/new、/favorites、/notifications、/blog/new、/blog/1/edit、/search3 种 type 等)全部 200 无告警。 - 插件钩子正面验证:
/thread/70上红包卡片 ×1、主帖举报 ×1、回复举报 ×11、楼中楼按钮 ×11。 - 移动端三档宽度:
>1024px头像 64px/用户栏 150px;900~1024px头像 48px;<900px头像 40px、用户栏 100% 折叠为顶栏。 - 三语走查发现并修复 4 个真实缺键:
nav.menu、search.search、search.advanced、profile.administrator在 zh/en/zh_tw 三语字典全部缺失(I18n 缺键时回吐键名,页面直接显示原始键名;属 Step 1/2 前存量缺陷),三语各补 4 键后复扫:12 页(3 语 × 4 页)零键名泄漏;三语字典各 1224 键、差集为空、主题引用的 166 个键三语零缺失。 - 收尾:全部改动文件
php -l通过、UTF-8 无 BOM + LF;冒烟缓存已清理;临时测试账号zz_smoke_tmp(零内容产出)与临时脚本目录已删除,顺带修正派生计数器_runtime_total_users(281→282)。
6.3 验收 Checklist
实施方案中 10 项验收(目录无嵌套、备份齐全、A/B 处置、头像三档、详情四项、布局补齐、首页双模式、PageCache 维度、冒烟+三档+三语、编码与 lint)逐项全部 ✅。全案至此收口。
七、遗留与未适配项
| 项 | 说明 |
|---|---|
| 门户页副本漂移 | home/index.php / home/index_default.php 为主题覆盖副本;后续核心改 app/views/home/* 时需同步,已记入漂移清单。建议长期加一条「主题副本 mtime 早于核心视图即告警」的检查。 |
| sw.js / 发布包 update/N | 本次未打包。若发布:涉及 CSS 改动(xenforo.css),需按项目约定把 sw.js 一并入包并递增 CACHE_VERSION(flinthub-static-vX.Y.Z),包内带 version.php 与改动说明。 |
theme/settings.php 缺口 | 按既定口径只保留、不回填:仍是 8/20 核心旧拷贝、0 处 xen-、缺 9/5 核心改动。 |
剩余 14 处内联 style= | 10 处动态值(节点色、封面图、标签字号等)+ 4 处功能性 display:none(pow.js/auth.js 直接读写),均为必要保留。 |
| 并发/锁争用 | 本机 PHP 无 pcntl,需在 Linux 环境验证(与本主题无关)。 |
| B 组长尾页版式 | message/、post/、errors/404、thread/edit 走核心视图,为 Modern 版式 + XenForo 配色,未做 XenForo 版式重做。 |