如何将WordPress InnerBlocks的HTML存储为父区块属性?
解决FAQ区块JSON-LD生成问题的可行方案
方案一:封装通用递归函数提取嵌套InnerBlocks内容
既然你已经在用render_block过滤器,不用每次手动处理嵌套逻辑,写个通用函数就能一次性提取所有层级的InnerBlocks内容:
function get_all_inner_block_html( $blocks ) { $html = ''; foreach ( $blocks as $block ) { // 拼接当前区块的HTML内容 $html .= $block['innerHTML']; // 递归处理嵌套的子区块 if ( ! empty( $block['innerBlocks'] ) ) { $html .= get_all_inner_block_html( $block['innerBlocks'] ); } } return $html; } // 在render_block过滤器中使用 add_filter( 'render_block', function( $block_content, $block ) { // 仅处理你的FAQ区块,替换为实际的区块名称 if ( 'your-namespace/faq-block' !== $block['blockName'] ) { return $block_content; } $question = isset( $block['attrs']['question'] ) ? $block['attrs']['question'] : ''; $answer_html = get_all_inner_block_html( $block['innerBlocks'] ); // 生成JSON-LD结构化数据 $json_ld = sprintf( '<script type="application/ld+json"> { "@context": "https://schema.org", "@type": "FAQPage", "mainEntity": [{ "@type": "Question", "name": "%s", "acceptedAnswer": { "@type": "Answer", "text": "%s" } }] } </script>', esc_attr( $question ), esc_attr( $answer_html ) ); // 将JSON-LD注入wp_head add_action( 'wp_head', function() use ( $json_ld ) { echo $json_ld; }); return $block_content; }, 10, 2 );
这个函数只需写一次就能复用,不管嵌套多少层InnerBlocks,都会自动拼接所有内容的HTML。
方案二:监听编辑器变化,将InnerBlocks内容存入区块属性
虽然InnerBlocks本身没有value和onChange属性,但可以通过编辑器的数据监听,把InnerBlocks的序列化内容存到区块的content属性中:
在你的Edit.js组件中添加以下代码:
import { useSelect, useDispatch } from '@wordpress/data'; import { useEffect } from '@wordpress/element'; // 在Edit组件内部 const { clientId, setAttributes } = props; const { getBlock } = useSelect( ( select ) => select( 'core/block-editor' ), [] ); const { updateBlockAttributes } = useDispatch( 'core/block-editor' ); useEffect( () => { const currentBlock = getBlock( clientId ); if ( currentBlock ) { // 序列化InnerBlocks内容 const serializedContent = wp.blocks.serialize( currentBlock.innerBlocks ); // 更新区块的content属性 updateBlockAttributes( clientId, { content: serializedContent } ); } }, [ clientId, getBlock, updateBlockAttributes ] );
之后在PHP中,直接通过$block['attrs']['content']获取序列化内容,再解析成HTML即可:
$answer_html = wp_kses_post( do_shortcode( $block['attrs']['content'] ) );
注意:这种方式会增加区块属性的存储体积,FAQ场景下影响较小。
方案三:改用服务器端渲染(SSR)区块
如果你的区块适合服务器端渲染,可以在block.json中指定render_callback,直接在PHP中处理内容渲染和JSON-LD生成:
修改block.json:
{ "apiVersion": 3, "name": "your-namespace/faq-block", "title": "FAQ Block", "category": "widgets", "attributes": { "question": { "type": "string", "selector": "h1,h2,h3,h4,h5,h6" } }, "editorScript": "file:./index.js", "render": "file:./render.php" }
创建render.php文件:
<?php $question = isset( $attributes['question'] ) ? $attributes['question'] : ''; // 渲染所有InnerBlocks并获取HTML ob_start(); echo '<div class="faq-answer">'; foreach ( $inner_blocks as $block ) { echo render_block( $block ); } echo '</div>'; $answer_html = ob_get_clean(); // 生成JSON-LD并注入wp_head $json_ld = sprintf( '<script type="application/ld+json"> { "@context": "https://schema.org", "@type": "FAQPage", "mainEntity": [{ "@type": "Question", "name": "%s", "acceptedAnswer": { "@type": "Answer", "text": "%s" } }] } </script>', esc_attr( $question ), esc_attr( $answer_html ) ); add_action( 'wp_head', function() use ( $json_ld ) { echo $json_ld; }); // 返回区块前端渲染内容 echo '<div class="faq-block">'; echo '<h3 class="faq-question">' . esc_html( $question ) . '</h3>'; echo $answer_html; echo '</div>'; ?>
这种方式由服务器自动处理所有嵌套区块的渲染,不用手动写递归逻辑,实现更省心。
内容的提问来源于stack exchange,提问作者Walrus
相关产品推荐
相关产品推荐

