Looking over the laundry list of developer-specific features coming in WordPress 6.5, I’m like a kid on Christmas morning, shredding the wrapping paper to reveal all the goodies Santa dropped off the night before. But there’s that one special gift. The big one. The one I’ve been wishing and hoping for.
It’s the Block Bindings API.
For extenders, this is the foundation of so many features we’ve all been asking for since the launch of WordPress 5.0 and the Block Editor. This initial iteration provides support for custom fields integration, pattern overrides, and custom bindings.
This post is the start of an in-depth series that covers what block bindings are, why you should use them, and how to use them in your projects. In this first post, you’ll learn how to bind custom fields to block attributes.
I encourage you to leave comments on what you’d like to build with the Block Bindings API. What you see in WordPress 6.5 is only the first iteration of a massively powerful feature that will only become better in the versions to come.
If you’re reading this before WordPress 6.5 has been released, make sure that you’re testing with the latest version of WordPress trunk and the most up-to-date version of the Gutenberg plugin. Please report any issues that you find.
Table of Contents
What are block bindings?
Before we dive into the really fun stuff like connecting custom fields, let’s set the groundwork. It’s important to understand what the Block Bindings API is and why it’s so vital to the future of WordPress.
The basic structure of a block and bindings
Take a look at the markup for a basic Image block:
<!-- wp:image -->
<figure class="wp-block-image"><img src="" alt=""/></figure>
<!-- /wp:image -->
What the Block Bindings API does is let 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.
This means you can do things like bind a custom URL to the Image block’s url
attribute and text to the alt
attribute with data from custom fields (post meta), site data, and even more.
It’s also necessary to understand what attributes are available for a block that you want to bind data to. For the Image block, you can view its attributes via its block.json
file. There are many potential attributes. But for this exercise, let’s focus only on url
and alt
:
{
"attributes": {
"url": {
"type": "string",
"source": "attribute",
"selector": "img",
"attribute": "src",
"__experimentalRole": "content"
},
"alt": {
"type": "string",
"source": "attribute",
"selector": "img",
"attribute": "alt",
"default": "",
"__experimentalRole": "content"
}
}
}
If you look closely at the block markup and compare it to the attributes
property in block.json
, you’ll see:
- The
url
block attribute maps to<img src=""/>
. - Likewise, the
alt
block attribute maps to<img alt=""/>
.
In a real-world scenario, the Image block markup would look more like this (formatted for clarity):
<!-- wp:image {
"lightbox":{"enabled":true},
"id":1,
"sizeSlug":"large",
"linkDestination":"none"
} -->
<figure class="wp-block-image size-large">
<img src="/path/to/image.jpg" alt="This is the image alt text" class="wp-image-1"/>
</figure>
<!-- /wp:image -->
This markup indicates that:
- The
url
block attribute is/path/to/image.jpg
. - The
alt
block attribute isThis is the image alt text
.
It’s important to grasp the relationship between block attributes and how they are represented in the markup because the Block Bindings API works entirely with the attributes system.
Why the Block Bindings API is useful
What makes Bindings so powerful is that you can bind dynamic data to block attributes. Before WordPress 6.5, adding dynamic data within the block system meant building a custom dynamic block.
Let’s take a look at a real-world example. If you open the Your Name movie page from the WP Movies Demo, you will see a lot of data that has been generated dynamically:
Much of what you see there is (currently) built with several custom blocks that are tied to metadata. You can see this from the project’s GitHub repository. What if the team didn’t need to build all of those as custom blocks and could use their existing post meta fields instead? Some easy wins right now would be to use bindings to replace movie data like:
- Rating
- Release date
- Runtime
- Language
- Budget
- Revenue
Building custom blocks for that type of data has always felt like overkill in many situations, especially when the basic HTML markup of what you were building already existed as a Core block. For example, why build a custom block that uses a simple <p>
element with RichText content when the Core Paragraph block exists?
If you’re not very comfortable with advanced React JavaScript, the onramp to extending WordPress could feel more like climbing a mountain. The first version of the Block Bindings API will make that climb far less daunting, handing you more power with less code.
Sticking with the Image block example from the previous section, imagine connecting a custom URL from various sources like:
- A custom field
- A custom database table
- The media source on an image attachment template
- A fallback when the user doesn’t set an image
You don’t need to build a custom block for those things. You can bind the data directly to the existing WordPress Image block either through a Core or custom binding source, depending on the scenario.
Here’s an example of an Image block’s markup when pulling data from a fictional binding source:
<!-- wp:image {
"metadata":{
"bindings":{
"url":{
"source":"namespace/slug",
"args":{
"key":"some-field"
}
},
"alt":{
"source":"namespace/slug",
"args":{
"key":"some-other-field"
}
}
}
}
} -->
<figure class="wp-block-image">
<img src="" alt="" />
</figure>
<!-- /wp:image -->
Seriously, you’re just plugging in a few fields to make it work.
We’ll get to what each of those things does. I just wanted to familiarize you with the markup before jumping too far ahead.
The point is that Bindings let you attach any dynamic data from any source to a block attribute. (WordPress 6.5 will ship with limited support for a handful of Core blocks and attributes, which are listed in the table at the end of this post.)
Imagine a WordPress where you only needed to bind a few fields to an existing baseline block like Image, Heading, Paragraph, or others to create something that behaves just the way you need it to for your use case.
Pretty exciting thought, right? Well, WordPress 6.5 makes it a reality for several use cases.
Connecting custom fields to block attributes
One of the primary use cases for the Block Bindings API is to connect a custom field (i.e., post metadata) to a block. This could be something as simple as adding a custom text field to a Paragraph block. Or it could handle a more advanced scenario like pulling a custom image URL and alt text to attach to an Image block.
We’ll actually walk through both of these examples as a broad introduction to using custom fields, but I’m sure you have plenty of use cases already in mind.
Enabling custom fields
Given how much territory this tutorial will cover, I didn’t want to spend too much time teaching how custom fields work or how to build your own UI elements for them. Those things are out of scope for this post, so any custom fields added will be done through the default Custom Fields panel in the Post Editor.
To enable this panel in your editor, open the Options (⋮ icon) dropdown in the Post Editor and click the Preferences button. Under the Advanced section, toggle the Custom fields option on:
You will be asked to reload your browser so that the Custom Fields panel will appear at the bottom of the editor.
This tutorial shows you how to handle metadata with the Custom Fields panel, which works well for many use cases. But in a real-world project, you’ll most likely build out custom controls in the UI for your plugin/theme users. Or you can use one of the many existing custom fields plugins. That’s totally up to you.
The basics: binding a text field to a Paragraph block
Let’s kick this thing off with the simplest of possible examples: registering a meta key and binding it to a Paragraph block. How about we build something to display today’s mood?
It’s always good practice to prefix custom meta keys with your plugin or theme slug. It should look like this: projectslug_key
.
Your PHP code can run from either a custom plugin file or your theme’s functions.php
. Open the file of your choice and register a post meta key named projectslug_mood
:
add_action( 'init', 'projectslug_register_meta' );
function projectslug_register_meta() {
register_meta(
'post',
'projectslug_mood',
array(
'show_in_rest' => true,
'single' => true,
'type' => 'string',
'sanitize_callback' => 'wp_strip_all_tags'
)
);
}
Again, this tutorial isn’t about how to register meta. Just keep in mind that you must set show_in_rest
to true
for meta fields to work over the REST API and in the Block Editor. For more information on registering custom meta, refer to the register_meta()
documentation.
Now that you have registered your post meta, you’re ready to test a custom value and bind it to a block.
Open the Post Editor from your WordPress admin and scroll down to the Custom Fields panel. Add the projectslug_mood
key under the Name field and enter any text you want under the Value field. Then hit the Add Custom Field button:
WordPress 6.5 doesn’t have a built-in UI for binding custom fields to blocks, so you’ll need to switch to the Code Editor view for this next step. You can locate it via the Options menu (the ⋮ button in the top right panel).
Now add this block markup to the editor:
<!-- wp:paragraph {
"metadata":{
"bindings":{
"content":{
"source":"core/post-meta",
"args":{
"key":"projectslug_mood"
}
}
}
}
} -->
<p></p>
<!-- /wp:paragraph -->
Let’s take a brief moment to study the block markup you just entered before we get too far ahead of ourselves. There are certainly a lot of nested properties there!
Here is an overview of each of those nested properties:
metadata
: An object that contains metadata about the block.bindings
: An object that can contain one or more bindings for the block.content
: The block attribute to bind to the custom field. In this case, it’s the Paragraph block’scontent
attribute.source
: The bindings source registered via the Block Bindings API that will handle the return value on the server. This must be set tocore/post-meta
to use the built-in custom fields handling (we’ll cover other sources in Part 2 of this series).args
: An object that can contain one or more arguments to pass to the block bindings source. For custom fields, you must always set thekey
property to the name of the meta key you want to bind to the block attribute.
Now switch back to the Visual Editor view. You might see the projectslug_mood
key appear as the Paragraph content at first. The important part is that you should not be able to edit it from the Visual Editor itself.
Once you save the post, the value you entered into to Custom Fields panel should appear in its place:
If you view the post on the front end of your site, you should see the exact same output.
Now, of course, in a real-world project, you are going to build a custom UI or use a third-party plugin for inputting the data. And often, you will actually be outputting these fields in patterns or templates. This is just a quick and clean method of testing the underlying API and custom fields.
More advanced: multiple bindings on an Image block
Let’s kick this up a notch and try registering two different bindings to a single block. In this exercise, you’ll add a custom URL and alt text to an Image block. The process is pretty much the same.
First, register two metadata keys for posts:
projectslug_image_url
: This will store the URL that you’ll bind to the Image block’surl
attribute.projectslug_image_alt
: The alt text you’ll bind to thealt
attribute.
Open either your plugin file or your theme’s functions.php
(whichever you decided on in the previous step). Then add this code inside of the projectslug_register_meta()
function that you added earlier:
register_meta(
'post',
'projectslug_image_url',
array(
'show_in_rest' => true,
'single' => true,
'type' => 'string',
'sanitize_callback' => 'esc_url_raw'
)
);
register_meta(
'post',
'projectslug_image_alt',
array(
'show_in_rest' => true,
'single' => true,
'type' => 'string',
'sanitize_callback' => 'wp_strip_all_tags'
)
);
Head back to your Post Editor in the WordPress admin. Before adding any data to the Custom Fields panel, let’s see what an empty Image block looks like with the bindings in place.
Open the Code Editor view and paste this block markup into it:
<!-- wp:image { "metadata":{
"bindings":{
"url":{
"source":"core/post-meta",
"args":{
"key":"projectslug_image_url"
}
},
"alt":{
"source":"core/post-meta",
"args":{
"key":"projectslug_image_alt"
}
}
}
}
} -->
<figure class="wp-block-image">
<img src="" alt="" />
</figure>
<!-- /wp:image -->
If you recall from the previous section, the bindings
property for a block can contain multiple attributes. Take note of the structure in comparison to the Paragraph block from the previous section.
Once you’ve added the code, switch back to the Visual Editor. Your Image block should look like this:
As you can see, the UI around the Image block is a little nicer by default. It provides a message that the block is connected to a custom field. If you open your sidebar panel for the block, you should also see the same message for the Alternative Text field.
The most important thing is that both the image upload and alt text field should be locked from editing.
Now go to your Custom Fields panel in the post editor and enter a custom image URL for the projectslug_image_url
meta key and custom text for projectslug_image_alt
.
Once you’ve saved your fields and the post, the Image block should appear with the correct image and alt text in the UI:
Adding a fallback meta value
The Core register_meta()
function lets you register a default
field. If you set this when registering your meta key, it will appear as the default value until the user has set the meta value.
Let’s revisit the code where you registered the meta keys for the Image block in the previous section. Now add a new default
argument for the projectslug_image_url
meta. In the example below, you can see that I’ve set this to an image URL in my theme folder:
register_meta(
'post',
'projectslug_image_url',
array(
'show_in_rest' => true,
'single' => true,
'type' => 'string',
'sanitize_callback' => 'esc_url_raw',
'default' => get_theme_file_uri( 'assets/images/default.jpg' )
)
);
This is especially useful if you want to output a default when a user hasn’t entered a custom value. Here is what the Image block looks like with the default set for the projectslug_image_url
meta key:
You are more likely to use custom fields within WordPress’s template or patterns systems than in the Post Editor. And we’ve barely even scratched the surface of how you will use this in your day-to-day work. This is meant as a starting point for you to build your own solutions.
The current limitations and the future of the Block Bindings API
I bet you’re chomping at the bits to begin implementing this in your own projects—I know I am!
But before you take a nosedive into the deep end, I want you to understand what’s possible in WordPress 6.5 vs. what’s coming in future releases.
The biggest limitation is what blocks and attributes you can bind data to. The list is short for WordPress 6.5, but you can do a lot with a little:
Supported Blocks | Supported Attributes |
---|---|
Image | url , alt , title |
Paragraph | content |
Heading | content |
Button | url , text , linkTarget , rel |
There is no custom block support or way to define additional supported attributes. But this is only the beginning, and it’s a very solid start to one of the most exciting developer features to land in WordPress.
There is a huge list of planned features that you can look forward to with WordPress 6.6 and beyond:
- Additional block and attribute support based on feedback (note that the bindings rely heavily on what’s possible with the HTML API).
- An opt-in mechanism so that any block can enable bindings.
- Making the editor APIs public, giving you more control over the user experience.
- An interface for editing the custom field values directly in the editor when a binding exists (yes, you read that right: a block-native custom fields editing experience).
- The addition of more Core sources for data beyond custom fields like site data, user data, and more.
Up next: creating custom bindings sources
If you’re interested in going even deeper into the Block Bindings API, stay tuned into the Developer Blog. The next post in this series will teach you how to register your own bindings sources.
In the meantime, I encourage you to explore what’s possible with custom fields. And please share all of your feedback—good or bad—in the comments. I want to see this feature continue to evolve in the coming WordPress releases.
Resources
- Connecting block attributes and custom fields
- Block Bindings API
- WordPress/gutenberg#58961
- Known issues to be fixed for WordPress 6.5:
Props to @santosguillamot, @bph, @ndiego, and @bjmcsherry for providing feedback and reviewing this post.
Leave a Reply