Directory

Introducing Block Bindings, part 1: connecting custom fields – WordPress Developer Blog

Introducing Block Bindings, part 1: connecting custom fields

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.

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 is This 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’s content attribute.
  • source: The bindings source registered via the Block Bindings API that will handle the return value on the server. This must be set to core/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 the key 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’s url attribute.
  • projectslug_image_alt: The alt text you’ll bind to the alt 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 BlocksSupported Attributes
Imageurl, alt, title
Paragraphcontent
Headingcontent
Buttonurl, 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

Props to @santosguillamot, @bph, @ndiego, and @bjmcsherry for providing feedback and reviewing this post.

41 responses to “Introducing Block Bindings, part 1: connecting custom fields”

  1. Joe Hoyle Avatar

    IMO the biggest change to the block editor since its inception! Really fantastic to see progress here, and I think the API is shaping up to meet requirements I’ve encountered when trying to build sites with the block editor. Excited to see how things progress on the UI too.

  2. WebMan Design | Oliver Juhas Avatar

    This is amazing! Thank you for thorough information, Justin.

  3. WebMan Design | Oliver Juhas Avatar

    Just a short addon: currently – while WordPress does not contain a better UI – the UI for inserting custom fields can be improved by using a plugin such as Advanced Custom Fields.

    1. Justin Tadlock Avatar

      I also plan to write a tutorial on building custom field controls in the editor. We have one post, Creating a custom block that stores post meta, that works for some use cases, but I want to do something that feels a little more traditional with the meta fields in the sidebar.

      1. Gregoire Noyelle Avatar

        Hi Justin,

        Thanks a lot. As Oliver mentioned, do you think it is possible to use ACF for saving simple post meta and then use them with your method?

        1. Justin Tadlock Avatar

          I’ve never used ACF before, but I would assume that it registers meta using the standard register_post_meta() or register_meta() API functions under the hood. If that’s the case, it should work great.

          1. Gregoire Noyelle Avatar

            Thanks, Justin. That’s great.
            Yes, for the simple ACF fields, you can use the get_post_meta() function to display the values.

        2. WebMan Design | Oliver Juhas Avatar

          I can confirm this works. Just install ACF, create your metabox and do the blocks magic. 🙂

          1. Mrinal Haque Avatar

            Hi,
            That’s great to know. 🙂
            However, I would like to mention that only the ACF Pro plugin currently can handle “Block binding API” things. But, the free version of ACF is incapable of handling this stuff.

          2. Grégoire Noyelle Avatar

            Thanks Oliver ! Great to know.

  4. Anh Tran Avatar

    This is a great feature and opens a lot of possibilities for developers to extend the functionality.

    Thank you for the tutorial and hopefully, we’ll see more support and more advanced guides on this topic.

  5. Elliott Richmond Avatar

    After experimenting with this today, I think it’s great, especially as it opens up greater flexibility when using meta in templates. However, if we have the ability to bind to existing blocks in 6.5, has there been any thought given to simply creating a “custom meta block”?

    1. Justin Tadlock Avatar

      There’s been a lot of discussion around approaches to meta. I’m about 99% certain there was a meta block ticket, but I couldn’t find it.

      I think, at least for now, the direction seems to be the Block Bindings API approach, which should give developers coverage for the majority of use cases (once it’s fleshed out, of course). Given that Core already has most of the baseline HTML elements in place, most data can be tied to those without much code work. For more complex types of meta, I think you’ll likely still need custom-built blocks.

      But it’d be interesting to see what a dedicated meta block might look like, particularly with how it fits into the overall direction and work that’s been done so far.

      1. Elliott Richmond Avatar

        Indeed, understanding the output of more complex data, such as conditional statements and loops, can be challenging. As you mentioned, it’s likely territory for custom blocks. I also noticed that the example provided only includes ‘single’ meta. I’m eager to see how this develops further.

  6. Sunny Morgan Avatar
    Sunny Morgan

    Is there a plan to simplify the insertion of meta data into the blocks? For example, in the future will we need to go into code view to insert dynamic data into a paragraph?

  7. ivanxxmakarov Avatar

    Hey, everybody.

    I did it just like you did in the video. Also reread the whole article, 3 times uninstalled wordpress completely and put a clean version, tried through ACF custom fields or standard custom fields. Nothing comes out the result is always the same, it just does not output.

    I do not know what to do, I really need to output custom data and do as before through the template does not work, as the page does not work the usual php.

    Here already and do not know what to do.

    Version WordPress 6.4.3

    1. Justin Tadlock Avatar

      This is a feature that’s coming in WordPress 6.5. You can grab the latest 6.5 release candidate here for testing.

  8. HelgaTheViking Avatar

    >WordPress 6.5 doesn’t have a built-in UI for binding custom fields to blocks

    Is that coming in the future? This is a great start, but it’s not really accessible to the average user this way.

    1. Justin Tadlock Avatar

      Currently, it’s mostly just an API (with some small UI integration), so it is very much a developer feature. It’s my understanding that there will be some work toward bringing Block Bindings (particularly for use with custom fields) to the user interface. I don’t know if that’ll happen in 6.6 and what it will look like. I believe the API needs to really be fleshed out first, and we need to see how developers make use of it. We’re really just in “phase 1” of the API itself.

      1. Kathy Avatar

        Sounds good! In the meantime, Brian’s Chords posted a great idea of using block variations to generate a UI right now.
        https://youtu.be/qD5U7TNUKTQ

        1. Justin Tadlock Avatar

          Maybe I misunderstood what you were originally asking. To expand on my original answer (in light of your reply):

          WordPress absolutely has a UI layer for showing that a block is bound to a custom field. This is built into WordPress 6.5. You can see some of that in the screenshots in the post.

          However, WordPress does not have a UI for binding custom fields to blocks (i.e., users can’t create custom bindings without touching code). This is the part that should come in the future.

          Those are two different things, so I want to make sure some clarity on what UI exists and what doesn’t.

          What the addition of Block Variations does is 1) make the bound blocks directly insertable and 2) give you the ability to improve the user experience (e.g., custom icon, title, description, etc.). I highly recommend using Block Bindings alongside Block Variations (which is something that we’re planning to showcase in the next post on the Block Bindings API). But I do want to make it clear that this technique doesn’t generate a UI for binding custom fields to blocks.

          1. HelgaTheViking Avatar

            Thanks for the clarification. My post was def ambiguous. The Block Variations provide an approach for simplifying the creating of blocks that are already bound versus actually providing a UI to select the bound field.

  9. David Innes Avatar

    Awesome to see blocks catching up with features found in mature page builders like Beaver Builder and even Elementor since 2017. Gutenberg users really will find this sort of thing extremely useful.

    I agree 100% it’s always incredibly wasteful how many custom blocks are needed for things that have been bog simple in page builders going back, sometimes as far as 2010 and 2011. So, kudos to the team for adding this much-needed feature.

    Extra credit if you ever get around to adding connections to the actual block interface instead of forcing the average site owner to learn JSON syntax.

  10. Nils Henrik Avatar
    Nils Henrik

    Thank you Justin for this introduction, the whole API looks really promising.

    I understand that, for now, fetching dynamic data via the Block Binding API is not supported when using the query loop, right?

    1. Justin Tadlock Avatar

      You should be able to use the Block Bindings API for supported blocks (Header, Paragraph, Button, and Image) within the Query Loop / Post Template blocks just like you could outside of it.

  11. Lovro Hrust Avatar

    I just wanted to see what happens when various unintended behaviour is introduced and it turns out that it is not well handled (I think I will open issues).
    1. If meta field is not registered, binding displays key instead of value – very bad for debugging. Block is still not editable and shows binding as active.
    2. If field is registered, but there is no value, block shows placeholder, but it is not editable, which will confuse user.

    1. Justin Tadlock Avatar

      1. If meta field is not registered, binding displays key instead of value – very bad for debugging. Block is still not editable and shows binding as active.

      It is standard practice to always register any meta that you use in your plugins/themes. If nothing else, at least to add the correct sanitization callback (also why it was the first step in this tutorial). So I don’t recommend not registering it.

      2. If field is registered, but there is no value, block shows placeholder, but it is not editable, which will confuse user.

      This is the correct and default experience for this version of the API and the associated UI. So it’s a well-known limitation. This API is still very much a developer feature that you have to build around. I’ll be sharing some more tips/tricks related to UI in an upcoming post and a Developer Hours video session, but the tutorial here is primarily focused on using the API.

      There is a ticket that further explores future UI work that’s needed.

  12. Sunny Avatar

    Did WP 6.5 remove the custom fields panel from the preferences?

    1. Justin Tadlock Avatar

      No, it’s still there under Preferences > General > Advanced.

  13. Gin Avatar

    I love this feature and I am going to test it soon, thanks a lot Justin Tadlock!

    Hopefully soon we will have a dedicated Block for it!

  14. Thomas Cigolla Avatar

    It’s definitely not there anymore. The option to enter customized CSS is also no longer there.

  15. Birgit Pauli-Haack Avatar

    The toggle for Custom Fields is only available in the Post Editor.
    Preference > General > Advanced

    The Custom CSS option can be found in the Site Editor right Sidebar > Styles > Custom CSS&gt;

  16. Thomas Cigolla Avatar

    Ok, that was my mistake with the CSS, I didn’t really remember where the setting was.

    That’s a bit confusing with the post editor, why can’t you create a template with the type “Post” in the site editor or change the template type.

    Also, it is not possible to rename a template created in the Site Editor, but a template created via the Post Editor can be renamed? This issue probably belongs in another thread.

  17. Grégoire Noyelle Avatar

    Hi Justin,
    When using this technique with a custom post type, is there a specific setting to add apart from `’show_in_rest’ => true,` for the binding to work?

    1. Justin Tadlock Avatar

      The arguments for register_post_type()? custom-fields might need to be set in your supports array too.

  18. Nilo Velez Avatar

    One thing I really miss out is the ability to disable the output of a specific block based on a binding.

    Quick example. Imagine I have a custom field in a block to show the event a video belongs to:

    —-
    Event
    WordCamp Bilbao 2024
    —-

    If the custom field is empty, I want it to disappear, but also the heading “Event”.
    So, one solution could be to bind the (visibility?) of the container of both elements to the “emptiness” of the custom field

  19. Andre Ranulfo Avatar

    A real game changer!

  20. RS Avatar
    RS

    I see when registering the post meta, you are using ‘register_meta()’ , but from this youtube tutorial https://www.youtube.com/watch?v=qD5U7TNUKTQ, it’s using register_post_meta(), what’s the difference?
    If we are using ACF to create custom fields for our CPTs, should we use register_post_meta() or register_meta()?
    thanks!

    1. Justin Tadlock Avatar

      Either is fine. register_post_meta() is just a wrapper function for register_meta() that only lets you register meta for posts.

Leave a Reply

Your email address will not be published. Required fields are marked *