From 7e694b3cfe0a39a4ed0a808910ac043b8d11ff02 Mon Sep 17 00:00:00 2001 From: Matthew Reishus Date: Mon, 11 Nov 2024 13:08:17 -0600 Subject: [PATCH] jetpack plugin: Add support for WordPress 6.7+'s block metadata collection registration (#40064) * WIP: Add wp_register_block_metadata_collection to the jetpack plugin * changelog * Ignore WP sniffs for a build script Co-authored-by: Brad Jorsch * Add new built file to gitignore to avoid committing and gitattributes to ensure it exists in built packages * fix some issues * fix directory constants, add comments * move register_block_metadata_collection * build_block_manifest: More error checking and comments * add unit test * add phan suppress comment * try to fix phan suppression * better changelog comment * change to _inc/blocks when registering * Update projects/plugins/jetpack/changelog/update-wp_register_block_metadata_collection Co-authored-by: Brad Jorsch * Update projects/plugins/jetpack/tools/build-block-manifest.php Co-authored-by: Brad Jorsch * Update projects/plugins/jetpack/tools/build-block-manifest.php Co-authored-by: Brad Jorsch * move to build-extensions step * fix comment * move to _inc path --------- Co-authored-by: Brandon Kraft Co-authored-by: Brad Jorsch --- ...date-wp_register_block_metadata_collection | 4 + .../jetpack/class.jetpack-gutenberg.php | 27 +++ projects/plugins/jetpack/class.jetpack.php | 1 + projects/plugins/jetpack/package.json | 2 +- .../jetpack/tests/php/test_block_manifest.php | 160 ++++++++++++++++++ .../jetpack/tools/build-block-manifest.php | 93 ++++++++++ 6 files changed, 286 insertions(+), 1 deletion(-) create mode 100644 projects/plugins/jetpack/changelog/update-wp_register_block_metadata_collection create mode 100644 projects/plugins/jetpack/tests/php/test_block_manifest.php create mode 100644 projects/plugins/jetpack/tools/build-block-manifest.php diff --git a/projects/plugins/jetpack/changelog/update-wp_register_block_metadata_collection b/projects/plugins/jetpack/changelog/update-wp_register_block_metadata_collection new file mode 100644 index 0000000000000..db899e5772c71 --- /dev/null +++ b/projects/plugins/jetpack/changelog/update-wp_register_block_metadata_collection @@ -0,0 +1,4 @@ +Significance: minor +Type: enhancement + +Use wp_register_block_metadata_collection() on WordPress 6.7+ to improve block registration performance by reducing filesystem operations. (See https://core.trac.wordpress.org/changeset/59132) diff --git a/projects/plugins/jetpack/class.jetpack-gutenberg.php b/projects/plugins/jetpack/class.jetpack-gutenberg.php index ae63251b82539..0ff7814e9ecef 100644 --- a/projects/plugins/jetpack/class.jetpack-gutenberg.php +++ b/projects/plugins/jetpack/class.jetpack-gutenberg.php @@ -1331,6 +1331,33 @@ public static function site_supports_next_default_size() { // Final fallback. return false; } + + /** + * Register block metadata collection for Jetpack blocks. + * This allows for more efficient block metadata loading by avoiding + * individual block.json file reads at runtime. + * + * Uses wp_register_block_metadata_collection() if available (WordPress 6.7+) + * and if the manifest file exists. The manifest file is auto-generated + * during the build process. + * + * Runs on plugins_loaded to ensure registration happens before individual + * blocks register themselves on init. + * + * @static + * @since $$next-version$$ + * @return void + */ + public static function register_block_metadata_collection() { + $meta_file_path = JETPACK__PLUGIN_DIR . '_inc/blocks/blocks-manifest.php'; + if ( function_exists( 'wp_register_block_metadata_collection' ) && file_exists( $meta_file_path ) ) { + // @phan-suppress-next-line PhanUndeclaredFunction -- New in WP 6.7. We're checking if it exists first. + wp_register_block_metadata_collection( + JETPACK__PLUGIN_DIR . '_inc/blocks/', + $meta_file_path + ); + } + } } if ( ( new Host() )->is_woa_site() ) { diff --git a/projects/plugins/jetpack/class.jetpack.php b/projects/plugins/jetpack/class.jetpack.php index b7209115e34a3..65c62210b5e7b 100644 --- a/projects/plugins/jetpack/class.jetpack.php +++ b/projects/plugins/jetpack/class.jetpack.php @@ -628,6 +628,7 @@ private function __construct() { require_once JETPACK__PLUGIN_DIR . 'class.jetpack-gutenberg.php'; add_action( 'plugins_loaded', array( 'Jetpack_Gutenberg', 'load_independent_blocks' ) ); add_action( 'plugins_loaded', array( 'Jetpack_Gutenberg', 'load_block_editor_extensions' ), 9 ); + add_action( 'plugins_loaded', array( 'Jetpack_Gutenberg', 'register_block_metadata_collection' ) ); /** * We've switched from enqueue_block_editor_assets to enqueue_block_assets in WP-Admin because the assets with the former are loaded on the main site-editor.php. * diff --git a/projects/plugins/jetpack/package.json b/projects/plugins/jetpack/package.json index b7cc6d514c5bf..359589e5f089f 100644 --- a/projects/plugins/jetpack/package.json +++ b/projects/plugins/jetpack/package.json @@ -19,7 +19,7 @@ "build-asset-cdn-json": "php tools/build-asset-cdn-json.php", "build-client": "concurrently --names js,css,module-headings 'webpack --config ./tools/webpack.config.js' 'webpack --config ./tools/webpack.config.css.js' 'php tools/build-module-headings-translations.php'", "build-concurrently": "pnpm run clean && concurrently 'pnpm:compile-ts' 'pnpm:build-client' 'pnpm:build-extensions' 'pnpm:build-widget-visibility' && pnpm run build-asset-cdn-json", - "build-extensions": "webpack --config ./tools/webpack.config.extensions.js && tools/check-block-assets.php", + "build-extensions": "webpack --config ./tools/webpack.config.extensions.js && tools/check-block-assets.php && php tools/build-block-manifest.php", "build-production": "pnpm run clean && pnpm run build-production-client && pnpm run build-production-extensions && pnpm run build-production-widget-visibility && pnpm run build-asset-cdn-json", "build-production-concurrently": "pnpm run clean && concurrently 'pnpm:compile-ts-production' 'pnpm:build-production-client' 'pnpm:build-production-extensions' 'pnpm:build-production-widget-visibility' && pnpm run build-asset-cdn-json", "build-production-client": "NODE_ENV=production BABEL_ENV=production pnpm run build-client && pnpm exec validate-es ./_inc/build/", diff --git a/projects/plugins/jetpack/tests/php/test_block_manifest.php b/projects/plugins/jetpack/tests/php/test_block_manifest.php new file mode 100644 index 0000000000000..8c023a6fe4b54 --- /dev/null +++ b/projects/plugins/jetpack/tests/php/test_block_manifest.php @@ -0,0 +1,160 @@ +test_dir = rtrim( sys_get_temp_dir(), '/\\' ) . '/jetpack-block-manifest-test-' . uniqid(); + mkdir( $this->test_dir, 0777, true ); + $this->cleanup_paths[] = $this->test_dir; + } + + /** + * Clean up after ourselves. + * + * @return void + */ + public function tear_down() { + // Remove files first, then directories in reverse order. + foreach ( array_reverse( $this->cleanup_paths ) as $path ) { + if ( is_file( $path ) ) { + unlink( $path ); + } elseif ( is_dir( $path ) ) { + rmdir( $path ); + } + } + parent::tear_down(); + } + + /** + * Test that the script fails properly when directory doesn't exist. + * + * @return void + */ + public function test_nonexistent_directory() { + $this->expectException( Exception::class ); + $this->expectExceptionMessage( 'Input directory does not exist: /path/does/not/exist' ); + build_block_manifest( '/path/does/not/exist' ); + } + + /** + * Test that the script handles empty directories correctly. + * + * @return void + */ + public function test_empty_directory() { + $this->expectException( Exception::class ); + $this->expectExceptionMessage( "No block.json files found in: {$this->test_dir}" ); + build_block_manifest( $this->test_dir ); + } + + /** + * Test invalid JSON handling. + * + * @return void + */ + public function test_invalid_json() { + // Create test directory and file. + $block_dir = $this->test_dir . '/invalid-block'; + mkdir( $block_dir ); + $this->cleanup_paths[] = $block_dir; + + $json_file = $block_dir . '/block.json'; + file_put_contents( $json_file, '{invalid json}' ); + $this->cleanup_paths[] = $json_file; + + $this->expectException( Exception::class ); + $this->expectExceptionMessage( 'No valid block.json files were processed' ); + build_block_manifest( $this->test_dir ); + } + + /** + * Test successful manifest generation. + * + * @return void + */ + public function test_successful_manifest_generation() { + // Create test directories and files. + $block1_dir = $this->test_dir . '/block1'; + mkdir( $block1_dir ); + $this->cleanup_paths[] = $block1_dir; + + $block1_json = $block1_dir . '/block.json'; + file_put_contents( + $block1_json, + wp_json_encode( + array( + 'name' => 'test/block1', + 'title' => 'Test Block 1', + ) + ) + ); + $this->cleanup_paths[] = $block1_json; + + $block2_dir = $this->test_dir . '/block2'; + mkdir( $block2_dir ); + $this->cleanup_paths[] = $block2_dir; + + $block2_json = $block2_dir . '/block.json'; + file_put_contents( + $block2_json, + wp_json_encode( + array( + 'name' => 'test/block2', + 'title' => 'Test Block 2', + ) + ) + ); + $this->cleanup_paths[] = $block2_json; + + // Generate manifest. + $result = build_block_manifest( $this->test_dir ); + $this->assertTrue( $result ); + + // Track manifest file for cleanup. + $manifest_path = $this->test_dir . '/blocks-manifest.php'; + $this->cleanup_paths[] = $manifest_path; + + // Verify the manifest was created and contains expected data. + $this->assertFileExists( $manifest_path ); + + // Include and check manifest content. + $manifest = include $manifest_path; + $this->assertIsArray( $manifest ); + $this->assertArrayHasKey( 'block1', $manifest ); + $this->assertArrayHasKey( 'block2', $manifest ); + $this->assertEquals( 'Test Block 1', $manifest['block1']['title'] ); + $this->assertEquals( 'Test Block 2', $manifest['block2']['title'] ); + } +} diff --git a/projects/plugins/jetpack/tools/build-block-manifest.php b/projects/plugins/jetpack/tools/build-block-manifest.php new file mode 100644 index 0000000000000..b9e25758c9aed --- /dev/null +++ b/projects/plugins/jetpack/tools/build-block-manifest.php @@ -0,0 +1,93 @@ +