# 绑定

<div class="callout callout-alert">
区块绑定 API 仅适用于 WordPress 6.5 及以上版本。
</div>

区块绑定 API 允许你将动态数据“绑定”到区块的属性上，这些数据随后会反映在最终输出到前端浏览器的 HTML 标记中。

例如，可以将图像区块的 `url` 属性连接到一个函数，该函数从外部 API 返回随机图像。

```html
<!-- wp:image {
	"metadata":{
		"bindings":{
			"url":{
				"source":"my-plugin/get-random-images"
			}
		}
	}
} -->
```

## Compatible blocks and their attributes

Right now, not all block attributes are compatible with block bindings. There is some ongoing effort to increase this compatibility, but for now, this is the default list:

| Supported Blocks         | Supported Attributes              |
| ------------------------ | --------------------------------- |
| core/image               | id, url, title, alt, caption      |
| core/heading             | content                           |
| core/paragraph           | content                           |
| core/button              | url, text, linkTarget, rel        |
| core/navigation-link     | url                               |
| core/navigation-submenu  | url                               |
| core/post-date           | datetime                          |

## 核心数据源

WordPress 内置了多个区块绑定数据源，无需自定义注册即可使用：

- `core/post-meta`
- `core/post-data`
- `core/term-data`
- `core/pattern-overrides`

### core/post-meta

`core/post-meta` 源允许你将区块属性绑定到文章元字段。

**要求：**

-   文章元必须通过 `show_in_rest => true` 注册
-   文章元键名不能以下划线开头（受保护的键名不可访问）

**使用示例：**

首先，注册你的文章元：

```php
register_meta(
	'post',
	'my_custom_field',
	array(
		'show_in_rest' => true,
		'single'       => true,
		'type'         => 'string',
	)
);
```

然后将其绑定到区块属性：

```html
<!-- wp:paragraph {
	"metadata":{
		"bindings":{
			"content":{
				"source":"core/post-meta",
				"args":{"key":"my_custom_field"}
			}
		}
	}
} -->
<p>回退内容</p>
<!-- /wp:paragraph -->
```

### core/post-data

_**注意：** 自 WordPress 6.9 起。_

`core/post-data` 数据源提供对文章数据字段的访问。

**可用字段：**

-   `date` - 文章发布日期
-   `modified` - 文章最后修改日期
-   `link` - 文章固定链接

**使用示例：**

```html
<!-- wp:paragraph {
	"metadata":{
		"bindings":{
			"content":{
				"source":"core/post-data",
				"args":{"field":"date"}
			}
		}
	}
} -->
<p>回退内容</p>
<!-- /wp:paragraph -->
```

### core/term-data

_**注意：** 自 WordPress 6.9 起。_

当存在分类术语上下文时，`core/term-data` 数据源提供对分类术语数据字段的访问。它需要从区块上下文中获取 `termId` 和 `taxonomy` 才能正常工作。

#### Available Fields

| Field | Description | Example Output |
|-------|-------------|----------------|
| `id` | Term ID | `123` |
| `name` | Term name | `Category Name` |
| `link` | URL to term archive | `https://example.com/category/news` |
| `slug` | URL-friendly slug | `category-slug` |
| `description` | Term description | `A description of the category` |
| `parent` | Parent term ID (hierarchical taxonomies) | `0` |
| `count` | Number of posts in this term | `5` |

#### 示例用法

**在列表中显示分类名称：**

```html
<!-- wp:terms-query {"termQuery":{"taxonomy":"category","perPage":5}} -->
<div class="wp-block-terms-query">
	<!-- wp:term-template {"layout":{"type":"default"}} -->
	<!-- wp:paragraph {"metadata":{"bindings":{"content":{"source":"core/term-data","args":{"field":"name"}}}}} -->
	<p>分类名称</p>
	<!-- /wp:paragraph -->
	<!-- /wp:term-template -->
</div>
<!-- /wp:terms-query -->
```

**创建带链接的分类归档页面：**

```html
<!-- wp:terms-query {"termQuery":{"taxonomy":"post_tag","perPage":10}} -->
<div class="wp-block-terms-query">
	<!-- wp:term-template {"layout":{"type":"default"}} -->
	<!-- wp:paragraph {"metadata":{"bindings":{"content":{"source":"core/term-data","args":{"field":"name"}}}}} -->
	<p><a href="#">标签名称</a></p>
	<!-- /wp:paragraph -->
	<!-- /wp:term-template -->
</div>
<!-- /wp:terms-query -->
```

#### 上下文要求

[`core/term-data`](https://github.com/WordPress/gutenberg/tree/trunk/packages/editor/src/bindings/term-data.js) 源文件在以下上下文中工作：

1.  **任何提供术语上下文的区块** - 内置区块如 [`core/term-template`](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src/term-template)，或通过区块上下文提供 `termId` 和 `taxonomy` 的自定义区块
2.  **导航区块** - 为 `core/navigation-link` 和 `core/navigation-submenu` 提供特殊的向后兼容处理（这些区块从区块属性而非上下文中读取数据）

### core/pattern-overrides

The `core/pattern-overrides` source enables pattern instances to have their content overridden on a per-instance basis. This is particularly useful for synced patterns where you want to allow specific blocks to be customized while keeping the rest of the pattern synchronized .

**How it works:**

-   Pattern blocks can define which attributes are overridable using `metadata.bindings`
-   Each pattern instance stores its override values in the `content` attribute
-   The binding connects the block attribute to the override value using the block's `metadata.name` as a key
-   The context structure follows: `pattern/overrides → {block_name} → {attribute_name}`

**Example usage:**

In the pattern definition, mark blocks as overridable:

```html
<!-- wp:paragraph {
   "metadata":{
      "bindings":{
         "content":{
            "source":"core/pattern-overrides"
         }
      },
      "name":"custom-heading"
   }
} -->
<p>Default heading text</p>
<!-- /wp:paragraph -->
```

When the pattern is instantiated, users can override the content for that specific instance:

```html
<!-- wp:block {"ref":123,"content":{"custom-heading":{"content":"My custom heading text"}}} / -->
```

In this example:

-   **`custom-heading`** is a unique identifier for the `core/paragraph` block within the `core/pattern-overrides` system.
-   It acts as a key in the overrides context structure: `pattern/overrides → custom-heading → content`.
-   This identifier allows multiple blocks of the same type (e.g., `core/paragraph`) within a pattern to have distinct, per-instance attribute overrides using `metadata.name`.

For instance, `"custom-heading"` links the specific paragraph block's `content` attribute to its override value (`"My custom heading text"`) for a particular pattern instance.

### 扩展支持的属性

_**注意：** 自 WordPress 6.9 起。_

开发者可以使用 `block_bindings_supported_attributes` 过滤器来扩展支持的属性列表。此过滤器允许为额外的块属性添加支持。

有两个可用的过滤器：

- `block_bindings_supported_attributes`：一个通用过滤器，接收支持的属性数组和块类型名称。
- `block_bindings_supported_attributes_{$block_type}`：一个针对特定块类型的动态过滤器（例如，`block_bindings_supported_attributes_core/image`）。

为 Image 块添加 `caption` 属性支持的示例：

```php
add_filter(
	'block_bindings_supported_attributes_core/image',
	function ( $supported_attributes ) {
		$supported_attributes[] = 'caption';
		return $supported_attributes;
	}
);
```

为自定义块添加支持的示例：

```php
add_filter(
	'block_bindings_supported_attributes_my-plugin/my-block',
	function ( $supported_attributes ) {
		$supported_attributes[] = 'title';
		$supported_attributes[] = 'description';
		return $supported_attributes;
	}
);
```

此过滤器也会影响哪些块和属性可用于模式覆盖，因为这两个功能共享相同的基础支持属性配置。

## 注册自定义数据源

注册数据源需要至少定义 `name`、`label` 以及一个 `callback` 函数，该函数从数据源获取值并传递给区块属性。

数据源注册后，任何支持区块的 `metadata.bindings` 属性均可配置为从该数据源读取值。

注册可通过 PHP 在服务器端完成，或通过 JavaScript 在编辑器内完成，两种方式可共存。

服务器端注册定义的标签将被编辑器内定义的标签覆盖。

### Server registration

Server registration allows applying a callback that will be executed on the frontend for the bound attribute.

The function to register a custom source is `register_block_bindings_source($name, $args)`:

-   `name`: `string` that sets the unique ID for the custom source.
-   `args`: `array` that contains:
    -   `label`: `string` with the human-readable name of the custom source.
    -   `uses_context`: `array` with the block context that is passed to the callback (optional).
    -   `get_value_callback`: `function` that will run on the bound block's render function. It accepts three arguments: `source_args`, `block_instance` and `attribute_name`. This value can be overridden with the filter `block_bindings_source_value`.

Note that `register_block_bindings_source()` should be called from a handler attached to the `init` hook.

Here is an example:

```php
add_action(
	'init',
	function () {
		register_block_bindings_source(
			'wpmovies/visualization-date',
			array(
				'label'              => __( 'Visualization Date', 'custom-bindings' ),
				'get_value_callback' => function ( array $source_args, $block_instance ) {
					$post_id = $block_instance->context['postId'];
					if ( isset( $source_args['key'] ) ) {
						return get_post_meta( $post_id, $source_args['key'], true );
					}
				},
				'uses_context'       => array( 'postId' ),
			)
		);
	}
);
```

This example needs a `post_meta` registered, and, also, a filter can be used to return a default `$visualization_date` value, which will be shown in the next heading.

```php
add_action(
	'init',
	function () {
		register_meta(
			'post',
			'wp_movies_visualization_date',
			array(
				'show_in_rest' => true,
				'single'       => true,
				'type'         => 'string',
				'label'        => __( 'Movie visualization date', 'custom-bindings' ),
			)
		);
	}
);
```

<div class="callout callout-alert">
<strong>Note:</strong> Post meta keys that begin with an underscore (e.g. `_example_key`) are protected and cannot be used with Block Bindings. Additionally, post meta must be registered with `show_in_rest = true` to be available through the Block Bindings API.
</div>

#### Block bindings source value filter

_**Note:** Since WordPress 6.7._

The value returned by `get_value_callback` can be modified with the `block_bindings_source_value` filter.
The filter has the following parameters:

-   `value`: The value to be filtered.
-   `name`: The name of the source.
-   `source_args`: `array` containing source arguments.
-   `block_instance`: The block instance object.
-   `attribute_name`: The name of the attribute.

Example:

```php
function wpmovies_format_visualization_date( $value, $name ) {
	// Prevent the filter to be applied to other sources.
	if ( $name !== 'wpmovies/visualization-date' ) {
		return $value;
	}
	if ( ! $value ) {
		return date( 'm/d/Y' );
	}
	return date( 'm/d/Y', strtotime( $value ) );
}

add_filter( 'block_bindings_source_value', 'wpmovies_format_visualization_date', 10, 2 );
```

#### 服务器注册核心示例

Core 中有几个示例可供参考。

-   文章元数据。[源代码](https://github.com/WordPress/wordpress-develop/blob/trunk/src/wp-includes/block-bindings/post-meta.php)
-   文章数据。[源代码](https://github.com/WordPress/wordpress-develop/blob/trunk/src/wp-includes/block-bindings/post-data.php)
-   分类数据。[源代码](https://github.com/WordPress/wordpress-develop/blob/trunk/src/wp-includes/block-bindings/term-data.php)
-   模式覆盖。[源代码](https://github.com/WordPress/wordpress-develop/blob/trunk/src/wp-includes/block-bindings/pattern-overrides.php)
-   Twenty Twenty-Five 主题。[源代码](https://github.com/WordPress/wordpress-develop/blob/trunk/src/wp-content/themes/twentytwentyfive/functions.php)

### Editor registration

_**Note:** Since WordPress 6.7._

Editor registration on the client allows defining what the bound block will do when the value is retrieved or when the value is edited.

The function to register a custom source is `registerBlockBindingsSource( args )`:

-   `args`: `object` with the following structure:
    -   `name`: `string` with the unique and machine-readable name.
    -   `label`: `string` with the human readable name of the custom source. In case it was defined already on the server, the server label will be overridden by this one, in that case, it is not recommended to be defined here. (optional)
    -   `usesContext`: `array` with the block context that the custom source may need. In case it was defined already on the server, it should not be defined here. (optional)
    -   `getValues`: `function` that retrieves the values from the source. (optional)
    -   `setValues`: `function` that allows updating the values connected to the source. (optional)
    -   `canUserEditValue`: `function` to determine if the user can edit the value. The user won't be able to edit by default. (optional)
    -   `getFieldsList`: `function` that returns available fields for the UI dropdown selector. (_Since WordPress 6.9_) (optional)

This example will show a custom post meta date in the editor and, if it doesn't exist, it will show today's date. The user can edit the value of the date. (Caution: This example does not format the user input as a date—it's only for educational purposes.)

```js
import { registerBlockBindingsSource } from '@wordpress/blocks';
import { __ } from '@wordpress/i18n';
import { store as coreDataStore } from '@wordpress/core-data';

registerBlockBindingsSource( {
	name: 'wpmovies/visualization-date',
	label: __( 'Visualization Date', 'custom-bindings' ), // We can skip the label, as it was already defined in the server in the previous example.
	usesContext: [ 'postType' ], // We can skip postId, as it was already defined in the server in the previous example.
	getValues( { select, context } ) {
		let wpMoviesVisualizationDate;
		const { getEditedEntityRecord } = select( coreDataStore );
		if ( context?.postType && context?.postId ) {
			wpMoviesVisualizationDate = getEditedEntityRecord(
				'postType',
				context?.postType,
				context?.postId
			).meta?.wp_movies_visualization_date;
		}
		if ( wpMoviesVisualizationDate ) {
			return {
				content: wpMoviesVisualizationDate,
			};
		}

		return {
			content: new Date().toLocaleDateString( 'en-US' ),
		};
	},
	setValues( { select, dispatch, context, bindings } ) {
		dispatch( coreDataStore ).editEntityRecord(
			'postType',
			context?.postType,
			context?.postId,
			{
				meta: {
					wp_movies_visualization_date: bindings?.content?.newValue,
				},
			}
		);
	},
	canUserEditValue( { select, context } ) {
		return true;
	},
} );
```

#### getValues

The `getValues` function retrieves the value from the source on block loading. It receives an `object` as an argument with the following properties:

-   `bindings` returns the bindings object of the specific source. It must have the attributes as a key, and the value can be a `string` or an `object` with arguments.
-   `clientId` returns a `string` with the current block client ID.
-   `context` returns an `object` of the current block context, defined in the `usesContext` property. [More about block context.](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-context/).
-   `select` returns an `object` of a given store's selectors. [More info in their docs.](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-data/#select).

The function must return an `object` with this structure:
`{ 'block attribute' : value }`

#### setValues

`setValues` 函数用于更新绑定区块源的所有值。它接收一个包含以下属性的 `object` 作为参数：

-   `bindings` 返回特定源的绑定对象。它必须以属性作为键，值可以是 `string` 或包含参数的 `object`。此对象包含一个带有用户输入的 `newValue` 属性。
-   `clientId` 返回一个包含当前区块客户端 ID 的 `string`。
-   `context` 返回当前区块上下文的 `object`，在 `usesContext` 属性中定义。[更多关于区块上下文的信息。](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-context/)
-   `dispatch` 返回存储操作创建者的 `object`。[更多关于 dispatch 的信息。](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-data/#dispatch)
-   `select` 返回给定存储选择器的 `object`。[更多信息请参阅其文档。](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-data/#select)

#### getFieldsList

_**Note:** Since WordPress 6.9._

The `getFieldsList` function enables custom sources to appear in the Block Bindings UI dropdown selector. When a user selects an option from the dropdown, the source is automatically bound to the block attribute with the corresponding `args` from the selected field. This function must return an array of field objects that define the available binding options.

Each field object in the array should have the following properties:

-   `label`: `string` that defines the label shown in the dropdown selector. Defaults to the source label if not provided.
-   `type`: `string` that defines the attribute value type. It must match the attribute type it binds to; otherwise, it won't appear in the UI. For example, an `id` attribute that accepts only numbers should only display fields that return numeric values.
-   `args`: `object` that defines the source arguments that are applied when a user selects the field from the dropdown.

Example:

```js
registerBlockBindingsSource( {
	name: 'my-plugin/custom-fields',
	label: 'Custom Fields',
	getFieldsList() {
		return [
			{
				label: 'Author Name',
				type: 'string',
				args: {
					field: 'author_name',
				},
			},
			{
				label: 'Publication Year',
				type: 'string',
				args: {
					field: 'publication_year',
				},
			},
			{
				label: 'Page Count',
				type: 'number',
				args: {
					field: 'page_count',
				},
			},
		];
	},
	getValues( { bindings } ) {
		// Implementation to retrieve values based on args.field
	},
} );
```

With this implementation, users will see "Author Name", "Publication Year", and "Page Count" as options in the Block Bindings UI dropdown when binding block attributes to your custom source.

<div class="callout callout-info">
Check the <a href="https://github.com/WordPress/block-development-examples/tree/trunk/plugins/editor-bindings">Editor Bindings</a> example from the <a href="https://github.com/WordPress/block-development-examples/">Block Development Examples</a> repo
</div>

#### 编辑器注册核心示例

核心中有几个示例可供参考。

-   文章元数据。[源代码](https://github.com/WordPress/gutenberg/blob/5afd6c27bfba2be2e06b502257753fbfff1ae9f0/packages/editor/src/bindings/post-meta.js#L74-L146)
-   模式覆盖。[源代码](https://github.com/WordPress/gutenberg/blob/5afd6c27bfba2be2e06b502257753fbfff1ae9f0/packages/editor/src/bindings/pattern-overrides.js#L8-L100)

## 注销数据源

_**注意：** 自 WordPress 6.7 起。_

`unregisterBlockBindingsSource` 通过提供名称来注销一个区块绑定数据源。

```js
import { unregisterBlockBindingsSource } from '@wordpress/blocks';

unregisterBlockBindingsSource( 'plugin/my-custom-source' );
```

## 获取所有数据源

_**注意：** 自 WordPress 6.7 起。_

`getBlockBindingsSources` 返回所有已注册的区块绑定数据源。

```js
import { getBlockBindingsSources } from '@wordpress/blocks';

const registeredSources = getBlockBindingsSources();
```

## 获取特定绑定源

_**注意：** 自 WordPress 6.7 起。_

`getBlockBindingsSource` 通过名称返回特定的区块绑定源。

```js
import { getBlockBindingsSource } from '@wordpress/blocks';

const blockBindingsSource = getBlockBindingsSource( 'plugin/my-custom-source' );
```

## 区块绑定工具

_**注意：** 自 WordPress 6.7 起。_

UseBlockBindingUtils 是一个包含两个辅助函数的钩子，允许开发者轻松编辑 `metadata.bindings` 属性。

它接受一个 `clientId` 字符串作为参数，如果未设置，函数将使用上下文中的当前区块客户端 ID。

示例：

```js
import { useBlockBindingsUtils } from '@wordpress/block-editor';

const { updateBlockBindings } = useBlockBindingsUtils('my-block-client-id-12345');
...
```

### updateBlockBindings

`updateBlockBindings` 的工作方式与 `updateBlockAttributes` 类似，可用于创建、更新或移除特定的连接。

```js
import { useBlockBindingsUtils } from '@wordpress/block-editor';

const { updateBlockBindings } = useBlockBindingsUtils();

function updateBlockBindingsURLSource( url ) {
	updateBlockBindings( {
		url: {
			source: 'myplugin/new-source',
		},
	} );
}

// 从 url 属性中移除绑定。
function removeBlockBindingsURLSource() {
	updateBlockBindings( { url: undefined } );
}
```

### removeAllBlockBindings

`removeAllBlockBindings` 将通过移除 `metadata.bindings` 属性来删除区块中的所有现有连接。

```js
import { useBlockBindingsUtils } from '@wordpress/block-editor';

const { removeAllBlockBindings } = useBlockBindingsUtils();

function clearBlockBindings() {
	removeAllBlockBindings();
}
```