For years, WordPress developers have faced a frustrating bottleneck: displaying custom data inside the block editor required either heavy shortcodes, custom PHP blocks, or diving headfirst into complex React development. If you just wanted to output a simple Advanced Custom Fields (ACF) text string inside a native heading block, the workflow felt disproportionately complex.
That changed with WordPress 6.5 and the introduction of the Block Bindings API.
The Block Bindings API allows you to connect native core block attributes (like the text of a Paragraph block or the URL of an Image block) directly to dynamic data sources, such as post meta, without writing a single line of React. When paired with ACF, it bridges the gap between legacy PHP data structures and the modern block editor.
In this guide, we will walk through exactly how to bind ACF data to native WordPress blocks, allowing you to build dynamic, lightweight sites using standard core blocks.
What is the Block Bindings API?
At its core, the Block Bindings API acts as a bridge. It tells a WordPress block: “Don’t use the static text entered in the editor; instead, fetch your value from this specific data source.”
Before block bindings, if a client wanted an ACF field named “Book ISBN” to appear on a page, you had three primary options:
- Build a custom block using ACF Blocks (requires PHP but adds overhead).
- Build a custom React block (steep learning curve).
- Use a shortcode block (terrible user experience in the editor).
Now, you can simply use a native WordPress Paragraph block and “bind” its content attribute to your ACF book_isbn field. When the field updates, the block updates. This drastically reduces the need for custom block scaffolding and keeps your site utilizing clean, native WordPress markup.
Step 1: Prepare Your ACF Fields
Before we can bind anything, we need data. For this tutorial, let’s assume we are building a library catalog and have a Custom Post Type called “Books.”
We will create a simple ACF field group assigned to the “Books” post type:
- Field Label: Book Author
- Field Name:
book_author - Field Type: Text
Crucial Step: For the Block Bindings API to read post meta natively, the meta field must be registered in WordPress and accessible via the REST API. Fortunately, ACF handles this seamlessly.
When creating your field in the ACF UI, navigate to the Advanced tab of the field settings and ensure Show in REST API is toggled On.
(Note: In ACF 6.8+, ACF introduced a native Block Bindings UI and a datastore filter (acf/settings/enable_datastore) that makes this even easier, but understanding the manual markup is essential for complex architectures or earlier versions).
Step 2: Binding the Block (The Manual Method)
Currently, the native WordPress visual editor (prior to 6.7/6.8 enhancements) does not have a comprehensive point-and-click interface for creating bindings. To connect our ACF field, we must edit the block markup directly.
- Navigate to your “Book” post in the WordPress editor.
- Add a standard Paragraph block and type some placeholder text, like “Author Name Goes Here.”
- Switch to the Code Editor view (click the three vertical dots in the top right of the screen > Code Editor).
- Locate your paragraph block’s HTML comment, which will look something like this:
<!-- wp:paragraph -->
<p>Author Name Goes Here</p>
<!-- wp:paragraph -->
To bind this block to our book_author ACF field, we need to inject the metadata and bindings object into the block’s attributes. Update the block comment to this:
<!-- wp:paragraph {
"metadata": {
"bindings": {
"content": {
"source": "core/post-meta",
"args": {
"key": "book_author"
}
}
}
}
} -->
<p>Author Name Goes Here</p>
<!-- /wp:paragraph -->
Breaking Down the Code:
content: This is the attribute of the block we are targeting. For a paragraph, it’s thecontent. If we were binding an Image block, we might target theurloraltattribute.source: We are usingcore/post-meta, which tells WordPress to look in thewp_postmetadatabase table.key: This is the exact Field Name (book_author) from our ACF setup.
When you switch back to the Visual Editor, you will notice a purple outline around the block. This indicates it is a bound block. The placeholder text will still be visible in the editor, but when you view the post on the frontend, WordPress will intercept the rendering process and replace the placeholder with the actual value from your ACF field.
Step 3: Registering Custom Binding Sources (PHP)
While binding directly to core/post-meta works well for simple text strings, what if you need to manipulate the data before displaying it? Perhaps you want to combine the author’s first and last name, or format a date specifically.
This is where the true power of the Block Bindings API shines: registering your own custom sources using pure PHP.
Let’s register a custom source that outputs a formatted price. In your theme’s functions.php or a custom plugin, add the following code:
add_action( 'init', 'mytheme_register_custom_binding_sources' );
function mytheme_register_custom_binding_sources() {
register_block_bindings_source( 'mytheme/book-data', array(
'label' => __( 'Book Data', 'mytheme' ),
'get_value_callback' => 'mytheme_book_data_callback',
'uses_context' => array( 'postId' ),
) );
}
function mytheme_book_data_callback( $source_args, $block_instance, $attribute_name ) {
// Check which key was requested in the block markup
if ( ! isset( $source_args['key'] ) ) {
return null;
}
$post_id = $block_instance->context['postId'];
switch ( $source_args['key'] ) {
case 'formatted_price':
// Fetch the raw ACF value
$raw_price = get_field( 'book_price', $post_id );
if ( $raw_price ) {
// Return the manipulated data
return '$' . number_format( (float)$raw_price, 2 );
}
return 'Price Unavailable';
default:
return null;
}
}
Now, in the block editor, you can bind a heading or paragraph block to this new custom source instead of the raw post meta:
<!-- wp:paragraph {
"metadata": {
"bindings": {
"content": {
"source": "mytheme/book-data",
"args": {
"key": "formatted_price"
}
}
}
}
} -->
<p>Price Goes Here</p>
<!-- /wp:paragraph -->
By leveraging custom callbacks, you maintain complex PHP logic on the server side while keeping the frontend strictly native blocks, resulting in leaner code and better performance.
Why This Matters for Performance
Using the Block Bindings API instead of heavy third-party page builders or overly complex custom React blocks directly benefits your site’s performance. Because you are utilizing native WordPress blocks, the HTML output is minimal, CSS is efficiently loaded via theme.json, and database queries are optimized by WordPress Core during the render phase.
This lean approach is crucial for optimizing your Core Web Vitals, as it reduces the amount of JavaScript shipped to the browser and prevents DOM bloat.
The Future of Block Bindings
The current implementation of the Block Bindings API is highly developer-focused, requiring manual HTML comment manipulation or code snippets. However, as of WordPress 6.6+, an ‘Attributes’ panel has begun appearing in the sidebar to better surface these connections, and plugins like ACF are rapidly building UI layers on top of this API.
Mastering this API now allows you to build highly dynamic, maintainable architectures that lean into the future of WordPress development. By strictly separating your backend data management from the frontend visual presentation, you ensure content editors can safely update values without ever breaking block layouts—all without tackling the steep, time-consuming learning curve of React.
Frequently Asked Questions (FAQ)
Which core blocks support the Block Bindings API?
Currently, supported blocks include Paragraph (content), Heading (content), Image (url, alt, title), and Button (text, url, linkTarget, rel). Support for more blocks is continually being added in newer WordPress releases.
Can I bind an ACF Repeater field using Block Bindings?
No. The Block Bindings API is currently designed for simple string or scalar values (like Text, Number, or URL fields). Complex array-based data structures, such as ACF Repeaters or Flexible Content fields, are not currently supported and still require custom PHP loops or ACF Blocks to render.
Why does my bound block not show the ACF data in the visual editor?
Unless you are using the latest ACF datastore integrations (ACF 6.8+) which enable bidirectional sync, standard bindings often only display a placeholder in the editor and render the actual dynamic data on the front-end of the website.