Block Bindings: Improvements to the Editor Experience in 6.7

WordPress 6.7 introduces various improvements to the BlockBlock Block is the abstract term used to describe units of markup that, composed together, form the content or layout of a webpage using the WordPress editor. The idea combines concepts of what in the past may have achieved with shortcodes, custom HTML, and embed discovery into a single consistent API and user experience. Bindings APIAPI An API or Application Programming Interface is a software intermediary that allows programs to interact with each other and share data in limited, clearly defined ways. and the built-in post metaMeta Meta is a term that refers to the inside workings of a group. For us, this is the team that works on internal WordPress sites like WordCamp Central and Make WordPress. source, including a default UIUI User interface and the beginnings of a public editor API.

For an introduction to Block Bindings, first introduced in WordPress 6.5, see the prior dev note.

New Block Bindings UI

Compatible blocks — which currently include Heading, Paragraph, Image, and Button — have received a new default UI for viewing bindings.

Called Attributes, you can find the new tool panel in block settings whenever a compatible block is selected in either the post or site editor.

The panel shows active bindings on the current block. If there are any post meta available, the panel is also interactive, allowing you to bind attributes to those custom fields via the built-in post meta block bindings source.

Currently, there are two limitations to the panel:

  1. It will not allow users to bind attributes to custom sources just yet. 

    Bindings to custom sources, which can be added via the code editor or other programmatic means, will still display in the panel — they just can’t be connected via the UI for the moment in WordPress 6.7.

    A flexible API for connecting custom sources to the Attributes panel is currently under development and is planned for public release in the future.

    For now, the rollout of that API has started with the built-in post meta source to allow time for gathering feedback.
  2. For each attribute, the panel will only show custom fields that match its data type. For example, an attribute of type string or rich-text can only be connected to a custom fieldCustom Field Custom Field, also referred to as post meta, is a feature in WordPress. It allows users to add additional information when writing a post, eg contributors’ names, auth. WordPress stores this information as metadata. Users can display this meta data by using template tags in their WordPress themes. of type string, and an attribute of number can only be connected to another number.

New Post Meta Label Attribute

To improve how custom fields appear in the editor UI, a new label attribute has been created for post meta, which can be defined during registration:

If specified, the label will render in place of the meta key in the Attributes panel — in this example, the label would replace movie_director. The label will also render under certain circumstances in other parts of the editor, including as a placeholder for Rich Text if a block is bound to the post meta source and a default value is undefined.

Usage In Custom Post Templates

One of the primary use cases for Block Bindings is to assist in creating templates for custom post types. Given a custom post typeCustom Post Type WordPress can hold and display many different types of content. A single item of such a content is generally called a post, although post is also a specific post type. Custom Post Types gives your site the ability to have templated posts, to simplify the concept. called movie, for example, one can define how custom fields for that post type will render, such as via connected images, headings, paragraphs, and buttons.

Here is an example of how one could use connected blocks to create a layout:

One can override the content in connected blocks for each instance of the custom post type, a much simpler and more flexible way of creating layouts than in the past — all without needing to create custom blocks.

Default Permissions

Accompanying this UI is a new canUpdateBlockBindings editor setting, used to determine whether the UI is interactive for users or not.

By default, this editor setting is set to a new edit_block_binding capability, which maps to a user’s ability to either:

  1. Edit the post type (in the post editor), or
  2. Edit the theme options (in the site editor)

This means that the setting is by default set to true for administrators, and false for other users.

This default setting can be overridden using the block_editor_settings_all filterFilter Filters are one of the two types of Hooks https://codex.wordpress.org/Plugin_API/Hooks. They provide a way for functions to modify data of other functions. They are the counterpart to Actions. Unlike Actions, filters are meant to work in an isolated manner, and should never have side effects such as affecting global variables and output. and modifying $editor_settings['canUpdateBlockBindings'] as follows:

function my_plugin_override_can_update_block_bindings( $settings ) {
    $settings['canUpdateBlockBindings'] = true;
    return $settings;
}
add_action( 'block_editor_settings_all', 'my_plugin_override_can_update_block_bindings' );

New Public Editor APIs

Several functions have been exposed to enable the use of block bindings in the editor.

Registration API

Source Bootstrapping 

As part of the new editor API, Block Bindings will automatically register custom sources defined on the server with bootstrapped values in the editor. This will allow existing sources registered using just the server APIs to render in the UI.

This means that any sources already registered using the server APIs, available since 6.5, will appear in the UI, at least minimally, without any action required.

For example, given the following server registration and block markup…

Server Registration
function my_plugin_register_block_bindings_post_attributes() {
    register_block_bindings_source(
        'my-plugin/post-attributes',
        array(
            'label'              => _x( 'Post Attributes', 'block bindings source', 'my-plugin' ),
            'get_value_callback' => 'my_plugin_block_bindings_post_attributes_get_value',
            'uses_context'       => array( 'postId' ),
        )
    );
}
add_action( 'init', 'my_plugin_register_block_bindings_post_attributes' );

function my_plugin_block_bindings_post_attributes_get_value( array $source_args, $block_instance ) {
    $allowed_fields = array( 'title', 'excerpt' );
    if ( ! in_array( $source_args['key'], $allowed_fields ) ) {
        return null;
    }
    $post = get_post( $block_instance->context['postId'] );
    return $post->{'post_' . $source_args['key']};
}
Block Markup
<!-- wp:paragraph {"metadata":{"bindings":{"content":{"source":"my-plugin/post-attributes","args":{"key":"title"}}}}} -->
<p></p>
<!-- /wp:paragraph -->

…the source will get registered in the editor with the source’s name my-plugin/post-attributes, label, and uses_context values. This is enough for the UI to render as follows:

In this case, however, the bound paragraph in the block canvas will simply show the source label and will not be dynamic. Further customization of the editor experience requires using the new editor registration functions, detailed in the next section.

Editor Registration

The following functions have been exposed to allow customization of the editor experience:

  • registerBlockBindingsSource: Registers a source on the client (using this function will override the bootstrapped registration).
  • unregisterBlockBindingsSource: Unregisters an existing source.
  • getBlockBindingsSource: Gets a specific registered source and its properties.
  • getBlockBindingsSources: Gets all the registered sources in the client.

These are based on other registration APIs like block types, block variations, or block collections.

Source Properties

Registered sources in the client can include the following properties:

  • name: The unique and machine-readable name.
  • label: Human-readable label. Will overwrite preexisting label if it has already been registered on the server.
  • usesContext: Array of context needed by the source only in the editor. Will be merged with existing uses_context if it has already been registered on the server.
  • getValues: Function to get the values from the source. It receives select, clientId, context, and the block bindings created for that specific source. It must return an object with attribute: value. Similar to getBlockAttributes.
  • setValues: Function to update multiple values connected to the source. It receives select, clientId, dispatch, context, and the block bindings created for that specific source, including the new value. Similar to updateBlockAttributes.
  • canUserEditValue: Function to let the editor know if the block attribute connected should be editable or not. It receives select, context, and the source arguments.
Example Usages 
Register a Block Bindings Source

Building on the example server registration, use the following JavaScriptJavaScript JavaScript or JS is an object-oriented computer programming language commonly used to create interactive effects within web browsers. WordPress makes extensive use of JS for a better user experience. While PHP is executed on the server, JS executes within a user’s browser. https://www.javascript.com/. to register in the editor by enqueuing on the enqueue_block_editor_assets hook:

import { registerBlockBindingsSource } from '@wordpress/blocks';
import { __ } from '@wordpress/i18n';
import { store as coreEditorStore } from '@wordpress/editor';

const allowedAttributes = [ 'title', 'excerpt' ];

registerBlockBindingsSource( {
    name: 'my-plugin/post-attributes',
    usesContext: [ 'postType' ],	
    getValues( { select, bindings } ) {
        const values = {};
        for ( const [ attributeName, source ] of Object.entries( bindings ) ) {
            if ( allowedAttributes.includes( source.args.key ) ) {
                values[ attributeName ] = select( coreEditorStore ).getEditedPostAttribute( source.args.key );
            }
        }
        return values;
    },
    setValues( { dispatch, bindings } ) {
        const newValues = {};
        for ( const [ attributeName, source ] of Object.entries( bindings ) ) {
            if ( allowedAttributes.includes( source.args.key ) ) {
                newValues[ source.args.key ] = source.newValue;
            }
        }
        if ( Object.keys( newValues ).length > 0 ) {
            dispatch( coreEditorStore ).editPost( newValues );
        }
    },
    canUserEditValue( { context, args } ) {
        return allowedAttributes.includes( args.key ) && 'post' === context.postType;
    },
} );

To connect example blocks to the source, go to the post editor, open the code editor, and use the following markup:

<!-- wp:paragraph {"metadata":{"bindings":{"content":{"source":"my-plugin/post-attributes","args":{"key":"title"}}}}} -->
<p></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph {"metadata":{"bindings":{"content":{"source":"my-plugin/post-attributes","args":{"key":"excerpt"}}}}} -->
<p></p>
<!-- /wp:paragraph -->

For a more in-depth example of how these properties can be defined in a real-world scenario, see the registration for the built-in post meta source.

Unregister a Block Bindings Source
import { unregisterBlockBindingsSource } from '@wordpress/blocks';

unregisterBlockBindingsSource( 'plugin/my-custom-source' );
Get All Block Bindings Sources
import { getBlockBindingsSources } from '@wordpress/blocks';

const registeredSources = getBlockBindingsSources();
Get a Block Bindings Source
import { getBlockBindingsSource } from '@wordpress/blocks';

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

Note: If desired, sources may be registered only on the client and not on the server at all. This could be useful for creating forms in the adminadmin (and super admin), or otherwise using bindings to interact with other parts of WordPress, or other dynamic data.

Block Bindings Utils

The useBlockBindingsUtils hook returns helper functions to modify the metadata.bindings attribute. The hook accepts an optional clientId argument. If the clientId is not specified, the helper functions will execute in the current block edit context.

Right now, the helpers include:

  • updateBlockBindings: This works similarly to updateBlockAttributes. It can be used to create, update, or remove specific connections.
  • removeAllBlockBindings: This is used to remove all existing connections in a block.

Example usage

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

const { updateBlockBindings, removeAllBlockBindings } = useBlockBindingsUtils();

// Updates bindings for url and alt attributes.
updateBlockBindings( {
    url: {
        source: 'core/post-meta',
        args: {
            key: 'url_custom_field',
        },
    },
    alt: {
        source: 'core/post-meta',
        args: {
            key: 'alt_custom_field',
        },
    },
} );

// Removes all bindings set for the block.
removeAllBlockBindings();

Used internally by the default UI for the post meta source and pattern overrides, these utils can be useful in building custom UI for other sources.

For more examples of how these functions are used in practice by the built-in UI, see the calls to updateBlockBindings and removeAllBlockBindings.

New Server Filter

A block_bindings_source_value filter has been introduced to allow for overriding of the value returned by a source in a bound block. It takes the following arguments:

  • value: Value returned by the source.
  • name: Name of the source.
  • source_args: Arguments passed to the source.
  • block_instance: The bound block.
  • attribute_name: The connected attribute in the bound block.
function modify_block_bindings_source_value( $value, $name, $source_args, $block_instance, $attribute_name ) {
    if ( 'core/post-meta' === $name && 'movie_runtime' === $source_args['key'] ) {
        return $value . ' minutes';
    }
    return $value;
}
add_filter( 'block_bindings_source_value', 'modify_block_bindings_source_value', 10, 5 );

Conclusion

The developers behind Block Bindings are always happy to hear feedback. Please feel free to share bugs, feature requests, or other thoughts by creating issues on GithubGitHub GitHub is a website that offers online implementation of git repositories that can easily be shared, copied and modified by other developers. Public repositories are free to host, private repositories require a paid subscription. GitHub introduced the concept of the ‘pull request’ where code changes done in branches by contributors can be reviewed and discussed before being merged be the repository owner. https://github.com/ or leaving a comment on this post.

Anyone can also follow and comment on Block Bindings development via the latest iteration, which is posted in the Block Bindings tracking issue at the beginning of each release cycle. Be sure to subscribe to the tracking issue for updates!

Lastly, if you’d like to help shape the roadmap for Block Bindings by sharing your use cases, feel free to post in Block Bindings discussions.

Props to @santosguillamot @gziolo @cbravobernal @greenshady @fabiankaegy and @welcher for their help compiling this post.

#6-7, #block-bindings, #dev-notes, #dev-notes-6-7