Block Bindings API
Block Bindings API позволяет привязать данные из внешнего источника к атрибутам блока.
Например, можно связать атрибут url блока Image с функцией, которая возвращает URL картинки:
<!-- wp:image {
"metadata":{
"bindings":{
"url":{
"source":"my-plugin/get-random-image"
}
}
}
} -->
После этого значение атрибута берётся не из сохранённой разметки блока, а из указанного источника.
Block Bindings API доступен с WordPress 6.5.
Часть возможностей появилась позже:
- WP 6.7 - UI в редакторе, JS-регистрация источников,
useBlockBindingsUtils(). - WP 6.9 -
core/post-data,core/term-data,getFieldsList(), фильтры supported attributes. - WP 7.0 - Pattern Overrides работают для любых атрибутов, которые поддерживают Block Bindings, включая кастомные блоки.
Коротко
Block Bindings API нужен для связи атрибутов блока с динамическими данными.
Основной синтаксис хранится в metadata.bindings:
{
"metadata": {
"bindings": {
"content": {
"source": "core/post-meta",
"args": {
"key": "my_custom_field"
}
}
}
}
}
Главное после WP 7.0:
- supported attributes стали общей точкой расширения для Block Bindings и Pattern Overrides;
- Pattern Overrides можно использовать с кастомными блоками;
- для динамических блоков WordPress передаёт вычисленные binding-значения прямо в
render_callback(); - для кастомных источников можно сделать полноценный UI через
registerBlockBindingsSource()иgetFieldsList().
Совместимые блоки и атрибуты
По умолчанию bindings работают не со всеми атрибутами блоков. Сейчас в ядре поддерживаются такие блоки и атрибуты:
| Блок | Атрибуты |
|---|---|
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 |
С WP 6.9 этот список можно расширять фильтрами:
С WP 7.0 это особенно важно: если атрибут добавлен в supported attributes, он может использоваться не только для Block Bindings, но и для Pattern Overrides.
Пример добавления поддержки атрибута linkDestination для блока Image:
add_filter(
'block_bindings_supported_attributes_core/image',
static function ( $supported_attributes ) {
$supported_attributes[] = 'linkDestination';
return $supported_attributes;
}
);
Пример для кастомного блока:
add_filter(
'block_bindings_supported_attributes_my-plugin/card',
static function ( $supported_attributes ) {
$supported_attributes[] = 'title';
$supported_attributes[] = 'description';
return $supported_attributes;
}
);
Источники ядра
В WordPress есть несколько встроенных источников:
core/post-metacore/post-datacore/term-datacore/pattern-overrides
core/post-meta
Источник core/post-meta привязывает атрибуты блока к метаполям записи.
Требования:
- метаполе должно быть зарегистрировано с
show_in_rest => true; - ключ метаполя не должен начинаться с
_; - тип метаполя должен подходить к типу атрибута блока.
Пример регистрации метаполя:
register_meta( 'post', 'my_custom_field', array( 'show_in_rest' => true, 'single' => true, 'type' => 'string', 'label' => 'Custom field', ) );
Пример привязки к Paragraph:
<!-- wp:paragraph {
"metadata":{
"bindings":{
"content":{
"source":"core/post-meta",
"args":{
"key":"my_custom_field"
}
}
}
}
} -->
<p>Fallback content</p>
<!-- /wp:paragraph -->
Fallback content нужен как запасное значение. Если binding не вернёт данные, блок сможет показать сохранённый контент.
core/post-data
С WP 6.9 источник core/post-data даёт доступ к данным текущей записи.
Доступные поля:
| Поле | Что возвращает |
|---|---|
date |
дату публикации |
modified |
дату последнего изменения |
link |
permalink записи |
Пример:
<!-- wp:paragraph {
"metadata":{
"bindings":{
"content":{
"source":"core/post-data",
"args":{
"field":"date"
}
}
}
}
} -->
<p>Fallback content</p>
<!-- /wp:paragraph -->
core/term-data
С WP 6.9 источник core/term-data даёт доступ к данным термина таксономии.
Он работает только там, где есть term context. Например, внутри core/term-template или внутри кастомного блока, который передаёт termId и taxonomy.
Доступные поля:
| Поле | Что возвращает |
|---|---|
id |
ID термина |
name |
название термина |
link |
URL архива термина |
slug |
slug |
description |
описание |
parent |
ID родительского термина |
count |
количество записей в термине |
Пример вывода названий терминов:
<!-- 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>Category Name</p>
<!-- /wp:paragraph -->
<!-- /wp:term-template -->
</div>
<!-- /wp:terms-query -->
Для блоков навигации есть отдельная обработка совместимости: core/navigation-link и core/navigation-submenu могут брать данные не из context, а из атрибутов самого блока.
core/pattern-overrides
Источник core/pattern-overrides используется для переопределения контента внутри Synced Pattern.
Идея такая: структура и дизайн паттерна остаются синхронизированными, но отдельные атрибуты вложенных блоков можно менять в каждом экземпляре паттерна. Подробнее тут.
С WP 7.0 Pattern Overrides больше не ограничены небольшим списком core-блоков. Любой атрибут, который поддерживает Block Bindings, может быть доступен для overrides. Это работает и для кастомных блоков.
Как это работает
- Внутри паттерна у блока должен быть
metadata.name. - В
metadata.bindingsуказывается источникcore/pattern-overrides. - Экземпляр паттерна хранит переопределённые значения в атрибуте
content. - Ключом служит
metadata.nameблока. - Структура данных такая:
pattern/overrides -> {block_name} -> {attribute_name}.
Пример для одного атрибута:
<!-- wp:paragraph {
"metadata":{
"name":"custom-heading",
"bindings":{
"content":{
"source":"core/pattern-overrides"
}
}
}
} -->
<p>Default text</p>
<!-- /wp:paragraph -->
Пример экземпляра паттерна с переопределённым контентом:
<!-- wp:block {
"ref":123,
"content":{
"custom-heading":{
"content":"My custom heading text"
}
}
} /-->
Если нужно разрешить переопределять все поддерживаемые атрибуты блока, можно использовать __default:
<!-- wp:button {
"metadata":{
"name":"custom-button",
"bindings":{
"__default":{
"source":"core/pattern-overrides"
}
}
}
} -->
<div class="wp-block-button">
<a class="wp-block-button__link wp-element-button" href="#">Default button</a>
</div>
<!-- /wp:button -->
__default означает: подключить к core/pattern-overrides все атрибуты блока, которые поддерживают Block Bindings.
Pattern Overrides для кастомного блока
Сначала нужно добавить нужные атрибуты в supported attributes:
add_filter(
'block_bindings_supported_attributes_my-plugin/card',
static function ( $supported_attributes ) {
$supported_attributes[] = 'title';
$supported_attributes[] = 'description';
return $supported_attributes;
}
);
Затем в разметке паттерна можно подключить overrides:
<!-- wp:my-plugin/card {
"title":"Default title",
"description":"Default description",
"metadata":{
"name":"custom-card",
"bindings":{
"__default":{
"source":"core/pattern-overrides"
}
}
}
} /-->
Для динамических блоков с WP 7.0 обычно не нужно вручную читать $block->context['pattern/overrides']. WordPress сам вычислит связанные значения и передаст их в render_callback() через $attributes.
function my_plugin_render_card( $attributes ) {
$title = $attributes['title'] ?? '';
$description = $attributes['description'] ?? '';
return sprintf(
'<div class="my-card"><h3>%s</h3><p>%s</p></div>',
esc_html( $title ),
esc_html( $description )
);
}
Для статических блоков WordPress пытается заменить значения в HTML через HTML API. Если атрибут сложно найти в сохранённой разметке, может понадобиться render_callback() или фильтр render_block.
Кастомный источник
Кастомный источник нужен, когда данные берутся не из стандартных источников ядра.
Например:
- из внешнего API;
- из настроек плагина;
- из данных пользователя;
- из сложной логики темы;
- из кастомной таблицы.
Источник можно зарегистрировать на сервере через PHP и в редакторе через JavaScript. Эти регистрации могут работать вместе.
Серверная регистрация отвечает за рендер на фронтенде. Регистрация в редакторе отвечает за отображение и редактирование значения в UI.
Серверная регистрация
Функция:
register_block_bindings_source( $name, $args );
Основные аргументы:
| Аргумент | Описание |
|---|---|
label |
название источника |
uses_context |
список context-значений, которые нужны callback-функции |
get_value_callback |
функция, которая возвращает значение для атрибута |
Вызывать регистрацию нужно на хуке init.
Пример:
add_action(
'init',
static function () {
register_block_bindings_source(
'wpmovies/visualization-date',
array(
'label' => 'Visualization Date',
'uses_context' => [ 'postId' ],
'get_value_callback' => wpmovies_get_visualization_date( ... ),
)
);
}
);
function wpmovies_get_visualization_date( $source_args, $block, $attribute_name ) {
if ( empty( $source_args['key'] ) || empty( $block->context['postId'] ) ) {
return null;
}
return get_post_meta( $block->context['postId'], $source_args['key'], true );
}
Пример использования источника в блоке:
<!-- wp:paragraph {
"metadata":{
"bindings":{
"content":{
"source":"wpmovies/visualization-date",
"args":{
"key":"wp_movies_visualization_date"
}
}
}
}
} -->
<p>Fallback date</p>
<!-- /wp:paragraph -->
Фильтр block_bindings_source_value
С WP 6.7 значение, которое вернул источник, можно изменить через фильтр block_bindings_source_value.
Фильтр получает:
$value- значение источника;$name- имя источника;$source_args- аргументы источника;$block_instance- экземпляр блока;$attribute_name- имя атрибута.
Пример:
add_filter( 'block_bindings_source_value', 'wpmovies_format_visual_date', 10, 5 );
function wpmovies_format_visual_date( $value, $name, $source_args, $block_instance, $attribute_name ) {
if ( 'wpmovies/visualization-date' !== $name ) {
return $value;
}
if ( empty( $value ) ) {
return '';
}
return wp_date( 'd.m.Y', strtotime( $value ) );
}
Регистрация источника в редакторе
С WP 6.7 источник можно зарегистрировать в редакторе через JavaScript:
import { registerBlockBindingsSource } from '@wordpress/blocks';
Функция:
registerBlockBindingsSource( args );
Основные параметры:
| Параметр | Описание |
|---|---|
name |
имя источника |
label |
название для UI |
usesContext |
нужный block context |
getValues |
получить значения для редактора |
setValues |
сохранить значения |
canUserEditValue |
разрешить или запретить редактирование |
getFieldsList |
список полей для выпадающего списка UI |
Пример:
import { registerBlockBindingsSource } from '@wordpress/blocks';
import { store as coreDataStore } from '@wordpress/core-data';
registerBlockBindingsSource( {
name: 'wpmovies/visualization-date',
label: 'Visualization Date',
usesContext: [ 'postId', 'postType' ],
getValues( { select, context } ) {
const { getEditedEntityRecord } = select( coreDataStore );
const record = getEditedEntityRecord(
'postType',
context.postType,
context.postId
);
return {
content: record?.meta?.wp_movies_visualization_date || '',
};
},
setValues( { dispatch, context, bindings } ) {
dispatch( coreDataStore ).editEntityRecord(
'postType',
context.postType,
context.postId,
{
meta: {
wp_movies_visualization_date: bindings?.content?.newValue,
},
}
);
},
canUserEditValue() {
return true;
},
} );
getValues()
getValues() вызывается, когда редактору нужно получить значение связанного атрибута.
Функция получает объект с данными:
bindings- bindings для текущего источника;clientId- client ID блока;context- block context;select- селекторы data store.
Функция должна вернуть объект вида:
{
content: 'Value'
}
Ключ объекта должен совпадать с именем атрибута блока.
setValues()
setValues() вызывается, когда пользователь меняет значение связанного атрибута в редакторе.
Функция получает:
bindings- bindings, включаяnewValue;clientId- client ID блока;context- block context;dispatch- actions data store;select- selectors data store.
getFieldsList()
С WP 6.9 getFieldsList() позволяет показать поля кастомного источника в UI Block Bindings.
Когда пользователь выбирает поле из списка, редактор сам добавляет binding к нужному атрибуту блока.
Функция должна вернуть массив объектов:
| Поле | Описание |
|---|---|
label |
название поля в UI |
type |
тип значения |
args |
аргументы, которые будут записаны в binding |
Пример:
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 } ) {
const values = {};
Object.entries( bindings ).forEach( ( [ attributeName, binding ] ) => {
values[ attributeName ] = getValueByField( binding.args.field );
} );
return values;
},
} );
type должен подходить к типу атрибута. Например, поле с type: 'number' не будет показываться для строкового атрибута.
Удаление и получение источников
С WP 6.7 в редакторе доступны функции для работы с зарегистрированными источниками.
unregisterBlockBindingsSource()
Удаляет источник по имени:
import { unregisterBlockBindingsSource } from '@wordpress/blocks';
unregisterBlockBindingsSource( 'plugin/my-custom-source' );
getBlockBindingsSources()
Возвращает все зарегистрированные источники:
import { getBlockBindingsSources } from '@wordpress/blocks';
const sources = getBlockBindingsSources();
getBlockBindingsSource()
Возвращает один источник по имени:
import { getBlockBindingsSource } from '@wordpress/blocks';
const source = getBlockBindingsSource( 'plugin/my-custom-source' );
Block Bindings Utils - useBlockBindingsUtils()
С WP 6.7 есть хук useBlockBindingsUtils(). Он помогает менять metadata.bindings у блока из JS.
import { useBlockBindingsUtils } from '@wordpress/block-editor';
const { updateBlockBindings, removeAllBlockBindings } = useBlockBindingsUtils();
updateBlockBindings()
Создаёт, обновляет или удаляет привязки у текущего блока.
import { useBlockBindingsUtils } from '@wordpress/block-editor';
const { updateBlockBindings } = useBlockBindingsUtils();
function connectUrl() {
updateBlockBindings( {
url: {
source: 'my-plugin/url-source',
},
} );
}
function disconnectUrl() {
updateBlockBindings( {
url: undefined,
} );
}
removeAllBlockBindings()
Удаляет все bindings у блока:
import { useBlockBindingsUtils } from '@wordpress/block-editor';
const { removeAllBlockBindings } = useBlockBindingsUtils();
function clearBindings() {
removeAllBlockBindings();
}
useBlockEditingMode()
Хук. Позволяет узнать или изменить режим редактирования блока. Находится в @wordpress/block-editor.
Управляет тем, какой UI будет доступен для блока и его внутренних блоков. Режим наследуется вложенными блоками, если у них не задан свой режим. Если вызвать хук вне контекста блока, режим применяется ко всем блокам.
Доступные режимы:
default- обычное редактирование блока.contentOnly- скрывает неконтентные элементы интерфейса: настройки блока, mover-кнопки, часть toolbar-контролов и т.д.disabled- полностью запрещает редактирование блока, его нельзя выбрать.
Если вызвать хук без параметра:
const mode = useBlockEditingMode();
он просто вернет текущий режим редактирования.
Если передать режим:
useBlockEditingMode( 'contentOnly' );
он установит этот режим для текущего блока и его вложенных блоков.
Пример проверки contentOnly
Иногда нужно понять, что блок сейчас находится в contentOnly режиме, и показать другой UI. Например, когда боковая панель с настройками скрыта, можно вынести управление изображениями в BlockControls.
const { BlockControls, InspectorControls, useBlockEditingMode } = wp.blockEditor;
const { Dropdown, ToolbarButton } = wp.components;
const isContentOnlyMode = ( useBlockEditingMode() || 'default' ) === 'contentOnly';
if ( isContentOnlyMode ) {
return (
<BlockControls group="other">
<Dropdown
popoverProps={ { placement: 'bottom-start' } }
renderToggle={ ( { isOpen, onToggle } ) => (
<ToolbarButton
label="Images"
icon="format-image"
onClick={ onToggle }
isPressed={ isOpen }
/>
) }
renderContent={ () => (
<div style={ { padding: '1rem', width: '320px' } }>
<FocalImagesControl
params={ {
setAttributes,
desktopImage,
tabletImage,
mobileImage,
} }
/>
</div>
) }
/>
</BlockControls>
);
}
Такой прием полезен для кастомных блоков внутри паттернов или template parts, где WordPress ограничивает редактирование только контентом, но разработчику всё равно нужно оставить доступ к отдельным контентным настройкам.