Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Block Bindings: Docs API reference. #66251

Merged
merged 26 commits into from
Oct 30, 2024
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/reference-guides/block-api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ The following sections will walk you through the existing block APIs:
- [Annotations](/docs/reference-guides/block-api/block-annotations.md)
- [API Versions](/docs/reference-guides/block-api/block-api-versions.md)
- [Attributes](/docs/reference-guides/block-api/block-attributes.md)
- [Bindings](/docs/reference-guides/block-api/block-bindings.md)
- [Context](/docs/reference-guides/block-api/block-context.md)
- [Deprecation](/docs/reference-guides/block-api/block-deprecation.md)
- [Edit and Save](/docs/reference-guides/block-api/block-edit-save.md)
Expand Down
285 changes: 285 additions & 0 deletions docs/reference-guides/block-api/block-bindings.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,285 @@
# Bindings

The Block Bindings API lets you “bind” dynamic data to the block’s attributes, which are then reflected in the final HTML markup that is output to the browser on the front end.

An example could be connecting an Image block `url` attribute to a function that returns random images from an external 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. This is some ongoing effort to increase this compatibility, but for now, this is the list:
artemiomorales marked this conversation as resolved.
Show resolved Hide resolved

| Supported Blocks | Supported Attributes |
| -------- | ------- |
| Paragraph | content |
| Heading | content |
| Image | ID, url, title, alt |
gziolo marked this conversation as resolved.
Show resolved Hide resolved
| Button | text, url, linkTarget, rel |

## Registering a custom source

Registering a source requires defining at least `name` and a `callback` function that gets a value from the source and passes it back to a block attribute.
cbravobernal marked this conversation as resolved.
Show resolved Hide resolved

Once a source is registered, any supporting block's `metadata.bindings` attribute can be configured to read a value from that source.

Registration can be done on the server via PHP or in the editor via JavaScript, and both can coexist.

The label defined in server registration will be overridden by the label defined in the editor.

### Server registration

Server registration allows applying a callback that will be executed on the frontend for the defined 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 render function. It accepts three arguments: `source_args`, `block_instance` and `attribute_name`. This value can be overriden 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'];
$visualization_date = get_post_meta( $post_id, 'wp_movies_visualization_date', true );
if ( ! $visualization_date ) {
$visualization_date = date("m/d/Y");
gziolo marked this conversation as resolved.
Show resolved Hide resolved
}
return $visualization_date;
},
'uses_context' => array( 'postId' ),
)
);
}
);
```

This example needs a `post_meta` registered:

```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' ),
gziolo marked this conversation as resolved.
Show resolved Hide resolved
)
);
}
);
```

#### Block bindings source value filter

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.

gziolo marked this conversation as resolved.
Show resolved Hide resolved
#### Server registration Core examples

There are a few examples in Core that can be used as a reference.

- Post Meta. [Source code](https://github.com/WordPress/wordpress-develop/blob/68d2421d758498095449006a055ad8ce5b7a8a40/src/wp-includes/block-bindings/post-meta.php#L59)
- Pattern overrides. [Source code](https://github.com/WordPress/wordpress-develop/blob/68d2421d758498095449006a055ad8ce5b7a8a40/src/wp-includes/block-bindings/pattern-overrides.php#L36)
- Twenty Twentyfive theme. [Source code](https://github.com/WordPress/wordpress-develop/blob/68d2421d758498095449006a055ad8ce5b7a8a40/src/wp-content/themes/twentytwentyfive/functions.php#L130)
gziolo marked this conversation as resolved.
Show resolved Hide resolved


### Editor registration

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` is an `object` with the following structure:
- `name` is a `string` with the unique and machine-readable name.
- `label` is a `string` with the human readable name of the custom source. (optional)
- `usesContext` is an `array` with the block context that the custom source may need. (optional)
- `getValues` is a `function` that retrieves the values from the source. (optional)
- `setValues` is a `function` that allows updating the values connected to the source. (optional)
- `canUserEditValue` is a `function` to determine if the user can edit the value. The user won't be able to edit by default. (optional)
- `getFieldsList` is an experimental `function` that should not be used yet by third-party developers in production, as it is subject to change and may be removed in upcoming releases. It creates a list for the block bindings UI with post meta.

The `label` argument will override the one defined on the server if they are different.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we move this sentence to the label property explanation?



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 is not formatting the user input as a date, it's only for educational purposes.)

```js
import {
registerBlockBindingsSource,
} from '@wordpress/blocks';
import { __ } from '@wordpress/i18n';
artemiomorales marked this conversation as resolved.
Show resolved Hide resolved

registerBlockBindingsSource( {
name: 'wpmovies/visualization-date',
label: __( 'Visualization Date' ),
usesContext: [ 'postId', 'postType' ],
setValues( { select, dispatch, context, bindings } ) {
dispatch( coreDataStore ).editEntityRecord(
'postType',
context?.postType,
context?.postId,
{
meta: {
wp_movies_visualization_date: bindings?.content?.newValue,
},
}
);
},
getValues( { select, context } ) {
cbravobernal marked this conversation as resolved.
Show resolved Hide resolved
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' ),
};
},
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` return the bindings object. 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

The `setValues` function updates all the values of the source of the block bound. It receives an `object` as an argument with the following properties:

- `bindings` returns the bindings object. It must have the attributes as a key, and the value can be a string or an object with arguments. This object contains a `newValue` property with the user's input.
- `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/).
- `dispatch` returns an `object` of the store's action creators. [More about dispatch](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-data/#dispatch).
- `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).


#### Editor registration Core examples

There are a few examples in Core that can be used as a reference.

- Post Meta. [Source code](https://github.com/WordPress/gutenberg/blob/5afd6c27bfba2be2e06b502257753fbfff1ae9f0/packages/editor/src/bindings/post-meta.js#L74-L146)
- Pattern overrides. [Source code](https://github.com/WordPress/gutenberg/blob/5afd6c27bfba2be2e06b502257753fbfff1ae9f0/packages/editor/src/bindings/pattern-overrides.js#L8-L100)

## Unregistering a source

`unregisterBlockBindingsSource` unregisters a block bindings source by providing its name.

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

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

## Getting all sources

`getBlockBindingsSources` returns all registered block bindings sources.

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

const registeredSources = getBlockBindingsSources();
```

## Getting one specific source

`getBlockBindingsSource` return a specific block bindings source by its name.

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

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

## Block Bindings Utils

WordPress 6.7 includes a hook with two helpers that allows developers to edit the `metadata.bindings` attribute easily.
cbravobernal marked this conversation as resolved.
Show resolved Hide resolved

### updateBlockBindings

`updateBlockBindings` works similarly to `updateBlockAttributes`, and can be used to create, update, or remove specific connections.

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

const { updateBlockBindings } = useBlockBindingsUtils();

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

gziolo marked this conversation as resolved.
Show resolved Hide resolved
### removeAllBlockBindings

`removeAllBlockBindings`, as its name suggests, will remove all existing connections in a block by removing the `metadata.bindings` attribute.

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

const { removeAllBlockBindings } = useBlockBindingsUtils();

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



Loading