gutenbergdocs/docs/how-to-guides/metabox.md
2025-10-22 01:40:18 +08:00

265 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## 补充资源
- [创建存储文章元数据的自定义区块](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 <h4> %s </h4>", $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 文档类型(`<!DOCTYPE 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
<?php
// 注册自定义元标签字段
function myguten_register_post_meta() {
register_post_meta( 'post', 'myguten_meta_block_field', array(
'show_in_rest' => 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 (
<div { ...blockProps }>
<TextControl
__nextHasNoMarginBottom
__next40pxDefaultSize
label="元数据区块字段"
value={ metaFieldValue }
onChange={ updateMetaValue }
/>
</div>
);
},
// 不保存信息至区块
// 数据通过钩子保存至文章元数据
save: () => {
return null;
},
} );
```
创建文章并添加元数据区块即可验证功能。您将看到可输入值的字段。当保存文章(草稿或已发布)时,文章元数据值也会同步保存。可通过保存后重新加载草稿来验证——重新加载后表单仍将保留输入内容。
您还可以检查数据库表`wp_postmeta`确认新文章ID包含新字段数据。
**故障排除**请确保在每次修改后重新构建代码您更新了步骤1的PHP代码且JavaScript文件已正确加入队列。检查构建输出和开发者控制台是否有错误信息。