WP Editor.md 导致 Document 主题首页「文章导航」消失的完整排查与修复记录
- 笔记
- 16天前
- 75热度
- 0评论
WP Editor.md 导致 Document 主题首页「文章导航」消失的完整排查与修复记录
环境:WordPress + WP Editor.md(wp-editormd)+ Document 主题(theme-document)
现象:启用 WP Editor.md 后,博客首页左侧「🗂️ 文章导航」整块不显示或「像消失了一样」;禁用插件后恢复正常。
结论:这不是 Markdown 标题解析失败,而是 前台脚本加载策略 + jQuery 句柄冲突 + 主题侧栏默认透明 叠加导致的兼容性问题。
一、现象描述
1.1 用户看到什么
- 首页本应出现左侧 文章导航 栏,列出当前页各篇文章标题,点击可锚点跳转到对应
h2。 - 安装并启用 WP Editor.md,且通常开启了「支持前台评论 Markdown」等选项后,导航栏消失。
- 浏览器控制台常见报错(修复前典型堆栈,行号随版本可能变化):
Uncaught ReferenceError: $ is not defined
at monitor.js:11:1
at main.js:2:1
at index.js:4:1
Uncaught ReferenceError: jQuery is not defined
Uncaught ReferenceError: Prism is not defined
1.2 容易产生的误解
| 误解 | 实际情况 |
|---|---|
| 「Markdown 标题不是 HTML,主题解析不到」 | 首页导航来自 $wp_query 文章列表 + post_title,不解析正文 Markdown |
| 「文章总标题没写进目录所以整块没了」 | 单篇文章页才涉及总标题目录;首页是 列表导航,逻辑不同 |
「插件 CSS 把侧栏 display:none 了」 |
更常见是 opacity: 0 且 JS 未执行,DOM 仍在,肉眼看不见 |
二、Document 主题首页导航是怎么工作的
要理解 bug,必须先弄清主题 期望 的行为。
2.1 显示条件(PHP 层)
首页侧栏模板:template/index/sidebar-index-left.php
if ( nicen_theme_showArticleCate() ) {
$catelog = nicen_theme_navigator();
if ( ! empty( $catelog ) ) {
// 输出 #space > #navigator ...
}
}
两层门闩:
nicen_theme_showArticleCate()- 博客首页 / 「最新文章」型首页:读取主题选项
document_show_left_nav - 分类、标签、搜索等:读取
document_show_else_left_nav
- 博客首页 / 「最新文章」型首页:读取主题选项
nicen_theme_navigator()返回值非空- 若当前查询结果里没有任何可展示文章,返回空字符串 → 整块 HTML 不输出(不是隐藏,是根本没有 DOM)
2.2 目录 HTML 如何生成(首页分支)
include/functions/common.php 中 nicen_theme_navigator() 在 非单篇文章页(含首页)时:
global $wp_query;
foreach ( $wp_query->posts as $post ) {
// 过滤「不在首页显示」的分类/标签
// 生成 <li><a href="#h2{post_id}">1. 文章标题</a></li>
}
要点:
- 数据来自 主查询
$wp_query->posts,与文章摘要、Markdown 正文无关。 - 锚点
#h2{ID}对应列表模板里每篇文章的<h2 id="h2...">(见template/index/article-list.php)。 - 单篇文章页(与首页 bug 无关,但易混淆):目录首项为 文章总标题(
#document-post-title),其下为正文##/###/####(HTML 模式)或h1/h2/h3短代码(meta 模式);需主题选项 HTML 标签 目录模式以配合 WP Editor.md。
2.3 显示条件(CSS + JS 层)
即使 PHP 输出了 #space 和 #navigator,用户仍可能「看不见」,因为主题还有一套 前端定位与显隐 机制。
CSS 默认透明
#navigator 在样式中默认:
html body .main-container #space #navigator {
opacity: 0;
position: fixed;
/* ... */
}
首页导航容器还带 class isIndex(sidebar-index-left.php)。
设计意图:避免侧栏在 JS 计算 left/top 之前 闪一下错位,等 monitor.js 算好位置后再 show()。
JS 负责定位与显示
common/inline/monitor.js(在开启首页左侧导航时由 include/themes/load.php 引入):
let navigator = $('#navigator');
if (navigator.length > 0) {
navigator.css('left', pos.left);
navigator.css('top', space.getTop());
navigator.show(); // 主要改 display;opacity 靠 inline style 或后续逻辑
}
common/main.js 还负责滚动时固定侧栏等行为,全部依赖 jQuery 全局 $。
主题加载顺序(修复前的问题版本)曾存在:
- 脚本 未声明 依赖
jquery - 在 头部 执行,早于 WP Editor.md 替换 jQuery 的时机
→ 一旦 $ 不存在,整链 JS 中断,opacity: 0 永远得不到纠正。
三、WP Editor.md 做了什么(冲突从哪来)
3.1 插件前台模块的触发条件
wp-editormd/src/Main.php 在以下情况实例化前台控制器 EditormdFront\Controller:
Config::get_option("support_front", "editor_basics") == "on"
|| Config::get_option("support_other_text", "editor_basics") !== ""
? new ControllerFront() : null;
即:开启 前台评论 Markdown,或填写了 自定义前台编辑器元素 ID,就会挂接 wp_enqueue_scripts。
修复前的行为:只要满足上述配置,全站所有页面(含首页、归档页)都会执行 enqueue_front_scripts(),而首页根本没有 #comment 评论框——Editor.md 的配置脚本会在 document.ready 里发现没有目标 textarea 然后 return,但 jQuery 已被替换/注销。
3.2 jQuery「兼容模式」与句柄替换
Front\Controller::enqueue_front_scripts()(修复前核心逻辑):
if (Config::get_option("jquery_compatible", "editor_advanced") !== "off") {
wp_enqueue_script("jquery", null, null, array(), false); // 头部加载
} else {
wp_deregister_script("jquery"); // 注销 WordPress 默认 jquery
wp_enqueue_script("jQuery-CDN", .../jquery.min.js, ..., true); // 页脚、新句柄
}
wp_enqueue_script("Editormd_Front", ..., array("jquery" 或 "jQuery-CDN"));
wp_enqueue_script("Config_Front", ..., array("Editormd_Front"));
| 模式 | 行为 | 对主题的影响 |
|---|---|---|
兼容模式 开启(jquery_compatible ≠ off) |
仍用核心 jquery,但可能强制 头部 加载 |
与主题 页脚 脚本顺序易错位 |
| 兼容模式 关闭 | wp_deregister_script('jquery'),改用句柄 jQuery-CDN |
主题若仍依赖句柄 jquery 或未声明依赖 → $ 未定义 |
同一插件内 KaTeX、MindMap、FrontStyle 等模块在修复前也会在 wp_enqueue_scripts 全站 重复执行类似的 jQuery 注销/注册逻辑,首页无辜中招。
3.3 Prism 报错(次要但会加剧排查难度)
开启语法高亮自动加载时,插件在 wp_print_footer_scripts 输出:
Prism.plugins.autoloader.languages_path = "...";
若主题或插件脚本顺序导致 Prism 全局变量尚未定义,会再抛 Prism is not defined。该错误与导航无直接关系,但说明 首页加载了本不需要的 Editor.md 前台资源。
四、故障链:从插件启用到导航「消失」
下面是一条完整的因果链(修复前)。
flowchart TB
A([启用前台评论 Markdown]) --> B[全站加载 Front / Config_Front]
B --> C{jquery_compatible?}
C -->|关闭| D[wp_deregister jquery<br/>改用 jQuery-CDN]
C -->|开启| E[jquery 在 head 加载<br/>主题脚本在 footer]
D --> F[main · monitor · index<br/>执行时 $ 未定义]
E --> F
F --> G[monitor.js 解析期报错<br/>$.fn.scrollUnique]
G --> H[侧栏定位 / show 未执行]
H --> I["navigator opacity 仍为 0"]
I --> J([用户感知:导航消失])
B --> K[首页无评论框<br/>Editor 逻辑空 return]
K --> L([jQuery 被改动<br/>却无编辑器收益])
classDef entry fill:#e3f2fd,stroke:#1565c0,color:#0d47a1
classDef fault fill:#ffebee,stroke:#c62828,color:#b71c1c
classDef side fill:#fff8e1,stroke:#f9a825,color:#f57f17
class A entry
class J fault
class L side
4.1 为何「禁用插件就好」
禁用 WP Editor.md 后:
- 不再
wp_deregister_script('jquery') - 不再全站加载
Config_Front/ Prism 内联 - WordPress 默认
jquery+ 主题脚本依赖恢复正常 →monitor.js跑通 → 侧栏可见
这证明 数据层(PHP 目录)往往是好的,问题在 资源加载与前端执行环境。
4.2 为何「HTML 里可能有,但看不见」
用开发者工具检查 DOM,常见:
- 存在
<div id="space">和<aside id="navigator" class="... isIndex"> <ul>内有<li>链接列表- 计算样式
opacity: 0或visibility/display导致不可见
所以这不是「没生成导航」,而是 生成后未被正确展示。
4.3 与 Markdown 正文的关系(单篇页补充)
单篇文章页「整块不显示」曾有 两类独立原因:
| 类型 | 原因 | 处理 |
|---|---|---|
| 目录为空 | 仅扫描正文标题、无 ## 且未包含总标题 |
目录首项固定为 post_title(nicen_theme_build_post_title_catalog_item) |
| 标题对不上 | 默认 meta 模式找 ,Editor.md 存的是 <h2> |
主题迁移为 HTML 标签 模式(document_catelog_mode = html) |
| 点击无效 | 正文 <h2> 无 id |
nicen_theme_fit_html_cat_mode 经 the_content 注入 id='h21' 等 |
当前单篇页:总标题 + 正文章节 均会进入侧栏(nicen_theme_build_body_catalog_items)。本文重点仍是 首页列表导航 + Editor.md 全站脚本。
五、WordPress 脚本加载机制(原理速览)
理解修复方案需要一点 WP 脚本 API 背景。
5.1 wp_enqueue_script 与依赖
wp_enqueue_script( 'handle', $src, $deps, $ver, $in_footer );
$deps:必须先加载的句柄数组(如array('jquery'))。$in_footer:true时脚本在</body>前输出;false时在<head>输出。- 多个插件/主题在
wp_enqueue_scripts钩子上注册,默认优先级 10;后注册的可声明依赖先注册的句柄。
5.2 wp_deregister_script 的风险
wp_deregister_script('jquery') 会移除核心注册的 jquery 句柄。之后:
- 仅声明依赖
jquery的脚本可能 拿不到 jQuery; - 必须使用新句柄(如
jQuery-CDN)并在 同一请求内 由某处wp_enqueue_script('jQuery-CDN')。
若主题在优先级 10 注册、插件在 10 注销、主题在 999 才补救,则 中间任何在 10~999 之间执行且用到 $ 的内联或脚本都会炸。
5.3 为何「优先级 100 / 999」能缓解
主题将 nicen_theme_load_source 挂在 wp_enqueue_scripts, 999:
- 等 Editor.md 完成 jQuery 注销/替换;
- 调用
nicen_theme_ensure_jquery():检测是否已注册jQuery-CDN,统一句柄; wp_add_inline_script( $handle, 'window.$ = window.jQuery = jQuery;', 'after' );- 所有主题脚本
array( $jq, ... )且$in_footer = true。
这样保证:jQuery 先就绪,再执行主题的 main.js / monitor.js / index.js。
六、修复方案(分层说明)
本次采用 插件侧减少误伤 + 主题侧加固 的组合拳。
6.1 插件:按页面类型加载前台资源(根因收敛)
文件:wp-editormd/src/Front/Controller.php
新增 should_enqueue_front_assets():
private function should_enqueue_front_assets() {
$support_other = trim( (string) Config::get_option( "support_other_text", "editor_basics" ) );
if ( $support_other !== "" ) {
return true; // 用户自定义前台编辑器 ID,保留全站加载
}
if ( Config::get_option( "support_front", "editor_basics" ) !== "on" ) {
return false;
}
return is_singular() && comments_open(); // 仅单篇且评论开放
}
在 enqueue_front_styles / enqueue_front_scripts 开头:
if ( ! $this->should_enqueue_front_assets() ) {
return; // 首页直接 return,不再 deregister jquery
}
效果:首页不再加载 Editor.md 前台 bundle,从源头避免 jQuery 被无故替换。
同类调整:
| 模块 | 调整 |
|---|---|
FrontStyle\Controller |
仅 is_singular() 时加载(文内链接新标签页等) |
KaTeX::katex_enqueue_scripts |
仅 is_singular() |
MindMap::mindmap_enqueue_scripts |
仅 is_singular() |
6.2 主题:jQuery 句柄统一与加载顺序
文件:theme-document-1.2.108/include/themes/load.php
function nicen_theme_jquery_handle() {
return wp_script_is( 'jQuery-CDN', 'registered' ) ? 'jQuery-CDN' : 'jquery';
}
function nicen_theme_ensure_jquery() {
$handle = nicen_theme_jquery_handle();
wp_enqueue_script( $handle );
wp_add_inline_script( $handle, 'window.$ = window.jQuery = jQuery;', 'after' );
return $handle;
}
- 钩子优先级 999(
nicen_theme_load_source)。 main、main-monitor、main-index等均array( $jq, ... )+ 页脚加载。- 检测到
WP_EDITORMD_VER时,在全站额外加载主题自带prism.js(含首页),避免历史版本中Prism is not defined。 nicen_theme_editormd_prism_compat()(优先级 1000)仅在Config_Front已注册时为其增加prism依赖;首页修复后通常不加载 Config_Front,主要靠上一条全站prism兜底。
6.3 主题:monitor.js 顶层 $ 防护
文件:common/inline/monitor.js
修复前文件顶部:
$.fn.scrollUnique = function () { ... }; // 解析时即需要 $
改为 IIFE:
(function ($) {
$.fn.scrollUnique = function () { ... };
})(window.jQuery);
即使依赖声明偶发失效,只要 jQuery 已加载,插件方法注册不会拖垮整个文件。
6.4 主题:首页导航不依赖 JS 也能可见(体验兜底)
CSS(assets/extra/normal.scss / style.css):
#navigator {
opacity: 0;
&.isIndex {
opacity: 1; // 首页文章导航
}
}
内联样式(开启首页导航时):
#space #navigator.isIndex, #space #navigator { opacity: 1; }
即使 JS 仍失败,用户也能看到导航列表(仅固定定位可能不够完美,但不会「整块消失」)。
6.5 主题:目录生成不污染主循环
文件:include/functions/common.php
首页 nicen_theme_navigator() 不再对每篇文章 setup_postdata( $post ),改为:
function nicen_theme_can_show_post( $post ) {
// 用 wp_get_post_categories / wp_get_post_tags 按 ID 判断,不依赖全局 $post
}
避免侧栏渲染阶段改动全局 $post,影响随后 have_posts() 文章列表循环。
七、修复后的资源加载时序(首页)
sequenceDiagram
autonumber
participant WP as WordPress
participant EM as WP Editor.md
participant TH as Document 主题
Note over WP,TH: 首页请求 · 修复后
WP->>+EM: wp_enqueue_scripts(prio 10)
Note right of EM: should_enqueue_front_assets()<br/>首页 → false
EM-->>-WP: 跳过 Front/Config<br/>不触碰 jquery
WP->>+TH: wp_enqueue_scripts(prio 999)
TH->>TH: nicen_theme_ensure_jquery()
TH->>TH: enqueue main / monitor / index
TH->>TH: inline:window.$ = jQuery
TH->>TH: CSS navigator.isIndex opacity 1
deactivate TH
opt 仅当存在 Config_Front 时
WP->>TH: wp_enqueue_scripts(prio 1000)
Note right of TH: prism_compat 补依赖
end
WP->>WP: 页脚输出脚本
Note over TH: monitor.js 执行成功<br/>侧栏可见
Note over EM,TH: PrismJSAuto 仍可能在全站加载 Prism,<br/>但不再伴随会注销 jquery 的 Front bundle
八、自查清单(读者可自行排查)
8.1 浏览器控制台
- 无
$ is not defined/jQuery is not defined - 无
Prism is not defined(若仍有,检查 Prism 与 Config_Front 依赖顺序)
8.2 主题设置
- 首页显示左侧导航(
document_show_left_nav)已开启 - 当前页为博客首页,或「设置 → 阅读」为「最新文章」时的静态首页(
is_home()/is_front_page()+show_on_front=posts)
8.3 DOM 检查
- 存在
#space/#navigator.isIndex ul内有li > a[href="#h2xxx"]#navigator计算样式opacity为 1
8.4 插件设置
- 若必须保留全站自定义编辑器 ID(
support_other_text),需接受该 ID 所在页仍会加载 Editor 资源 - 仍有个案时,可开启 Editor.md jQuery 兼容模式
8.5 PHP 层目录为空
若 DOM 根本没有 #space:
- 检查
$wp_query->posts是否为空; - 检查
document_no_display是否把所有文章分类/标签都排除了; - 与 Editor.md 无关,应查查询与主题过滤逻辑。
九、经验总结与最佳实践
9.1 对插件作者
- 前台资源按场景加载:评论编辑器只需
is_singular() && comments_open()(及自定义 ID 页),避免全站wp_deregister_script('jquery')。 - 避免多处重复注销 jQuery:KaTeX、MindMap、Front、FrontStyle 应共用统一的「前台资源是否加载」判断。
- 不要假设全局
$:打包脚本可用window.jQuery,或保证deps正确。
9.2 对主题作者
- 所有脚本声明
jquery/ 兼容句柄依赖,并尽量页脚加载。 - 慎用
opacity: 0作为唯一显隐手段;关键 UI 应有 CSS 兜底或noscript友好。 - 侧栏/目录生成避免
setup_postdata污染主循环;用WP_Post对象 +get_the_title( $post )。 - 与主流 Markdown 插件共存:在
wp_enqueue_scripts较晚优先级统一 jQuery,并window.$ = jQuery。
9.3 对站点维护者
- Document + WP Editor.md 可同时使用;若仅需后台 Markdown,可关闭「前台评论 Markdown」,减少冲突面。
- 排查「导航消失」时,先看控制台,再看 DOM,最后才怀疑 Markdown 解析。
十、相关文件索引
| 角色 | 路径 |
|---|---|
| 首页侧栏模板 | theme-document-1.2.108/template/index/sidebar-index-left.php |
| 目录生成 | theme-document-1.2.108/include/functions/common.php → nicen_theme_navigator() |
| 脚本加载 | theme-document-1.2.108/include/themes/load.php |
| 正文 h2 锚点(HTML 模式) | theme-document-1.2.108/include/themes/initialize.php → nicen_theme_fit_html_cat_mode |
| 导航交互 | theme-document-1.2.108/common/inline/monitor.js |
| 文章 Mermaid | theme-document-1.2.108/include/themes/mermaid.php |
| 插件前台 | wp-editormd/src/Front/Controller.php |
| 插件入口 | wp-editormd/src/Main.php |
十一、结语
WP Editor.md 导致 Document 主题首页文章导航消失,本质不是 Markdown 与目录算法不兼容,而是:
- 插件在 不需要编辑器 的页面仍改变 全局 jQuery 注册方式;
- 主题导航依赖 jQuery 执行显隐/定位,且 CSS 默认
opacity: 0; - 脚本错误导致 「有 DOM、看不见」,表象像功能被删。
通过 收敛插件前台加载范围、主题统一 jQuery 依赖与优先级、CSS/JS 双保险,即可在保留 Markdown 编辑能力的同时恢复首页文章导航。
文档版本:2026-05-27(审校)· 对应 theme-document 1.2.108 与 wp-editormd 10.2.1 修复实践