Home › Block and Plugin Tutorials › Block Editor › How to Generate a Block Manifest to Improve Block Performance
How to Generate a Block Manifest to Improve Block Performance
In WordPress 6.7, block manifests were introduced to improve overall block performance. This was iterated on in WordPress 6.8, making block registration much easier. In this tutorial, I’ll explain why block manifests are needed, and how to generate them.
What are block manifests?
Screenshot of a Block Manifest File
A block manifest is a file that contains all of the information about your blocks in PHP format. Think of it as one large file that contains all of your block.json data for every block registered.
In a normal operation, your block.json file is read and parsed numerous times in WordPress, which can hamper performance.
For each page load, the following operations are executed by WordPress:
- Scan folders for
block.jsonfiles. - When a
block.jsonfile is found, read its contents into memory. - Call
json_decodeon the file contents to convert it to a PHP array. - Register the block using the decoded data.
Source: Improve PHP Performance for Block Registration.
Block Manifests solve this problem by helping you register a group of blocks as a collection. Once registered, your block.json files are consolidated in a blocks-manifest.php file, which can be read in once as needed.
Since the file is in PHP format, it can be read in programmatically and parsed server-side, thus improving read/write and parsing performance.
Block manifests for single-block plugins
Should block manifests be used for single-block plugins? Yes, and no.
In principle there is, yes. The benefit is that it would still avoid parsing the `block.json` file via `json_decode()`, which is somewhat expensive.
For a single block the real performance impact is probably negligible, but when things add up (e.g. 20+ plugins with a single block), it’s still useful to use a block metadata collection even for plugins with a single block.
So certainly a best practice even in those cases.
WordPress Core Committer
In principle, if you have a single-block plugin, you don’t need block manifests, but it is a good idea to do so.
Generating a block manifest
Flowchart of Block Manifest Generation
To generate a block manifest, you’ll need to update your build tools slightly to use the latest version of @wordpress/scripts.
Let’s walk through how I would update my plugin WP Plugin Info Card, which has 4 blocks, to use block manifests for registration.
Using npx @wordpress/create-block
If generating a new block plugin using @wordpress/create-block, the plugin will already be set up to use block manifests.
Step 1: Update the @wordpress/scripts package
You’ll need to update your @wordpress/scripts package to version 30.20.0 or higher.
First, I’ll navigate to my plugin via command line and uninstall @wordpress/scripts.
npm uninstall @wordpress/scripts --legacy-peer-depsCode language: Bash (bash)Once that’s done, I’ll reinstall it using this command:
npm install @wordpress/scripts@^30.20.0 --save-dev --legacy-peer-depsCode language: Bash (bash)Step 2: Update your package.json to include manifests
Here’s how my build steps currently look in my package.json file.
"scripts": {
"start": "wp-scripts start wppic-blocks=./src/index.js --env mode=development",
"dev": "wp-scripts start wppic-blocks=./src/index.js --env mode=development",
"build": "wp-scripts build wppic-blocks=./src/index.js --env mode=production",
"zip": "wp-scripts plugin-zip"
},Code language: JSON / JSON with Comments (json)In order to generate the block manifest, I’ll add a --blocks-manifest flag into my package.json file.
"scripts": {
"start": "wp-scripts start wppic-blocks=./src/index.js --blocks-manifest --env mode=development",
"dev": "wp-scripts start wppic-blocks=./src/index.js --blocks-manifest --env mode=development",
"build": "wp-scripts build wppic-blocks=./src/index.js --blocks-manifest --env mode=production",
"zip": "wp-scripts plugin-zip"
},Code language: JSON / JSON with Comments (json)After that, I’ll test using npm run build to see if my block manifest file is generated.
Generated Blocks Manifest File
Now that the file is generated, I need to register the block collection.
Registering a block collection
To register blocks, you would normally use function register_block_type. Here’s an example from WP Plugin Info Card:
register_block_type(
Functions::get_plugin_dir( 'build/blocks/PluginInfoCard/block.json' ),
array(
'render_callback' => array( $this, 'info_card_render' ),
)
);
register_block_type(
Functions::get_plugin_dir( 'build/blocks/PluginInfoCardQuery/block.json' ),
array(
'render_callback' => array( $this, 'info_card_query_render' ),
)
);
register_block_type(
Functions::get_plugin_dir( 'build/blocks/SitePluginsCardGrid/block.json' ),
array(
'render_callback' => array( $this, 'site_plugin_card_grid_render' ),
)
);
register_block_type(
Functions::get_plugin_dir( 'build/blocks/PluginScreenshotsInfoCard/block.json' ),
array(
'render_callback' => array( $this, 'site_plugin_screenshots' ),
)
);Code language: PHP (php)To update this block, I’ll be using WP 6.7 function wp_register_block_metadata_collection and WP 6.8 function wp_register_block_types_from_metadata_collection.
In order to make this compatible with previous versions of WordPress, I’ll be adding a few conditionals and function checks.
if ( function_exists( 'wp_register_block_types_from_metadata_collection' ) ) {
wp_register_block_types_from_metadata_collection( Functions::get_plugin_dir( 'build' ), Functions::get_plugin_dir( 'build/blocks-manifest.php' ) );
return;
} else {
if ( function_exists( 'wp_register_block_metadata_collection' ) ) {
wp_register_block_metadata_collection( Functions::get_plugin_dir( 'build' ), Functions::get_plugin_dir( 'build/blocks-manifest.php' ) );
}
$manifest_data = require Functions::get_plugin_dir( 'build/blocks-manifest.php' );
foreach ( array_keys( $manifest_data ) as $block_type ) {
register_block_type( __DIR__ . "/build/{$block_type}" );
}
}Code language: PHP (php)- In the above example, the function wp_register_block_types_from_metadata_collection is called if the user is above WP 6.8. This function both registers the collection, and individual blocks. So in theory this is a one-and-done operation.
- If the user is on WP 6.7, the function wp_register_block_metadata_collection is called to register the collection. You’ll still need to register the blocks individually.
- Lastly, the blocks are registered individually (if on WP 6.7 or lower).
You may have noticed I’m using a static method to find my files and directories. This is detailed in an article I wrote about useful utility functions you can add to your plugin.
Dealing with dynamic blocks and render_callback
Using block.json and render.php
If you have a dynamic block and your block is already using render.php, you can skip this section.
If you have a dynamic block and use render_callback to output your block to the frontend, you’ll have to modify the registration arguments at run-time.
Function wp_register_block_types_from_metadata_collection both registers the collection and blocks, but it doesn’t provide a render_callback argument. This means if you’re using block-manifests with render_callback, your blocks will no longer display.
Here’s how to get render_callback back.
Using filter block_type_metadata_settings, we can modify the registration arguments for the block when it’s registered.
Here’s the full function when registering my dynamic blocks:
$render_callbacks = array(
'wp-plugin-info-card/wp-plugin-info-card' => array( $this, 'info_card_render' ),
'wp-plugin-info-card/wp-plugin-info-card-query' => array( $this, 'info_card_query_render' ),
'wp-plugin-info-card/site-plugin-card-grid' => array( $this, 'site_plugin_card_grid_render' ),
'wp-plugin-info-card/plugin-screenshots-info-card' => array( $this, 'site_plugin_screenshots' ),
);
add_filter(
'block_type_metadata_settings',
function ( $settings, $metadata ) use ( $render_callbacks ) {
if ( isset( $render_callbacks[ $metadata['name'] ] ) ) {
$settings['render_callback'] = $render_callbacks[ $metadata['name'] ];
}
return $settings;
},
10,
2
);
if ( function_exists( 'wp_register_block_types_from_metadata_collection' ) ) {
wp_register_block_types_from_metadata_collection( Functions::get_plugin_dir( 'build' ), Functions::get_plugin_dir( 'build/blocks-manifest.php' ) );
return;
} else {
if ( function_exists( 'wp_register_block_metadata_collection' ) ) {
wp_register_block_metadata_collection( Functions::get_plugin_dir( 'build' ), Functions::get_plugin_dir( 'build/blocks-manifest.php' ) );
}
$manifest_data = require Functions::get_plugin_dir( 'build/blocks-manifest.php' );
foreach ( array_keys( $manifest_data ) as $block_type ) {
register_block_type( __DIR__ . "/build/{$block_type}" );
}
}Code language: PHP (php)Here’s what’s going on:
- I created an array with my blocks and their callbacks.
- I used an inline filter declaration and modified the block settings to include my callbacks.
- Block registration proceeds as normal, with the filter hooking in during registration.
With this update, my blocks now render correctly on the frontend.
Conclusion
Block manifests increase performance by not having to parse and render numerous block.json files per plugin.
I explained how to update a block plugin to use block manifests and how to update your build scripts.
There are some caveats when registering the blocks, notably if using render_callback for dynamic blocks.
Like the tutorial you just read? There's more like it.
There's more where that came from. Enter your email and I'll send you more like it.








