## 补充资源 - [创建存储文章元数据的自定义区块](https://developer.wordpress.org/news/2023/03/03/creating-a-custom-block-that-stores-post-meta/) ### 第三步:使用文章元数据 您可以通过多种方式使用上一步存储的文章元数据。 #### 在 PHP 中使用文章元数据 第一个示例使用文章元字段的值,并将其包裹在 `H4` 标签中附加到文章内容的末尾。 ```php function myguten_content_filter( $content ) { $value = get_post_meta( get_the_ID(), 'myguten_meta_block_field', true ); if ( $value ) { return sprintf( "%s

%s

", $content, esc_html( $value ) ); } else { return $content; } } add_filter( 'the_content', 'myguten_content_filter' ); ``` #### 在区块中使用文章元数据 您也可以在其他区块中使用文章元数据。在此示例中,数据会在每个段落区块渲染时(即显示给用户时)加载到其末尾。您可以根据需要将其替换为任何核心或自定义区块类型。 在 PHP 中,使用 [register_block_type](https://developer.wordpress.org/reference/functions/register_block_type/) 函数设置区块渲染时的回调,以包含元值。 ```php function myguten_render_paragraph( $block_attributes, $content ) { $value = get_post_meta( get_the_ID(), 'myguten_meta_block_field', true ); // 输出前检查值是否已设置 if ( $value ) { return sprintf( "%s (%s)", $content, esc_html( $value ) ); } else { return $content; } } register_block_type( 'core/paragraph', array( 'api_version' => 3, 'render_callback' => 'myguten_render_paragraph', ) ); ``` ### 第四步:使用区块模板(可选) 使用元区块的一个问题是作者很容易忘记添加,因为它需要添加到每篇文章中。您可以通过使用[区块模板](/docs/reference-guides/block-api/block-templates.md)来解决这个问题。区块模板是按文章类型预定义的区块项列表。模板允许您为文章类型指定默认的初始状态。 在此示例中,您将使用模板自动在文章顶部插入元区块。 将以下代码添加到 `myguten-meta-block.php` 文件中: ```php function myguten_register_template() { $post_type_object = get_post_type_object( 'post' ); $post_type_object->template = array( array( 'myguten/meta-block' ), ); } add_action( 'init', 'myguten_register_template' ); ``` 您还可以在数组中添加其他区块类型,包括占位符,甚至可以将文章锁定为一组特定的区块。模板是控制编辑体验的强大工具,更多信息请参阅上面链接的文档。 ## 总结 本指南展示了如何使用区块读取和写入文章元数据。以下部分介绍了与现有元框的向后兼容性。 ## 向后兼容性 ### 测试、转换和维护现有元框 在将元框转换为区块之前,可以先测试元框是否与区块编辑器兼容,并明确标记。 如果某个元框与区块编辑器不兼容,且无法更新以使其正常工作,下一步是在元框声明中添加 `__block_editor_compatible_meta_box` 参数: ```php add_meta_box( 'my-meta-box', 'My Meta Box', 'my_meta_box_callback', null, 'normal', 'high', array( '__block_editor_compatible_meta_box' => false, ) ); ``` WordPress 不会显示该元框,而是会显示一条消息,说明它与区块编辑器不兼容,并包含指向经典编辑器插件的链接。默认情况下,`__block_editor_compatible_meta_box` 为 `true`。 将元框转换为区块后,可以声明其存在以保持向后兼容性: ```php add_meta_box( 'my-meta-box', 'My Meta Box', 'my_meta_box_callback', null, 'normal', 'high', array( '__back_compat_meta_box' => true, ) ); ``` 当使用区块编辑器时,此元框将不再显示在元框区域中,因为它现在仅用于向后兼容。在经典编辑器中,它将像以前一样显示。 ### 元数据框数据收集 在每次区块编辑器页面加载时,我们会注册一个用于收集元数据框数据的操作,以判断某个区域是否为空。收集元数据框数据后,原始全局状态将被重置。 详见 [`register_and_do_post_meta_boxes`](https://developer.wordpress.org/reference/functions/register_and_do_post_meta_boxes/)。 该操作将遍历 `post.php` 用于注册元数据框的函数和钩子,包括 `add_meta_boxes`、`add_meta_boxes_{$post->post_type}` 和 `do_meta_boxes`。 元数据框会经过过滤,移除所有核心元数据框、标准自定义分类法元数据框,以及任何声明仅用于向后兼容的元数据框。 随后检查该特定类型元数据框的每个位置是否处于活动状态。若非空则存储值为 true,若为空则存储值为 false。这些元数据框位置数据随后会通过编辑器 Redux 存储库在 `INITIALIZE_META_BOX_STATE` 中分发。 理想情况下,这可以在编辑器实例化时完成,从而简化流程。但在 `admin_enqueue_scripts`(即调用 `initializeEditor()` 的阶段)之前无法获知元数据框状态。除非我们将 `initializeEditor()` 移至页脚或 `admin_head` 之后的某个阶段执行,否则目前只能如此处理。随着编辑器引导机制的最新改进,现在可能已具备可行性。需使用 ACF 进行测试验证。 ### Redux 与 React 元数据框管理 渲染区块编辑器时,元数据框会被渲染到隐藏的 `#metaboxes` 容器中。 *Redux 存储库默认将所有元数据框设为非活动状态*。当接收到 `INITIALIZE_META_BOX_STATE` 时,存储库会将活动元数据框区域的 `isActive` 标志更新为 `true`。随后 React 将检查 Redux 传递给 `MetaBox` 组件的新属性。若该 `MetaBox` 处于活动状态,则会渲染 `MetaBoxArea` 组件而非空内容。`MetaBox` 组件是协调 `MetaBoxArea` 与 Redux 存储库的容器组件。*若无活动元数据框,则保持默认状态。由于所有核心元数据框已被移除,这将成为默认行为。* #### MetaBoxArea 组件 组件渲染时会存储元数据框容器的引用,并从预取位置获取元数据框的 HTML 内容。 文章更新时,仅会提交处于活动状态的元数据框区域,以避免不必要的请求。元数据框提交不会创建额外修订版本。任何活动元数据框在触发 `REQUEST_POST_UPDATE` 时都会激活 Redux 操作(参见 `editor/effects.js`)。`REQUEST_META_BOX_UPDATES` 操作会将该元数据框状态设为 `isUpdating`。`isUpdating` 属性将传递至 `MetaBoxArea` 并触发表单提交。 当元数据框区域保存时,我们会显示更新遮罩层,防止用户在保存过程中修改表单值。 示例保存地址形如: `example.org/wp-admin/post.php?post=1&action=edit&meta-box-loader=1` 该地址通过 `_wpMetaBoxUrl` 全局变量自动传递给 React。 此页面模拟 `post.php` 的文章表单,提交时会触发所有常规钩子和操作,并具备正确的全局状态以正常执行所有 PHP 元数据框逻辑,无需修改现有代码。提交成功后,React 会触发 `handleMetaBoxReload` 来移除更新遮罩。 ### 常见兼容性问题 大多数 PHP 元数据框在区块编辑器中应能继续工作,但包含高级功能的元数据框可能会出现异常。以下是元数据框在区块编辑器中可能无法正常工作的常见原因: - 依赖针对旧编辑器文章标题、内容字段及其他元数据框选择器的插件 - 依赖 TinyMCE API 的插件(区块编辑器中不再存在单一 TinyMCE 实例) - 在“提交”或“保存”时更新 DOM 的插件 另请注意:若插件触发输出 PHP 警告或通知,将导致 HTML 文档类型(``)输出异常,从而使浏览器启用“怪异模式”(当浏览器无法识别文档类型时激活的兼容模式)。区块编辑器不适用于此模式,但可能*看似*正常运行。若遇到*元数据框覆盖编辑器*等布局问题,请检查网页源代码确认文档类型声明是否为页面首行内容。JavaScript 控制台也会显示相关警告提示。 # 元数据框 ## 概述 在区块编辑器出现之前,自定义元数据框被用于扩展编辑器功能。现在有了新的扩展方式,既赋予开发者更多能力,又为内容创作者带来更佳体验。建议将旧版自定义元数据框迁移至以下新方法之一,为编辑器用户创造更统一连贯的体验。 区块编辑器确实支持大多数现有元数据框,详见[下文向后兼容性说明](#向后兼容性)。 若您需要在编辑器外部处理文章元数据,请参阅[侧边栏教程](/docs/how-to-guides/sidebar-tutorial/plugin-sidebar-0.md)。 ### 使用区块存储元数据 通常区块会将属性值存储在序列化的区块HTML中。但您也可以创建将属性值保存为文章元数据的区块,这样就能在模板的任何位置通过编程方式访问这些数据。 本指南将演示如何创建能够提示用户输入单个值,并将其保存为文章元数据的区块。 ## 准备工作 本指南假设您已熟悉WordPress插件、文章元数据和基础JavaScript。建议先学习[JavaScript入门教程](/docs/getting-started/fundamentals/javascript-in-the-block-editor.md)打好基础。 虽然本指南将逐步创建基础区块,但推荐通过[创建区块教程](/docs/getting-started/tutorial.md)来更深入理解自定义区块的开发流程。 您需要准备: - WordPress开发环境 - 已激活并可编辑的基础插件 - 配置好构建和队列加载的JavaScript环境 您可参考[完整的元数据区块示例](https://github.com/WordPress/block-development-examples/tree/trunk/plugins/meta-block-bb1e55)来搭建开发环境。 ## 分步指南 1. [注册元字段](#步骤1-注册元字段) 2. [添加元数据区块](#步骤2-添加元数据区块) 3. [使用文章元数据](#步骤3-使用文章元数据) 4. [收尾工作](#步骤4-使用区块模板-可选) ### 步骤1:注册元字段 文章元字段是用于存储文章扩展数据的WordPress对象。使用前需先注册新元字段。详见[文章元数据管理](https://developer.wordpress.org/plugins/metadata/managing-post-metadata/)文档。 注册字段时请注意`show_in_rest`参数,这能确保数据被包含在REST API中(区块编辑器通过该API加载和保存元数据)。更多信息请参阅[`register_post_meta`](https://developer.wordpress.org/reference/functions/register_post_meta/)函数说明。 此外,文章类型需支持`custom-fields`才能使`register_post_meta`函数正常工作。 将以下代码添加到PHP插件中以注册字段: ```php true, 'single' => true, 'type' => 'string', ) ); } add_action( 'init', 'myguten_register_post_meta' ); ``` ### 步骤2:添加元数据区块 完成上一步的元字段注册后,接下来创建用于向用户显示字段值的新区块。 区块可通过`useEntityProp`钩子获取或修改元数据值。 将以下代码添加到JavaScript `src/index.js`: ```js import { registerBlockType } from '@wordpress/blocks'; import { TextControl } from '@wordpress/components'; import { useSelect } from '@wordpress/data'; import { useEntityProp } from '@wordpress/core-data'; import { useBlockProps } from '@wordpress/block-editor'; registerBlockType( 'myguten/meta-block', { edit: ( { setAttributes, attributes } ) => { const blockProps = useBlockProps(); const postType = useSelect( ( select ) => select( 'core/editor' ).getCurrentPostType(), [] ); const [ meta, setMeta ] = useEntityProp( 'postType', postType, 'meta' ); const metaFieldValue = meta[ 'myguten_meta_block_field' ]; const updateMetaValue = ( newValue ) => { setMeta( { ...meta, myguten_meta_block_field: newValue } ); }; return (
); }, // 不保存信息至区块 // 数据通过钩子保存至文章元数据 save: () => { return null; }, } ); ``` 创建文章并添加元数据区块即可验证功能。您将看到可输入值的字段。当保存文章(草稿或已发布)时,文章元数据值也会同步保存。可通过保存后重新加载草稿来验证——重新加载后表单仍将保留输入内容。 您还可以检查数据库表`wp_postmeta`,确认新文章ID包含新字段数据。 **故障排除**:请确保在每次修改后重新构建代码(您更新了步骤1的PHP代码,且JavaScript文件已正确加入队列)。检查构建输出和开发者控制台是否有错误信息。