WordPress Block Bindings API: connect blocks to post meta and custom data

By: Irina Shvaya | October 1, 2026
This guide is part of our WordPress resource hub: costs and hosting, the block editor, plugins, SEO and speed, security, maintenance, WooCommerce, development, comparisons and migrations.

The Block Bindings API lets a block attribute take its value from somewhere other than the block itself. Instead of typing a price into a Paragraph block, you bind the paragraph's content to a custom field, and WordPress fills in the current value every time the page renders. The same mechanism powers Pattern Overrides, which let editors change specific blocks inside a synced pattern.

The API arrived in WordPress 6.5 and has been extended in almost every release since. As of October 2026 (WordPress 7.1.2), WordPress ships four built-in sources (post meta, post data, term data and pattern overrides), lets developers register their own sources in PHP and JavaScript, and, since 6.9, lets developers extend which block attributes can be bound, including attributes of custom blocks.

This guide explains how bindings are stored, which blocks and attributes support them, how to bind a block to post meta, how to register a custom source, and where bindings fit next to custom blocks and field plugins.

Key Takeaways

  • A binding is stored in the block's metadata.bindings attribute and maps an attribute (such as content or url) to a source and optional arguments.
  • By default, bindings work with specific attributes of the Image, Heading, Paragraph, Button, Navigation Link, Navigation Submenu and Post Date blocks.
  • To bind post meta, register the meta key with show_in_rest set to true; keys starting with an underscore are protected and cannot be bound.
  • Custom sources are registered with register_block_bindings_source() on the server and registerBlockBindingsSource() in the editor.
  • Since WordPress 6.9, the block_bindings_supported_attributes filters add bindable attributes, and since 7.0 those attributes also work with Pattern Overrides, including on custom blocks.

How a binding is stored

Bindings live in the block's comment delimiter, inside a metadata object. For example, a Paragraph bound to a custom field called book_author looks like this in the post content: <!-- wp:paragraph {"metadata":{"bindings":{"content":{"source":"core/post-meta","args":{"key":"book_author"}}}}} --> <p>Fallback content</p> <!-- /wp:paragraph -->.

Three parts matter:

  • The attribute (content) that will receive the value.
  • The source (core/post-meta), a registered name that knows how to fetch the value.
  • The args, which the source uses to find the right value (here, the meta key).

When the page renders, WordPress calls the source's callback and replaces the attribute's value in the output. The saved HTML ("Fallback content") is what appears if the source returns nothing. Because the binding is just block markup, it works in posts, templates, template parts and patterns, and theme authors can ship bound blocks inside block themes.

Supported blocks and attributes

Not every attribute can be bound. The Block Bindings reference (last updated July 2026) lists this default set:

BlockBindable attributesTypical use
core/imageid, url, title, alt, captionProduct photo, author headshot, logo from a custom field
core/headingcontentEvent name, property address, product model
core/paragraphcontentPrice, opening hours, short facts
core/buttonurl, text, linkTarget, relBooking link, download URL, external listing
core/navigation-linkurlMenu items that follow a page or term
core/navigation-submenuurlSubmenu parents that follow a page or term
core/post-datedatetimeShow a custom date instead of the publish date

The reference notes "ongoing effort to increase this compatibility." You can also widen the list yourself with a filter, covered below.

Built-in sources

  • core/post-meta: reads a registered post meta field. Args: key.
  • core/post-data (since 6.9): reads post fields. Available fields are date, modified and link.
  • core/term-data (since 6.9): reads term fields (id, name, link, slug, description, parent, count) when term context is available, for example inside the Terms Query block's term template.
  • core/pattern-overrides: lets each instance of a synced pattern override the bound attribute, keyed by the block's metadata.name.

A pattern-overrides example: inside a synced pattern, a paragraph with {"metadata":{"bindings":{"content":{"source":"core/pattern-overrides"}},"name":"custom-heading"}} becomes editable per instance, and each instance stores its own value, such as <!-- wp:block {"ref":123,"content":{"custom-heading":{"content":"My custom heading text"}}} /-->. Our block theme development guide shows where patterns fit in a theme.

Binding a block to post meta, step by step

This is the most common use: show a custom field in a template without writing a custom block.

  1. Register the meta key on the init hook: register_post_meta( 'book', 'book_author', array( 'show_in_rest' => true, 'single' => true, 'type' => 'string', 'sanitize_callback' => 'sanitize_text_field' ) ). The reference's example uses register_meta( 'post', ... ), which works the same way for all post types; register_post_meta() scopes the field to one post type.
  2. Do not use a leading underscore. The reference states that keys such as _example_key "are protected and cannot be used with Block Bindings."
  3. Add the binding in a template (for example single-book.html) or a post, either by editing the block markup as shown above or through the editor UI.
  4. Check the front end. The paragraph now shows the field's value for whichever book is being viewed, because the source reads the current post from block context.

Since WordPress 6.7 the block sidebar includes an Attributes panel that shows active bindings and lets users connect supported attributes to registered post meta. According to the 6.7 dev note, a canUpdateBlockBindings editor setting controls who can change bindings in the UI, and by default only administrators can.

Custom post types and their fields are the usual data model behind bindings. If you are setting that up from scratch, see our guide to creating custom post types.

Registering a custom source

When data lives somewhere other than post meta (an options page, a custom table, a CRM, an external API), register your own source. For pulling third-party data into WordPress in the first place, see our guide to integrating APIs with WordPress; cache remote responses rather than calling the API on every render. A source needs a name, a label and a callback, and can be registered on the server, in the editor, or both.

Server registration (front-end values)

Call register_block_bindings_source() from a function hooked to init. A small example that exposes a site-wide phone number stored in an option:

add_action( 'init', function () { register_block_bindings_source( 'my-plugin/business-info', array( 'label' => __( 'Business info', 'my-plugin' ), 'get_value_callback' => function ( array $source_args ) { if ( isset( $source_args['field'] ) && 'phone' === $source_args['field'] ) { return get_option( 'my_plugin_phone', '' ); } return null; }, ) ); } );

A paragraph can then use {"source":"my-plugin/business-info","args":{"field":"phone"}}. The callback receives three arguments ($source_args, $block_instance and $attribute_name), and you can declare uses_context (for example array( 'postId' )) to read the current post ID from $block_instance->context. Values can be adjusted globally with the block_bindings_source_value filter (since 6.7), which receives the value, source name, source args, block instance and attribute name.

Treat the callback as public output. It runs for every visitor who loads a page containing the bound block, so it must only return data that anyone may see, and it should return plain values rather than markup.

Editor registration (what editors see and edit)

Since 6.7, registerBlockBindingsSource() from @wordpress/blocks controls the editor side. It accepts name, label, usesContext and four optional functions:

  • getValues: returns the values to show in the editor, as an object keyed by attribute.
  • setValues: writes changes back (for post meta, typically by dispatching editEntityRecord in the core-data store).
  • canUserEditValue: decides whether the bound value is editable in place; by default it is not.
  • getFieldsList (since 6.9): returns fields (label, type, args) so your source appears in the bindings dropdown. A field only appears for attributes whose type matches.

If you register a label on the server, leave it out of the editor registration; the reference says the editor label overrides the server one.

Extending bindings to more attributes and custom blocks

Since WordPress 6.9, two filters control which attributes can be bound: block_bindings_supported_attributes (general) and block_bindings_supported_attributes_{$block_type} (per block). For example, add_filter( 'block_bindings_supported_attributes_core/image', function ( $attributes ) { $attributes[] = 'linkDestination'; return $attributes; } ) makes the Image block's link destination bindable, and the same pattern with your own block name (block_bindings_supported_attributes_my-plugin/my-block) opts in a custom block's attributes.

WordPress 7.0 built on this. The 7.0 Pattern Overrides dev note explains that any attribute supporting Block Bindings now also supports Pattern Overrides, lifting the earlier limit to a fixed set of core blocks. For dynamic blocks, the bound values are passed to render_callback(). For static blocks, WordPress uses the HTML API to replace values for attributes sourced from html, rich-text or attribute selectors; if your selectors are more complex or your attributes are unsourced, add a render_callback or a render_block filter so the bound value appears.

If you are building the block itself, our guide to custom block development covers block.json attributes and the static versus dynamic choice that affects this.

Block bindings vs custom blocks vs field plugins

ApproachBest whenLimits
Block bindings on core blocksYou need to display one value (text, URL, image) inside an existing block and keep the theme's stylingOnly supported attributes; one value per attribute; layout logic stays in templates
Custom dynamic blockOutput combines several fields, needs conditional logic or a custom layoutRequires a plugin and build tooling (or PHP-only registration since 7.0)
Field plugin blocks or shortcodesThe site already depends on a field plugin's tools and editing UITies templates to that plugin; check how content behaves if it is removed

Bindings are a good default for "show this field here" in block themes, because they keep content in core blocks that any theme can style. When the display logic gets complicated, a dynamic block is usually clearer than chaining many bindings.

Practical tips and limitations

  1. Always register meta with show_in_rest. Unregistered or non-REST meta will not bind.
  2. Add a sanitize_callback when registering meta that editors can change, and consider an auth_callback to control who may edit the field.
  3. Keep fallback content meaningful. It is what visitors see if the source returns nothing.
  4. Remember context. core/post-meta reads the current post from block context; inside a Query Loop, each item gets its own post ID.
  5. Do not expose private data through a source. Sources run on the front end for all visitors.
  6. Test with caching. Bound values render on the server, so full-page caches show the value from when the page was cached.
  7. Document your sources. Templates that rely on a plugin's source break visually if that plugin is deactivated, so note the dependency in the theme or plugin readme.

For more on safe data handling, our posts on building secure WordPress plugins and WordPress coding standards cover sanitizing, escaping and capability checks.

Conclusion

Block bindings turn core blocks into data-aware components: a paragraph that shows a custom field, an image that follows an attachment ID, a button whose URL comes from your CRM. Register meta with show_in_rest, use the built-in sources where you can, register a custom source when data lives elsewhere, and use the 6.9 filters to make more attributes bindable. Since WordPress 7.0, the same work also unlocks Pattern Overrides for custom blocks. You will find related tutorials in our WordPress resource hub.

Frequently asked questions

Which WordPress version introduced block bindings?

WordPress 6.5 (April 2024). The editor UI panel arrived in 6.7, post-data and term-data sources and the supported-attributes filters in 6.9, and Pattern Overrides for any bindable attribute, including custom blocks, in 7.0.

Why does my post meta binding show nothing?

The most common causes are a meta key that was not registered with show_in_rest set to true, a key that starts with an underscore, an attribute that is not bindable, or a block that has no post context (for example, a template viewed outside a single post).

Can I bind a block to an ACF or SCF field?

Through core/post-meta, only if the field's value is stored as registered post meta exposed to the REST API. Field plugins can also register their own sources: ACF, for example, documents an acf/field block bindings source. Check your field plugin's documentation for its current requirements.

Can editors change bound values from the editor?

That depends on the source. A source's editor registration decides with canUserEditValue whether values can be edited in place, and who may create or change bindings is controlled by the canUpdateBlockBindings setting, which is limited to administrators by default.

Do block bindings work in classic themes?

Bindings are part of block markup, so they work anywhere blocks render, including block content in classic themes. They are most useful in block themes, where templates are made of blocks.

Put this into action with eSEOspace

We help businesses grow with website design that actually performs. Explore the services behind this guide:

Book a free strategy call →

Get a FREE Audit

We'll perform a comprehensive SEO, AEO, GEO & CRO audit of your website — completely free — and show you exactly how to outrank your competitors.

Don't have a site yet? Get in touch →

Get a FREE GEO/AEO/SEO Audit

We'll analyze your site's SEO, GEO, AEO & CRO — completely free — and show you exactly how to get found across Google and AI answers.

Don't have a site yet? Get in touch →

You Might Also like to Read