
本文详解如何将原本通过 the_content 过滤器实现的动态目录逻辑,重构为可复用、可插入任意位置的 WordPress 短代码 [toc_content],解决直接复用原函数导致输出为空的问题。
本文详解如何将原本通过 `the_content` 过滤器实现的动态目录逻辑,重构为可复用、可插入任意位置的 wordpress 短代码 `[toc_content]`,解决直接复用原函数导致输出为空的问题。
WordPress 中,将内容处理逻辑从 the_content 过滤器迁移到短代码(shortcode)时,必须适配短代码的调用签名与执行上下文。原始 create_toc($html) 函数设计为接收 $html(即文章正文 HTML 字符串)并返回「目录 + 修改后的 HTML」,但短代码回调函数的参数完全不同:
- 第一个参数是 $atts(属性数组,如 [toc_content depth="2"] 中的 array('depth' => '2'));
- 第二个参数是 $content(短代码包裹的内容,如 [toc_content]Hello[/toc_content] 中的 'Hello');
- 第三个参数是 $tag(短代码名称,如 'toc_content')。
因此,直接 add_shortcode('toc_content', 'create_toc') 会导致 $html 实际接收的是空数组 $atts,后续 DOM 解析必然失败,最终返回空字符串。
✅ 正确做法是:编写专用于短代码的独立函数,该函数主动获取当前文章内容(而非依赖传入),生成目录 HTML,并仅返回目录部分(短代码本身不负责重写全文):
function shortcode_toc_content($atts = array(), $content = null, $tag = '') {
// 仅在单篇文章页面生效
if (!is_single()) {
return '';
}
// 获取当前文章内容(注意:需确保已全局 $post 可用)
global $post;
if (!$post || empty($post->post_content)) {
return '<div class="toc-bound"><p class="toc-empty">暂无内容,无法生成目录。</p></div>';
}
// 使用 DOMDocument 解析 post_content(同原逻辑,但来源明确)
$html = apply_filters('the_content', $post->post_content); // 应用格式化(如 wpautop)
$dom = new DOMDocument();
libxml_use_internal_errors(true);
$dom->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'));
libxml_clear_errors();
$toc = '<div class="toc-bound">
<div class="toc-ctr">目录</div>
<ul class="toc">';
$i = 1;
$xpath = new DOMXPath($dom);
$expression = '//*[contains(concat(" ", normalize-space(@class), " "), " toc-item ")]';
foreach ($xpath->evaluate($expression) as $element) {
$text = trim($element->textContent);
if (empty($text)) continue;
$toc .= sprintf(
'<li><a href="%s#toc-%d">%s</a></li>',
esc_url(get_the_permalink()),
$i,
esc_html($text)
);
$element->setAttribute('id', 'toc-' . $i);
$i++;
}
$toc .= '</ul>
</div>';
// 关键:只返回目录 HTML,不拼接全文(短代码不修改原文)
return $toc;
}
add_shortcode('toc_content', 'shortcode_toc_content');
? 使用方式:
在文章编辑器中任意位置插入:
[toc_content]
并在需要锚点跳转的标题/区块上添加 class="toc-item",例如:
<h2 class="toc-item">安装步骤</h2> <div class="toc-item">配置说明</div>
⚠️ 注意事项:
- 短代码不会自动为 .toc-item 元素添加 ID —— 上述代码已在 DOM 中完成 id="toc-1" 等设置,但需确保 the_content 过滤器执行后 DOM 已渲染(通常没问题);
- 若主题或插件对 the_content 做了深度缓存/延迟加载,可能影响短代码内获取的内容准确性,建议配合 wp_reset_postdata() 或在 loop_start 后调用;
- 如需支持多级目录(如 h2/h3),应扩展 XPath 表达式并维护嵌套层级状态,而非简单线性
- ;
- 生产环境建议增加 ob_start() + ob_get_clean() 包裹 DOM 操作,避免因警告/notice 导致输出中断。
通过此重构,[toc_content] 成为真正解耦、可复用、符合 WordPress 短代码规范的目录组件,既保持原有功能,又获得灵活部署能力。











