WordPress:如何将基于H2标题的目录实现为Gutenberg自定义块?
适配Gutenberg块的目录生成方案
不需要完全重写现有代码,但要针对Gutenberg块的渲染逻辑做适配,同时修复原代码里的几个小问题,具体调整如下:
核心问题分析
原代码在模板里能正常运行,是因为模板处于文章循环的上下文里,get_the_ID()能稳定拿到当前文章ID;但Gutenberg块的渲染(尤其是编辑器预览场景)是独立执行的,上下文可能丢失,导致get_the_ID()拿不到正确值,另外原代码还有结构和语法bug,比如:
- 错误的
<div">标签(多了引号) sprintf参数数量不匹配(格式串2个占位符,传了4个参数)- 没有正确生成列表结构(只有a标签,缺失ul/li)
- DOM查询逻辑不准确(
contains("h2", name())会匹配类似h20的无效标签)
修改后的Gutenberg块实现
1. 注册自定义块
先注册块的基本结构:
function register_custom_toc_block() { register_block_type( 'custom/table-of-contents', [ 'render_callback' => 'render_custom_toc_block', 'attributes' => [], // 可扩展添加显示标题、层级控制等属性 'editor_style' => 'wp-block-library', // 复用编辑器默认样式 ] ); } add_action( 'init', 'register_custom_toc_block' );
2. 编写块渲染函数
修复原代码并适配Gutenberg上下文:
function render_custom_toc_block( $attributes, $content, $block ) { // 优先从块上下文获取文章ID(编辑器预览场景), fallback到当前文章ID $post_id = isset( $block->context['postId'] ) ? $block->context['postId'] : get_the_ID(); if ( ! $post_id || ! get_post( $post_id ) ) { return '<p class="toc-empty">请在文章编辑页面使用此块</p>'; } // 获取并处理文章内容 $post_content = apply_filters( 'the_content', get_post_field( 'post_content', $post_id ) ); $post_content = str_replace( ']]>', ']]>', $post_content ); // DOM解析提取H2标题 libxml_use_internal_errors( true ); $dom = new DOMDocument(); $dom->loadHTML( '<?xml encoding="utf-8" ?>' . $post_content ); libxml_clear_errors(); $xpath = new DOMXPath( $dom ); $headings = $xpath->query( '//h2' ); // 准确匹配H2标签 if ( ! $headings || $headings->length === 0 ) { return '<p class="toc-empty">本文暂无H2标题</p>'; } // 构建目录HTML结构 $toc_html = '<div class="custom-toc"><h3 class="toc-title">目录</h3><ul class="toc-list">'; $current_level = 2; // 起始层级为H2 foreach ( $headings as $heading ) { $heading_level = (int) $heading->tagName[1]; $heading_id = $heading->getAttribute( 'id' ); // 自动生成缺失的标题ID if ( empty( $heading_id ) ) { $heading_id = sanitize_title( $heading->nodeValue ); } $heading_text = esc_html( $heading->nodeValue ); // 处理层级嵌套(支持H3扩展) while ( $heading_level > $current_level ) { $toc_html .= '<ul class="toc-sub-list">'; $current_level++; } while ( $heading_level < $current_level ) { $toc_html .= '</ul></li>'; $current_level--; } $toc_html .= sprintf( '<li class="toc-item"><a href="#%s" class="toc-link">%s</a>', esc_attr( $heading_id ), $heading_text ); } // 关闭剩余的嵌套列表标签 while ( $current_level > 2 ) { $toc_html .= '</ul></li>'; $current_level--; } $toc_html .= '</li></ul></div>'; return $toc_html; }
关键适配点
- 上下文适配:通过
$block->context['postId']获取编辑器内的当前文章ID,解决块渲染时的上下文丢失问题; - 输出方式调整:Gutenberg块的渲染函数需要返回HTML字符串,而非直接
echo; - 结构修复:正确生成ul/li层级结构,修复原代码的标签错误;
- 容错处理:添加文章不存在、无H2标题等场景的提示;
- ID补全:自动为无ID的H2标题生成唯一ID,保证锚点跳转有效。
内容的提问来源于stack exchange,提问作者Cray
相关产品推荐
相关产品推荐

