WordPress 6.7 is expected to ship on November 12, 2024, and one of the biggest features is the ability to bind block attributes to custom fields directly from the Editor itself. If that doesn’t get you excited about this release, I don’t know what will.
But if you’re one of those developers who has been registering custom binding sources since WordPress 6.5, you may be wondering if WordPress will give the same treatment to your custom sources.
Yes. If you’re willing to put in a little legwork.
WordPress 6.7 will ship a public API for manipulating your blocks connected to custom binding sources in the Editor. Well, at least a partial API that gives you a whole lot of new power to build some interesting features.
In this tutorial, I’ll walk you through making the data from your custom binding sources appear in the Editor and also letting users edit that data from the connected blocks.
For more information on every Block Bindings API update coming to WordPress 6.7, check out the dev note on the Make Core blog.
Table of Contents
Setting up your plugin
Let’s get the basics out of the way first. Create a new folder named devblog-editor-bindings
in your /wp-content/plugins
directory with the following files and subfolders:
/public
/resources
/js
/editor.js
/plugin.php
/package.json
/webpack.config.js
You can, of course, do this same thing from within a theme, but keep in mind that you’ll need to change any plugin-specific functions used in the code examples to use functions appropriate for a theme.
As always when creating a plugin, you must set up your main plugin’s file header so that WordPress recognizes it as a valid plugin. Go ahead and add this code to your plugin.php
file:
<?php
/**
* Plugin Name: Dev Blog Editor Bindings
* Plugin URI: https://developer.wordpress.org/news
* Description: Exploring the Block Bindings API in the editor.
* Version: 1.0.0
* Requires at least: 6.7
* Requires PHP: 7.4
* Author: Your Name
* Author URI: https://developer.wordpres.org/news
* Text Domain: devblog
*/
// Custom code goes here.
Now open package.json
and add the start
and build
scripts, which will point to the /resources
and /public
folders you created earlier:
{
"name": "devblog-editor-bindings",
"scripts": {
"start": "wp-scripts start --webpack-src-dir=resources --output-path=public",
"build": "wp-scripts build --webpack-src-dir=resources --output-path=public"
}
}
Then open your computer’s command line program and type this command to install the @wordpress/scripts
and path
packages:
npm install @wordpress/scripts path --save-dev
The final setup step is extending WordPress’s webpack config so that it knows how to process your custom editor.js
file (this step may not be needed in the future if this pull request is merged). Add this code to your webpack.config.js
file:
// WordPress webpack config.
const defaultConfig = require( '@wordpress/scripts/config/webpack.config' );
// Utilities.
const path = require( 'path' );
// Add any a new entry point by extending the webpack config.
module.exports = {
...defaultConfig,
...{
entry: {
'js/editor': path.resolve( process.cwd(), 'resources/js', 'editor.js' )
}
}
};
With the foundation in place, let’s jump into the fun bits.
Registering a custom block binding source
Registering custom block bindings is well-trodden ground, so I won’t walk through every detail of the process. If this is your first experience with the Block Bindings API, stop here and read the two introductory tutorials:
- Introducing Block Bindings, part 1: Connecting custom fields
- Introducing Block Bindings, part 2: Working with custom binding sources
You’ll learn how to get and set post data with JavaScript as this tutorial progresses. But the first thing you need to do is register a binding for handling this data on the front end. Add this code to your plugin.php
file:
add_action( 'init', 'devblog_register_binding_sources' );
function devblog_register_binding_sources() {
register_block_bindings_source( 'devblog/post-data', [
'label' => __( 'Post Data', 'devblog' ),
'get_value_callback' => 'devblog_post_data_callback',
'uses_context' => [ 'postId' ],
]);
}
In the code above, the get_value_callback
value is set to devblog_post_data_callback
. WordPress triggers this function whenever it finds a block attribute that is connected to the binding source on the front end.
Let’s keep this relatively simple and focus on three pieces of data for our custom bindings source:
- Post title
- Post excerpt
- Post permalink
Each of these are strings, so they are good fits for the current Block Bindings API. Add this callback function to your plugin.php
file:
function devblog_post_data_callback( $args, $block, $name ) {
if ( ! isset( $args['key'] ) ) {
return null;
}
$post_id = $block->context['postId'] ?? get_the_ID();
if ( 'title' === $args['key'] ) {
return get_post_field( 'post_title', $post_id );
} elseif ( 'excerpt' === $args['key'] ) {
return get_post_field( 'post_excerpt', $post_id );
} elseif ( 'permalink' === $args['key'] ) {
return get_permalink( $post_id );
}
return null;
}
This function retrieves the value of the post title, excerpt, or permalink when connected to a block attribute. Otherwise, it returns null
.
Adding block markup
Now let’s make sure that the custom binding source actually works—it won’t do any good to jump into JavaScript if the initial implementation is broken. As always, test early and often.
Go to Posts > Add New Post in your WordPress admin. On the new post screen, click the Options button (⋮ icon in the top corner) and switch to the Code editor view in the dropdown. Then add this block markup before switching back to Visual editor:
<!-- wp:heading {
"placeholder":"Add post title",
"metadata":{
"bindings":{
"content":{
"source":"devblog/post-data",
"args":{"key":"title"}
}
}
}
} -->
<h2 class="wp-block-heading"></h2>
<!-- /wp:heading -->
<!-- wp:paragraph {
"placeholder":"Add post excerpt",
"metadata":{
"bindings":{
"content":{
"source":"devblog/post-data",
"args":{"key":"excerpt"}
}
}
}
} -->
<p></p>
<!-- /wp:paragraph -->
<!-- wp:buttons -->
<div class="wp-block-buttons">
<!-- wp:button {
"metadata":{
"bindings":{
"url":{
"source":"devblog/post-data",
"args":{"key":"permalink"}
}
}
}
} -->
<div class="wp-block-button"><a class="wp-block-button__link wp-element-button">Read post
</a></div>
<!-- /wp:button -->
</div>
<!-- /wp:buttons -->
I know what you’re thinking: this doesn’t look like anything special. You’ll see something like this: