Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions .changeset/block-metadata-manifest.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
---
"10up-toolkit": minor
---

Add WordPress Block Metadata Collections API support

Integrate automatic generation of block metadata manifest files to improve block registration performance in WordPress 6.7+. When enabled, toolkit generates a PHP file (`blocks-manifest.php`) containing all block metadata from a single source, eliminating the need to read multiple `block.json` files at runtime.

**New Features:**
- Add `useBlockManifest` configuration option (boolean, default: `false`)
- Add `--block-manifest` CLI flag for one-time manifest generation
- Add `BuildBlocksManifestPlugin` webpack plugin that hooks into build completion
- Automatic manifest regeneration in watch mode when blocks change

**Configuration:**

Enable via package.json:
```json
{
"10up-toolkit": {
"useBlockAssets": true,
"useBlockManifest": true
}
}
```

Or via CLI flag:
```bash
10up-toolkit build --block-manifest
10up-toolkit start --block-manifest
10up-toolkit watch --block-manifest
```

**WordPress Integration:**

Register the collection and automatically register all blocks:
```php
$blocks_dir = get_template_directory() . '/dist/blocks';
$manifest_path = get_template_directory() . '/dist/blocks-manifest.php';

wp_register_block_metadata_collection( $blocks_dir, $manifest_path );

// Automatically register all blocks from the manifest
$manifest = require $manifest_path;
foreach ( array_keys( $manifest ) as $block_dir ) {
register_block_type_from_metadata( $blocks_dir . '/' . $block_dir );
}
```

**Benefits:**
- Improved performance for projects with many blocks (50+)
- Reduced filesystem I/O operations
- Better opcode caching for block metadata
- Preserves transformed asset paths from the build process (TS→JS, SCSS→CSS)

The manifest is generated in `dist/blocks-manifest.php` and works seamlessly with the existing `useBlockAssets` workflow.
28 changes: 1 addition & 27 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

127 changes: 127 additions & 0 deletions packages/toolkit/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,106 @@ Since 10up-toolkit@6 this mode is on by default. To opt out of this mode you nee

By default, the source directory for blocks is `./includes/blocks/`. This can be customized via the `blocksDir` key in the paths' config.

### WordPress Block Metadata Collections

WordPress 6.7 introduced the [Block Metadata Collections API](https://make.wordpress.org/core/2024/10/17/new-block-type-registration-apis-to-improve-performance-in-wordpress-6-7/), which significantly improves block registration performance by reading metadata from a single PHP manifest file instead of multiple `block.json` files.
Comment thread
fabiankaegy marked this conversation as resolved.

10up-toolkit can automatically generate this manifest file during the build process. When enabled, it scans all built blocks in `dist/blocks/` and creates a `blocks-manifest.php` file containing all block metadata.

#### Enabling Block Manifest Generation

Enable via package.json configuration (always generates manifest):

```json
{
"10up-toolkit": {
"useBlockAssets": true,
"useBlockManifest": true
}
}
```

Or use the CLI flag for one-time generation:

```bash
10up-toolkit build --block-manifest
10up-toolkit start --block-manifest
10up-toolkit watch --block-manifest
```

#### WordPress Integration

Once the manifest is generated, register the collection and your block types. Add this to your theme's `functions.php` or plugin entry point.

**Recommended approach (automatic registration):**

```php
// Register the block metadata collection
$blocks_dir = get_template_directory() . '/dist/blocks';
$manifest_path = get_template_directory() . '/dist/blocks-manifest.php';

wp_register_block_metadata_collection( $blocks_dir, $manifest_path );

// Automatically register all blocks from the manifest
$manifest = require $manifest_path;
foreach ( array_keys( $manifest ) as $block_dir ) {
register_block_type_from_metadata( $blocks_dir . '/' . $block_dir );
}
```

**For plugins:**

```php
// Register the block metadata collection
$blocks_dir = plugin_dir_path( __FILE__ ) . 'dist/blocks';
$manifest_path = plugin_dir_path( __FILE__ ) . 'dist/blocks-manifest.php';

wp_register_block_metadata_collection( $blocks_dir, $manifest_path );

// Automatically register all blocks from the manifest
$manifest = require $manifest_path;
foreach ( array_keys( $manifest ) as $block_dir ) {
register_block_type_from_metadata( $blocks_dir . '/' . $block_dir );
}
```

**Manual registration (if you need more control):**

```php
wp_register_block_metadata_collection(
get_template_directory() . '/dist/blocks',
get_template_directory() . '/dist/blocks-manifest.php'
);

// Register specific blocks only
register_block_type_from_metadata( get_template_directory() . '/dist/blocks/example-block' );
register_block_type_from_metadata( get_template_directory() . '/dist/blocks/another-block' );
```
Comment thread
fabiankaegy marked this conversation as resolved.

The `wp_register_block_metadata_collection()` function tells WordPress about the manifest file. WordPress will then use the manifest data when you register individual block types with `register_block_type_from_metadata()`, avoiding the need to read each `block.json` file separately. The automatic registration approach loops through all blocks in the manifest, making it easier to maintain as you add or remove blocks.

#### How It Works

The manifest generation integrates seamlessly with the existing build pipeline:

1. Webpack builds and compiles all blocks (TypeScript, SCSS, etc.)
2. CopyWebpackPlugin copies `block.json` files to `dist/blocks/` and transforms asset paths (`.ts` → `.js`, `.scss` → `.css`) via the existing `transformBlockJson` utility
3. BuildBlocksManifestPlugin scans `dist/blocks/` for all transformed `block.json` files
4. Generates `dist/blocks-manifest.php` containing all block metadata with the already-transformed asset paths

In watch mode, the manifest automatically regenerates whenever block files change, preserving any path transformations from the build process.

#### Performance Benefits

The Block Metadata Collections API provides significant performance improvements:

- Reduced filesystem I/O operations
- Better opcode caching for block metadata
- Single file read instead of multiple `block.json` files
- Particularly beneficial for projects with 50+ blocks

The manifest file structure matches WordPress's expectations, with block identifiers (directory names) as keys and complete block metadata as values.

### WordPress Script Module Handling

Since WordPress 6.5 ESM scripts are now officially supported. In fact, they are required in order to use some new features such as the Interactivity API. In WordPress these script modules need to coexist with commonJs scripts though. So it's not as easy as just switching the entire toolkit mode to output ESM instead of commonJS.
Expand Down Expand Up @@ -784,6 +884,33 @@ Alternatively, you can set this up in `package.json`.

It only works with the build command, after finishing the build a new window will be automatically opened with the report.

### Block Manifest

> This option was added in 10up-toolkit v6.6.

The `--block-manifest` flag enables generation of a PHP manifest file for WordPress's Block Metadata Collections API (WordPress 6.7+). This improves block registration performance by consolidating all block metadata into a single file.

```bash
10up-toolkit build --block-manifest
10up-toolkit start --block-manifest
10up-toolkit watch --block-manifest
```

When enabled, toolkit generates `dist/blocks-manifest.php` containing all block metadata. In watch mode, the manifest regenerates automatically when block files change.

Alternatively, enable permanently in `package.json`:

```json
{
"10up-toolkit": {
"useBlockAssets": true,
"useBlockManifest": true
}
}
```

See the [WordPress Block Metadata Collections](#wordpress-block-metadata-collections) section for usage details.

### Source and Output

To set the source and main/output path via the CLI you can use the `-i` and `-o` (or `--input` and `--output` options)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"title": "Example Block One",
"description": "First example block",
"textdomain": "test-blocks",
"name": "test/example-one",
"icon": "feedback",
"category": "test-blocks",
"attributes": {
"content": {
"type": "string"
}
},
"supports": {
"align": false,
"html": false
},
"editorScript": "file:./index.js",
"editorStyle": "file:./editor.css",
"style": "file:./style.css"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.wp-block-test-example-one {
color: blue;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/* eslint-disable import/no-unresolved */
import { registerBlockType } from '@wordpress/blocks';

registerBlockType('test/example-one', {
edit: () => 'Example One',
save: () => 'Example One',
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.wp-block-test-example-one {
margin: 1em;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"title": "Example Block Three",
"description": "Third example block with TypeScript",
"textdomain": "test-blocks",
"name": "test/example-three",
"icon": "admin-tools",
"category": "test-blocks",
"editorScript": "file:./index.ts",
"style": "file:./style.scss"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/* eslint-disable import/no-unresolved */
import { registerBlockType } from '@wordpress/blocks';

registerBlockType('test/example-three', {
edit: () => 'Example Three',
save: () => 'Example Three',
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.wp-block-test-example-three {
$spacing: 2em;
padding: $spacing;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"title": "Example Block Two",
"description": "Second example block",
"textdomain": "test-blocks",
"name": "test/example-two",
"icon": "star-filled",
"category": "test-blocks",
"attributes": {
"message": {
"type": "string",
"default": "Hello"
}
},
"supports": {
"align": true,
"html": false
},
"editorScript": "file:./index.js",
"viewScript": "file:./view.js"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/* eslint-disable import/no-unresolved */
import { registerBlockType } from '@wordpress/blocks';

registerBlockType('test/example-two', {
edit: () => 'Example Two',
save: () => 'Example Two',
});
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
console.log('Example Two view script');
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "test-build-project-block-manifest",
"10up-toolkit": {
"useBlockAssets": true,
"useBlockManifest": true,
"paths": {
"blocksDir": "./__fixtures__/includes/blocks"
}
}
}
Loading
Loading