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.phpOpen the block-bindings-example.php file in your favorite code editor and add the following code:
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:
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:
__( '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_2mThe 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:
Placeholder
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.jsAs 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.
Now open the block-bindings-ui.js file and write the following code:
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.
Source link

