The Block Bindings API is a powerful tool in the block editor that lets you connect any data source to a block’s attributes.
This API was first introduced in WordPress 6.5 and, in its initial implementation, enabled WordPress users to display custom field values within posts and pages.
The Block Bindings API serves as the foundation for other robust WordPress features. Examples include Synced pattern overrides and the Post Date block variation introduced in WordPress 6.9.
So, exactly what is the Block Bindings API? And what is it used for? We will provide a simple introduction and a real-world example showing how to create bindings between Gutenberg blocks and external data sources.
Let’s get to work.
The Block Bindings API: Basic concepts
As we mentioned above, the Block Bindings API allows you to create bindings between a data source and the attributes of a block.
If you’re not familiar with block attributes, navigate to the src directory of the Gutenberg project’s block library on GitHub, find the Paragraph block, and open the block.json file. The attributes property provides a list of the Paragraph block’s attributes.
"attributes": {
"content": {
"type": "rich-text",
"source": "rich-text",
"selector": "p",
"role": "content"
},
"dropCap": {
"type": "boolean",
"default": false
},
"placeholder": {
"type": "string"
},
"direction": {
"type": "string",
"enum": [ "ltr", "rtl" ]
}
},
The following blocks support the Block Bindings API as of WordPress 6.9 and can therefore be linked to your custom fields:
| Supported blocks | Attributes |
|---|---|
| Paragraph | content |
| Title | content |
| Imagin | id, url, alt, title, caption |
| Button | text, url, linkTarget, rel |
To connect your custom fields to Gutenberg blocks, you must first register them. The following code registers a custom field via a WordPress plugin or your theme’s functions.php file:
add_action( 'init', function() {
register_post_meta( 'your-post-type', 'myplugin_meta_key', [
'show_in_rest' => true,
'single' => true,
'type' => 'string',
'description' => __( 'City name', 'textdomain' ),
'auth_callback' => 'is_user_logged_in',
] );
} );
Attributes define the characteristics of custom fields, and the documentation provides a complete list of them. To make a custom field available to the Block Bindings API, you must set show_in_rest to true. As of WordPress 6.9, string is the only supported type.
To see the Block Bindings API in action with custom fields, create a new WordPress plugin and register a meta field with the code shown above.
<?php
/**
* Plugin Name: Block Bindings example
* Description: Example plugin that uses the Block Bindings API.
* Version: 1.0.0
* Author: Your Name
* License: GPL2 or later
* Text Domain: block-bindings-example
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
add_action( 'init', function() {
register_post_meta( '', 'block_bindings_image_url', [
'show_in_rest' => true,
'single' => true,
'type' => 'string',
'description' => __( 'City name', 'block-bindings-example' ),
'auth_callback' => 'is_user_logged_in',
] );
} );
In your WordPress dashboard, activate the plugin. Then, navigate to the Posts screen and create a new post. When you select a supported block, the Attributes panel in the Block Settings sidebar will display the list of attributes that can be bound to a registered custom field.

Open the Options menu in the top right corner and select Preferences. In the General tab, locate the Advanced section and enable custom fields. Save your changes, wait for the page to reload, then return to the editor.

Your next step is to insert an Image block. With the block selected, click the + icon in the Attributes panel and select the url attribute. The Attributes panel will then show a list of available meta fields. Select url again. Now, you will see the list of meta fields available for the current post type.

Select your meta field and save the post. You should now see your image in both the editor and the frontend.

Starting with version 6.7 of WordPress, you can use the Label attribute to display text in the editor interface. The following code block shows an example:
add_action( 'init', function() {
register_post_meta( '', 'block_bindings_image_url', [
'show_in_rest' => true,
'single' => true,
'type' => 'string',
'description' => __( 'City image', 'block-bindings-example' ),
'label' => __('Image URL'),
'auth_callback' => 'is_user_logged_in',
] );
} );

When you open the code editor, you can see a JSON object within the image block delimiter. The metadata.bindings.url property shows that the url of the image block is linked to a metadata field.
<!-- wp:image {
"metadata":{
"bindings":{
"url":{
"source":"core/post-meta",
"args":{
"key":"block_bindings_image_url"
}
}
}
}
} -->
<figure class="wp-block-image"><img alt="/></figure>
<!-- /wp:image -->
The source property specifies the data source for the block bindings. The args.key property establishes a reference to your meta field.
The most interesting aspect of the Block Bindings API is its ability to register custom data sources, which opens up some exciting new possibilities for developers. Next, we’ll explore how to use data from third-party services with the Block Bindings API.
How to register custom Block Bindings data sources: A real-life example
Once you are familiar with the Block Bindings API’s basic concepts, we can move on to its more advanced and interesting aspects for developers.
As mentioned earlier, the Block Bindings API allows you to register custom data sources. This enables you to retrieve data from a remote source and/or manipulate raw data to generate useful information that can be automatically inserted into your content.
In this section, you learn how to maximize the potential of Block Bindings through a practical example that you can use as a foundation for developing your own custom applications.
Suppose you want to retrieve data from an external source and display it in your posts, pages, or custom post types. For instance, you might query a weather service API by sending a request with the latitude and longitude of a city to get real-time weather data, which you could then display on your site.
Thanks to the Block Bindings API, you can display the current temperature or provide your readers with the weather forecast for the coming days. You can also programmatically change the url attribute of one or more images on the page depending on weather conditions.
To add this feature to your WordPress website, you need to create a plugin. Follow these steps:
Step 1: Create a basic plugin
The first step is to create the plugin files. Navigate to the wp-content/plugins directory of your WordPress installation and create a new folder called block-bindings-example. Inside this folder, add the following files:
/wp-content/plugins/
└── /block-bindings-example/
├── block-bindings-example.php
└── /includes/
├── binding-sources.php
├── meta-fields.php
└── weather-api.php
Open the block-bindings-example.php file in your favorite code editor and add the following code:
<?php
/**
* Plugin Name: Block Bindings Example
* Description: Use WordPress Block Bindings API (6.5+) to dynamically bind weather data from Open-Meteo API to Gutenberg blocks using custom post meta and a custom binding source.
* Version: 1.0.0
* Author: Your Name
* License: GPL2 or later
* Text Domain: block-bindings-example
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
/**
* Cache duration for weather data: 30 minutes
* This reduces API calls and improves performance
*/
define( 'BB_WEATHER_CACHE_TIME', HOUR_IN_SECONDS / 2 );
require_once plugin_dir_path( __FILE__ ) . 'includes/meta-fields.php';
require_once plugin_dir_path( __FILE__ ) . 'includes/binding-sources.php';
require_once plugin_dir_path( __FILE__ ) . 'includes/weather-api.php';
/**
* Setup function
*/
function bb_init_setup() {
bb_register_post_meta();
bb_register_binding_sources();
}
add_action( 'init', 'bb_init_setup' );
Here’s what this code does:
- The constant
BB_WEATHER_CACHE_TIMEdetermines how long weather data is cached. This reduces API calls, improves page performance, and lowers service costs. - The
require_onceexpressions include the necessary scripts to register meta fields, register the binding source, and retrieve data from the API. - The setup function calls two functions that register the post meta fields and the custom binding sources.
Step 2: Register post meta fields
The next step is to register the meta fields you need for your use case. Open the meta-fields.php file in the includes folder and add the following code:
<?php
/**
* Registers custom post meta fields so they appear in the REST API and Block Bindings editor panel
*/
function bb_register_post_meta() {
if ( ! function_exists( 'register_post_meta' ) ) {
return;
}
register_post_meta( 'post', 'block_bindings_city_name', [
'show_in_rest' => true,
'single' => true,
'type' => 'string',
'description' => __( 'Add city name', 'block-bindings-example' ),
'label' => __( 'City name', 'block-bindings-example' ),
'auth_callback' => 'is_user_logged_in',
] );
register_post_meta( 'post', 'block_bindings_image_url', [
'show_in_rest' => true,
'single' => true,
'type' => 'string',
'description' => __( 'Add city image URL', 'block-bindings-example' ),
'label' => __( 'City image URL', 'block-bindings-example' ),
'auth_callback' => 'is_user_logged_in',
] );
register_post_meta( 'post', 'block_bindings_city_lat', [
'show_in_rest' => true,
'single' => true,
'type' => 'string',
'description' => __( 'Add city latitude', 'block-bindings-example' ),
'label' => __( 'Latitude', 'block-bindings-example' ),
'auth_callback' => 'is_user_logged_in',
] );
register_post_meta( 'post', 'block_bindings_city_lng', [
'show_in_rest' => true,
'single' => true,
'type' => 'string',
'description' => __( 'Add city longitude', 'block-bindings-example' ),
'label' => __( 'Longitude', 'block-bindings-example' ),
'auth_callback' => 'is_user_logged_in',
] );
}
The register_post_meta function registers a meta key for use in posts. Note that to use meta fields registered this way with the Block Bindings API, you must set show_in_rest to true and type to string. See the documentation for more information.
Step 3: Register Block Bindings source
It’s time to register your binding source. Open the binding-sources.php file and add the following code:
<?php
/**
* Registers a custom Block Bindings source: bb/weather-condition
*/
function bb_register_binding_sources() {
if ( ! function_exists( 'register_block_bindings_source' ) ) {
return;
}
register_block_bindings_source(
'bb/weather-condition',
[
'label' => __( 'Weather Condition', 'block-bindings-example' ),
'get_value_callback' => 'bb_get_weather_condition_value',
'uses_context' => [ 'postId' ], // We need postId to get meta values
]
);
}
The register_block_bindings_source() function requires the source name and a callback function that retrieves data from a source and returns the manipulated value.
Then, in the same binding-sources.php file, define the callback function.
function bb_get_weather_condition_value( array $source_args, WP_Block $block_instance ) {
$key = $source_args['key'] ?? null;
if ( ! $key ) {
return null;
}
// Get current post ID from block context (always available in post content)
$post_id = $block_instance->context['postId'] ?? null;
// Fallback: use global loop if context is missing
if ( ! $post_id && in_the_loop() ) {
$post_id = get_the_ID();
}
if ( ! $post_id || $post_id <= 0 ) {
error_log( 'BB DEBUG: Could not determine post ID for weather binding' );
return null;
}
$weather_data = bb_fetch_and_cache_weather_data( $post_id );
if ( ! is_array( $weather_data ) || ! isset( $weather_data[ $key ] ) ) {
return null;
}
$value = $weather_data[ $key ];
// Append °C symbol for temperature
if ( $key === 'temperature' ) {
return $value . '°C';
}
return $value;
}
Let’s break down this function:
$source_args['key']identifies the data bound to the block attribute.- The next line retrieves the ID of the current post from the
context. If thecontextis missing, as might be the case with previews, the ID of the current post is retrieved withget_the_ID(). - Then, it calls the
bb_fetch_and_cache_weather_datafunction, which retrieves the data from the API. We will define this function in the next step. $weather_data[$key]contains the data provided by the API, such as temperature and weather state.- If the key is
temperature, it appends°Cto the provided value. - The function then returns the final value.
Step 4: Retrieve data from an external source
As mentioned above, we retrieve data from the Open-Meteo service (free for non-commercial use).
To retrieve the current temperature and weather conditions, you need to send a request to the API that includes the latitude and longitude of a given location and the query var current=weather_code,temperature_2m. Below is an example request:
https://api.open-meteo.com/v1/forecast?latitude=-33.8717&longitude=151.2299¤t=weather_code,temperature_2m
The API provides a response similar to the following:
{
"latitude": -33.8717,
"longitude": 151.2299,
"generationtime_ms": 0.030875205993652344,
"utc_offset_seconds": 0,
"timezone": "GMT",
"timezone_abbreviation": "GMT",
"elevation": 13.0,
"current_units": {
"time": "iso8601",
"interval": "seconds",
"weather_code": "wmo code",
"temperature_2m":"°C"
},
"current": {
"time": "2025-12-01T16:00",
"interval": 900,
"weather_code": 3,
"temperature_2m":7.3
}
}

Now that you know how to get the data you need, open the weather-api.php file and add the following code:
function bb_fetch_and_cache_weather_data( $post_id ) {
$lat = get_post_meta( $post_id, 'block_bindings_city_lat', true );
$lng = get_post_meta( $post_id, 'block_bindings_city_lng', true );
$lat = str_replace( ',', '.', trim( $lat ) );
$lng = str_replace( ',', '.', trim( $lng ) );
if ( ! is_numeric( $lat ) || ! is_numeric( $lng ) ) {
error_log( 'BB DEBUG: Invalid latitude/longitude values after normalization' );
return false;
}
$transient_key = 'bb_weather_data_' . $post_id;
$cached_data = get_transient( $transient_key );
if ( $cached_data !== false ) {
error_log( "BB DEBUG: Cache hit for post ID {$post_id}" );
return $cached_data;
}
// Build Open-Meteo API URL
$api_url = sprintf(
'https://api.open-meteo.com/v1/forecast?latitude=%s&longitude=%s¤t=weather_code,temperature_2m',
rawurlencode( $lat ),
rawurlencode( $lng )
);
error_log( "BB DEBUG: Fetching weather data from: {$api_url}" );
$response = wp_remote_get( $api_url, [ 'timeout' => 10 ] );
if ( is_wp_error( $response ) ) {
error_log( 'BB DEBUG: API request failed – ' . $response->get_error_message() );
return false;
}
if ( wp_remote_retrieve_response_code( $response ) !== 200 ) {
error_log( 'BB DEBUG: API returned non-200 status code' );
return false;
}
$body = wp_remote_retrieve_body( $response );
$data = json_decode( $body, true );
if ( ! $data || ! isset( $data['current'] ) ) {
error_log( 'BB DEBUG: Invalid or empty API response' );
return false;
}
$temperature = $data['current']['temperature_2m'] ?? null;
$weather_code = $data['current']['weather_code'] ?? 0;
$mapped_data = [
'temperature' => round( (float) $temperature ),
'weather_state' => bb_map_wmo_code_to_state( (int) $weather_code ),
];
// Cache for 30 minutes
set_transient( $transient_key, $mapped_data, BB_WEATHER_CACHE_TIME );
error_log( 'BB DEBUG: Weather data fetched and cached successfully' );
return $mapped_data;
}
This function retrieves current weather data from the Open-Meteo API and stores it in the cache using transients. Let’s take a closer look.
- Two calls to
get_post_metaretrieve the latitude and longitude of your location. - The following two lines normalize the decimal separator in case the user enters a comma instead of a period.
- The conditional block checks if the values are in numerical format using
is_numeric(). - Next, it checks if the data is in cache. If so, it returns the cached data and stops the function without sending any request to the API.
- If no data is found in cache, it builds the request and stores the response.
- The following lines provide
temperatureandweather_code. weather_codeis mapped toweather_statethanks to thebb_map_wmo_code_to_statefunction, which is defined below.- The data is saved with
set_transient. - Finally, the function returns the mapped data.
Last, define the function that translates weather_code into a human-readable string:
function bb_map_wmo_code_to_state( $code ) {
if ( $code >= 0 && $code <= 3 ) {
return 'clear';
} elseif ( $code >= 51 && $code <= 67 ) {
return 'rainy';
} elseif ( $code >= 71 && $code <= 77 ) {
return 'snowy';
} elseif ( $code >= 95 ) {
return 'thunderstorm';
}
return 'cloudy';
}
The code is complete, and your plugin is ready for testing.
How to use the Block Bindings API
It’s time to learn how to use the new features added to your site with the Block Bindings API!
In your WordPress dashboard, navigate to the Plugins screen and activate the Block Bindings Example plugin you just created.

After that, create a new post or page. Add an Image block, a title, and four Row blocks containing two paragraphs each, as shown in the image below. Then, save the post.

Following, add your custom fields and save the post again.

Select the Image block and find the Attributes panel in the Block Settings sidebar. Click the + button to open the dropdown menu, which displays the list of Image block attributes that support Block Bindings. Select the url item.

After selecting the block attribute, the Advanced tab will display a new URL element with the description “Not connected.” Click on the url item again to view the list of available binding sources. Post Meta provides the four custom fields registered for the post type, along with their respective values. Select City Image URL.

You assigned the City Image URL meta field to the url attribute of the Image block. You should now see a photo of the city you chose.
Follow the same process for the other meta fields. Assign the City Name field to the content attribute of the Heading block and the Latitude and Longitude fields to the corresponding Paragraph blocks.
Now, connect the last two blocks to your custom binding source. Unfortunately, as you saw in the previous screenshots, this option is not available in the editor UI.
Currently, you need to switch to the code editor and manually write the markup for the two blocks linked to your binding source. Below is the code to display the temperature provided by the Open-Meteo service:
<!-- wp:paragraph {
"metadata":{
"bindings":{
"content":{
"source":"bb/weather-condition",
"args":{
"key":"temperature"
}
}
}
}
} -->
<p>Placeholder</p>
<!-- /wp:paragraph -->
With this method, the name of your binding source will appear in the editor as Weather Condition, but the actual data will only be visible in the front end.

Clearly, manually adding a JSON object to the block markup isn’t a user-friendly process. Fortunately, WordPress 6.9 introduced significant improvements to the Block Bindings API, making it possible to create a UI for custom data sources. Let’s try improving our plugin with a custom UI.
How to create a UI for your custom Block Bindings sources
To create a UI for your custom binding source, you need to write some JavaScript code. First, create a js subfolder under /includes and then create a block-bindings-ui.js file inside it. The plugin structure is now the following:
/wp-content/plugins/
└── /block-bindings-example/
├── block-bindings-example.php
└── /includes/
├── binding-sources.php
├── meta-fields.php
└── weather-api.php
└── /js/
└── block-bindings-ui.js
As a first step, add the JS script to the main file of your plugin:
function bb_enqueue_weather_bindings_ui() {
if ( ! function_exists( 'register_block_bindings_source' ) ) {
return;
}
$js_file_path = plugin_dir_path( __FILE__ ) . 'includes/js/block-bindings-ui.js';
if ( ! file_exists( $js_file_path ) ) {
return;
}
// Enqueue the script only in the editor
wp_enqueue_script(
'bb-weather-bindings-ui',
plugin_dir_url( __FILE__ ) . 'includes/js/block-bindings-ui.js',
[ 'wp-blocks', 'wp-element', 'wp-dom-ready', 'wp-block-bindings' ],
filemtime( $js_file_path ),
true
);
}
add_action( 'enqueue_block_editor_assets', 'bb_enqueue_weather_bindings_ui' );
Here’s what this function does:
- First, it checks that the
register_block_bindings_source()function exists. - Next, it checks that the
block-bindings-ui.jsfile exists in the plugin’s/includes/jsfolder. - The
wp_enqueue_script()function enqueues the script for use in the editor. For a detailed description of the function, please refer to the documentation. - It uses the
enqueue_block_editor_assetshook to queue scripts for the editing interface.
Ora aprite il file block-bindings-ui.js e scrivete il seguente codice:
wp.blocks.registerBlockBindingsSource({
name: 'bb/weather-condition',
label: 'Weather Condition',
useContext: [ 'postId', 'postType' ],
getValues: ( { bindings } ) => {
if ( bindings.content?.args?.key === 'temperature' ) {
return {
content: 'Current temperature provided by Open-Meteo.',
};
}
if ( bindings.content?.args?.key === 'weather_state' ) {
return {
content: 'Current conditions.',
};
}
return {
content: bindings.content,
};
},
getFieldsList() {
return [
{ label: 'Temperature (°C)', type: 'string', args: { key: 'temperature' } },
{ label: 'Weather Conditions', type: 'string', args: { key: 'weather_state' } }
];
}
});
- The
registerBlockBindingsSource()function registers a binding source in the block editor. nameis a unique identifier for your binding source. It must match exactly the name used in PHP withregister_block_bindings_source().labelis a human-readable name displayed in the Source dropdown of the Attributes panel.useContextsets the context values this source needs from the block.postIdis required so that the source knows which post’s meta/weather data to read.getValuesprovides a preview of the bounded value inside the block editor. It returns the options that appear in the dropdown after the user selects the binding source (“Weather Condition” in our example). This method is available since WordPress 6.9.getFieldsListreturns the options that appear in the dropdown after the user selects the binding source (“Weather Conditions” in our example).
Save the file and return to the editor. Your Weather Conditions source is now available in the editor UI, alongside Post Meta. Reload the page, then connect a Paragraph or Header block to your binding source. The image below shows the result.

The final image shows the result on the website’s frontend.

What else can you do with the Block Bindings API?
This article only scratches the surface of what you can build with the Block Bindings API. The great thing is that the development of this powerful WordPress feature is far from over, and we can expect new implementations and additions in the future.
Integrating the Block Bindings API with other powerful WordPress APIs, such as the Interactivity API, allows you to build dynamic, interactive applications that extend well beyond the traditional blogging features that made WordPress popular in its early years.
WordPress is no longer just a blogging platform or a website builder. It is now set to become a multipurpose development platform for all types of web applications.
The more powerful your applications are, the more important your hosting service becomes. Kinsta offers Premium managed hosting with high performance, robust security, extensive automation, and top-notch support recognized as industry-leading by G2 users.
The most powerful web applications require the best hosting infrastructure. Take a look at Kinsta plans to find the one that best suits your site’s needs.