Ticket #62002: add-metadata-registry.diff
File add-metadata-registry.diff, 11.4 KB (added by , 5 months ago) |
---|
-
src/wp-includes/blocks.php
diff --git a/src/wp-includes/blocks.php b/src/wp-includes/blocks.php index 9b24b989d4..b97a1e18ab 100644
a b function get_block_metadata_i18n_schema() { 375 375 return $i18n_block_schema; 376 376 } 377 377 378 /** 379 * Registers block metadata from a given source. 380 * 381 * This function allows core and third-party plugins to register their block metadata 382 * in a centralized location. Registering metadata can improve performance by avoiding 383 * multiple reads from the filesystem. 384 * 385 * @since 6.X.0 386 * 387 * @param string $namespace The namespace for the metadata (e.g., 'core', 'mythirdpartyplugin'). 388 * @param string $source The source identifier for the metadata within the namespace. 389 * This can be a unique identifier for your plugin's blocks. 390 * @param array $metadata The block metadata to be registered. 391 */ 392 function wp_register_block_metadata( $namespace, $source, $metadata ) { 393 WP_Block_Metadata_Registry::get_instance()->register( $namespace, $source, $metadata ); 394 } 395 378 396 /** 379 397 * Registers a block type from the metadata stored in the `block.json` file. 380 398 * … … function get_block_metadata_i18n_schema() { 393 411 * @param array $args Optional. Array of block type arguments. Accepts any public property 394 412 * of `WP_Block_Type`. See WP_Block_Type::__construct() for information 395 413 * on accepted arguments. Default empty array. 414 * @param string $metadata_source Optional. The source identifier for the metadata in the format `namespace/source`. 415 * The namespace is a unique identifier for your plugin or theme, and the source 416 * is a unique identifier for your block's metadata within that namespace. 417 * If provided, the function will attempt to retrieve the block's metadata 418 * from the `WP_Block_Metadata_Registry` before falling back to reading 419 * from the JSON file. Default empty string. 396 420 * @return WP_Block_Type|false The registered block type on success, or false on failure. 397 421 */ 398 function register_block_type_from_metadata( $file_or_folder, $args = array() ) { 399 /* 400 * Get an array of metadata from a PHP file. 401 * This improves performance for core blocks as it's only necessary to read a single PHP file 402 * instead of reading a JSON file per-block, and then decoding from JSON to PHP. 403 * Using a static variable ensures that the metadata is only read once per request. 404 */ 405 static $core_blocks_meta; 406 if ( ! $core_blocks_meta ) { 407 $core_blocks_meta = require ABSPATH . WPINC . '/blocks/blocks-json.php'; 408 } 409 410 $metadata_file = ( ! str_ends_with( $file_or_folder, 'block.json' ) ) ? 411 trailingslashit( $file_or_folder ) . 'block.json' : 412 $file_or_folder; 422 function register_block_type_from_metadata( $file_or_folder, $args = array(), $metadata_source = '' ) { 423 $metadata = array(); 424 $registry = WP_Block_Metadata_Registry::get_instance(); 413 425 414 426 $is_core_block = str_starts_with( $file_or_folder, ABSPATH . WPINC ); 415 // If the block is not a core block, the metadata file must exist.416 $metadata_file_exists = $is_core_block || file_exists( $metadata_file );417 if ( ! $metadata_file_exists && empty( $args['name'] ) ) {418 return false;419 }420 427 421 // Try to get metadata from the static cache for core blocks.422 $metadata = array();423 428 if ( $is_core_block ) { 424 429 $core_block_name = str_replace( ABSPATH . WPINC . '/blocks/', '', $file_or_folder ); 425 if ( ! empty( $core_blocks_meta[ $core_block_name ] ) ) { 426 $metadata = $core_blocks_meta[ $core_block_name ]; 430 $metadata = $registry->get_metadata( 'core', $core_block_name ); 431 432 if ( null === $metadata ) { 433 // Load core metadata if not already registered. 434 $core_blocks_meta = require ABSPATH . WPINC . '/blocks/blocks-json.php'; 435 foreach ( $core_blocks_meta as $block_name => $block_meta ) { 436 wp_register_block_metadata( 'core', $block_name, $block_meta ); 437 } 438 $metadata = $registry->get_metadata( 'core', $core_block_name ); 439 } 440 } elseif ( $metadata_source ) { 441 // Parse the metadata_source to get namespace and source 442 $parts = explode( '/', $metadata_source, 2 ); 443 if ( count( $parts ) === 2 ) { 444 $namespace = $parts[0]; 445 $source = $parts[1]; 446 $metadata = $registry->get_metadata( $namespace, $source ); 427 447 } 428 448 } 429 449 430 // If metadata is not found in the static cache, read it from the file. 431 if ( $metadata_file_exists && empty( $metadata ) ) { 432 $metadata = wp_json_file_decode( $metadata_file, array( 'associative' => true ) ); 450 // If metadata is not found in the registry, read from JSON file. 451 $metadata_file_exists = false; 452 if ( empty( $metadata ) ) { 453 $metadata_file = ( ! str_ends_with( $file_or_folder, 'block.json' ) ) ? 454 trailingslashit( $file_or_folder ) . 'block.json' : 455 $file_or_folder; 456 457 $metadata_file_exists = file_exists( $metadata_file ); 458 if ( $metadata_file_exists ) { 459 $metadata = wp_json_file_decode( $metadata_file, array( 'associative' => true ) ); 460 } else if ( ! $metadata_file_exists && empty( $args['name'] ) ) { 461 return false; 462 } 433 463 } 434 464 435 465 if ( ! is_array( $metadata ) || ( empty( $metadata['name'] ) && empty( $args['name'] ) ) ) { -
new file src/wp-includes/class-wp-block-metadata-registry.php
diff --git a/src/wp-includes/class-wp-block-metadata-registry.php b/src/wp-includes/class-wp-block-metadata-registry.php new file mode 100644 index 0000000000..a11ca34764
- + 1 <?php 2 /** 3 * Block Metadata Registry 4 * 5 * @package WordPress 6 * @subpackage Blocks 7 * @since 6.X.0 8 */ 9 10 /** 11 * Class used for managing block metadata from various sources. 12 * 13 * @since 6.X.0 14 */ 15 class WP_Block_Metadata_Registry { 16 17 /** 18 * Holds the instance of this class. 19 * 20 * @since 6.X.0 21 * @var WP_Block_Metadata_Registry 22 */ 23 private static $instance; 24 25 /** 26 * Container for storing block metadata. 27 * 28 * @since 6.X.0 29 * @var array 30 */ 31 private $metadata = array(); 32 33 /** 34 * Registers block metadata for a given source and namespace. 35 * 36 * @since 6.X.0 37 * 38 * @param string $namespace The namespace for the metadata (e.g., 'core', 'mythirdpartyplugin'). 39 * @param string $source The source identifier for the metadata within the namespace. 40 * @param array $metadata The block metadata. 41 */ 42 public function register( $namespace, $source, $metadata ) { 43 if ( ! isset( $this->metadata[ $namespace ] ) ) { 44 $this->metadata[ $namespace ] = array(); 45 } 46 $this->metadata[ $namespace ][ $source ] = $metadata; 47 } 48 49 /** 50 * Retrieves block metadata for a given namespace and source. 51 * 52 * @since 6.X.0 53 * 54 * @param string $namespace The namespace for the metadata. 55 * @param string $source The source identifier for the metadata within the namespace. 56 * @return array|null The block metadata for the source, or null if not found. 57 */ 58 public function get_metadata( $namespace, $source ) { 59 return isset( $this->metadata[ $namespace ][ $source ] ) ? $this->metadata[ $namespace ][ $source ] : null; 60 } 61 62 /** 63 * Retrieves the instance of this class. 64 * 65 * @since 6.X.0 66 * 67 * @return WP_Block_Metadata_Registry The instance. 68 */ 69 public static function get_instance() { 70 if ( null === self::$instance ) { 71 self::$instance = new self(); 72 } 73 return self::$instance; 74 } 75 } -
src/wp-settings.php
diff --git a/src/wp-settings.php b/src/wp-settings.php index d3dfe5776e..a152dd3f4f 100644
a b require ABSPATH . WPINC . '/class-wp-block-styles-registry.php'; 353 353 require ABSPATH . WPINC . '/class-wp-block-type-registry.php'; 354 354 require ABSPATH . WPINC . '/class-wp-block.php'; 355 355 require ABSPATH . WPINC . '/class-wp-block-list.php'; 356 require ABSPATH . WPINC . '/class-wp-block-metadata-registry.php'; 356 357 require ABSPATH . WPINC . '/class-wp-block-parser-block.php'; 357 358 require ABSPATH . WPINC . '/class-wp-block-parser-frame.php'; 358 359 require ABSPATH . WPINC . '/class-wp-block-parser.php'; -
tests/phpunit/tests/blocks/register.php
diff --git a/tests/phpunit/tests/blocks/register.php b/tests/phpunit/tests/blocks/register.php index 7e0c391e1f..770470ea0c 100644
a b class Tests_Blocks_Register extends WP_UnitTestCase { 1501 1501 $block_type->block_hooks 1502 1502 ); 1503 1503 } 1504 1505 /** 1506 * Tests registering a third-party block type using metadata from the registry. 1507 * 1508 * This test ensures that a block type can be registered using metadata stored 1509 * in the `WP_Block_Metadata_Registry` by providing a `$metadata_source` argument. 1510 * 1511 * @covers ::register_block_type_from_metadata 1512 */ 1513 public function test_register_block_type_from_registry_metadata() { 1514 $metadata = array( 1515 'name' => 'test/block-from-registry', 1516 'title' => 'Test Block From Registry', 1517 'category' => 'widgets', 1518 'icon' => 'smiley', 1519 'description' => 'This is a test block.', 1520 ); 1521 1522 $registry = WP_Block_Metadata_Registry::get_instance(); 1523 $registry->register( 'test', 'block-from-registry', $metadata ); 1524 1525 $result = register_block_type_from_metadata( 'nonexistent/path', array(), 'test/block-from-registry' ); 1526 1527 $this->assertInstanceOf( 'WP_Block_Type', $result ); 1528 $this->assertEquals( 'test/block-from-registry', $result->name ); 1529 } 1530 1531 /** 1532 * Tests registering a block type from a `block.json` file. 1533 * 1534 * This test ensures that `register_block_type_from_metadata()` can still register 1535 * a block type using metadata from a `block.json` file when no `$metadata_source` 1536 * argument is provided. 1537 * 1538 * @covers ::register_block_type_from_metadata 1539 */ 1540 public function test_register_block_type_from_json_file() { 1541 $temp_dir = get_temp_dir(); 1542 $block_json = $temp_dir . 'block.json'; 1543 file_put_contents( $block_json, json_encode( array( 1544 'name' => 'test/json-block', 1545 'title' => 'Test JSON Block', 1546 ) ) ); 1547 1548 $result = register_block_type_from_metadata( $temp_dir ); 1549 1550 $this->assertInstanceOf( 'WP_Block_Type', $result ); 1551 $this->assertEquals( 'test/json-block', $result->name ); 1552 1553 unlink( $block_json ); 1554 } 1504 1555 } -
new file tests/phpunit/tests/blocks/wpBlockMetadataRegistry.php
diff --git a/tests/phpunit/tests/blocks/wpBlockMetadataRegistry.php b/tests/phpunit/tests/blocks/wpBlockMetadataRegistry.php new file mode 100644 index 0000000000..7cac9c6803
- + 1 <?php 2 3 /** 4 * Tests for WP_Block_Metadata_Registry class. 5 * 6 * @group blocks 7 */ 8 class Tests_Blocks_WpBlockMetadataRegistry extends WP_UnitTestCase { 9 /** 10 * @var WP_Block_Metadata_Registry 11 */ 12 private $registry; 13 14 public function set_up() { 15 parent::set_up(); 16 $this->registry = WP_Block_Metadata_Registry::get_instance(); 17 } 18 19 public function test_register_and_get_metadata() { 20 $namespace = 'test-namespace'; 21 $source = 'test-source'; 22 $metadata = array( 'name' => 'test-block', 'title' => 'Test Block' ); 23 24 $this->registry->register( $namespace, $source, $metadata ); 25 26 $retrieved_metadata = $this->registry->get_metadata( $namespace, $source ); 27 $this->assertEquals( $metadata, $retrieved_metadata ); 28 } 29 30 public function test_get_nonexistent_metadata() { 31 $retrieved_metadata = $this->registry->get_metadata( 'nonexistent', 'nonexistent' ); 32 $this->assertNull( $retrieved_metadata ); 33 } 34 35 public function test_singleton_instance() { 36 $instance1 = WP_Block_Metadata_Registry::get_instance(); 37 $instance2 = WP_Block_Metadata_Registry::get_instance(); 38 39 $this->assertSame( $instance1, $instance2 ); 40 } 41 }