#### setValues 函数

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

- `bindings` 返回特定源的绑定对象。该对象必须以属性作为键，值可以是 `string` 或包含参数的 `object`。此对象包含一个 `newValue` 属性，用于存储用户的输入。
- `clientId` 返回一个 `string`，表示当前区块的客户端 ID。
- `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)。

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

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

- 文章元数据。[源代码](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();
}
```

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

核心代码库中有几个可用作参考的示例：

- 文章元数据。[源代码](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/pattern-overrides.php)
- 二十五主题。[源代码](https://github.com/WordPress/wordpress-develop/blob/trunk/src/wp-content/themes/twentytwentyfive/functions.php)

### 编辑器注册

_**注意：** 自WordPress 6.7起支持_

客户端编辑器注册允许定义绑定区块在获取值或编辑值时的行为。

注册自定义源的函数是 `registerBlockBindingsSource( args )`：

- `args`：包含以下结构的`对象`：
    - `name`：具有唯一性且机器可读名称的`字符串`
    - `label`：自定义源的人类可读名称`字符串`。若已在服务器端定义，服务器标签将被此标签覆盖，此时不建议在此重复定义（可选）
    - `usesContext`：自定义源可能需要的区块上下文`数组`。若已在服务器端定义，则不应在此重复定义（可选）
    - `getValues`：从源获取值的`函数`（可选）
    - `setValues`：允许更新与源连接值的`函数`（可选）
    - `canUserEditValue`：判断用户是否可以编辑值的`函数`。默认情况下用户无法编辑（可选）

此示例将在编辑器中显示自定义文章元数据日期，若不存在则显示当前日期。用户可以编辑日期值。（注意：此示例未将用户输入格式化为日期——仅用于教学目的）

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

registerBlockBindingsSource( {
	name: 'wpmovies/visualization-date',
	label: __( '观影日期', 'custom-bindings' ), // 可跳过标签定义，因已在前面示例的服务器端定义
	usesContext: [ 'postType' ], // 可跳过postId定义，因已在前面示例的服务器端定义
	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( 'zh-CN' ),
		};
	},
	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函数

`getValues`函数在区块加载时从源获取值。它接收包含以下属性的`对象`作为参数：

- `bindings` 返回特定源的绑定对象。必须以属性为键，值可以是`字符串`或带参数的`对象`
- `clientId` 返回当前区块客户端ID的`字符串`
- `context` 返回在`usesContext`属性中定义的当前区块上下文`对象`。[关于区块上下文的更多信息](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-context/)
- `select` 返回给定存储库选择器的`对象`。[详细文档](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-data/#select)

该函数必须返回具有以下结构的`对象`：
`{ '区块属性': 值 }`

# 数据绑定

<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"
			}
		}
	}
} -->
```

## 兼容区块及其属性

目前并非所有区块属性都支持数据绑定。虽然正在努力提升兼容性，但当前支持的列表如下：

| 支持区块           | 支持属性                    |
| ----------------    | --------------------       |
| 段落               | content                    |
| 标题               | content                    |
| 图片               | id, url, title, alt        |
| 按钮               | text, url, linkTarget, rel |

## 注册自定义数据源

注册数据源需要至少定义 `name`（名称）、`label`（标签）和 `callback`（回调函数），该函数从数据源获取值并传递给区块属性。

数据源注册后，任何支持的区块都可以通过配置 `metadata.bindings` 属性来读取该数据源的值。

注册可以通过 PHP 在服务器端完成，也可以通过 JavaScript 在编辑器端完成，两者可以共存。

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

### 服务器端注册

服务器端注册允许应用一个回调函数，该函数将在前端为绑定属性执行。

注册自定义数据源的函数是 `register_block_bindings_source($name, $args)`：

- `name`：`string`，设置自定义数据源的唯一 ID。
- `args`：`array`，包含：
    - `label`：`string`，自定义数据源的可读名称。
    - `uses_context`：`array`，传递给回调函数的区块上下文（可选）。
    - `get_value_callback`：`function`，在绑定区块的渲染函数中运行。它接受三个参数：`source_args`、`block_instance` 和 `attribute_name`。此值可以通过 `block_bindings_source_value` 过滤器进行修改。

注意，`register_block_bindings_source()` 应通过附加到 `init` 钩子的处理程序调用。

以下是一个示例：

```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' ),
			)
		);
	}
);
```

此示例需要注册一个 `post_meta`，并且可以使用过滤器返回默认的 `$visualization_date` 值，该值将在下一个标题中显示。

```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>注意：</strong>以下划线开头的文章元键（例如 `_example_key`）是受保护的，不能用于区块绑定。此外，文章元必须通过 `show_in_rest = true` 注册才能在区块绑定 API 中使用。
</div>

#### 区块绑定数据源值过滤器

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

`get_value_callback` 返回的值可以通过 `block_bindings_source_value` 过滤器进行修改。
该过滤器具有以下参数：

- `value`：要过滤的值。
- `name`：数据源的名称。
- `source_args`：包含数据源参数的 `array`。
- `block_instance`：区块实例对象。
- `attribute_name`：属性名称。

示例：

```php
function wpmovies_format_visualization_date( $value, $name ) {
	// 防止此过滤器应用于其他数据源。
	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 );
```