Make WordPress Core

Ticket #62002: add-metadata-registry-v3.diff

File add-metadata-registry-v3.diff, 12.7 KB (added by mreishus, 5 months ago)
  • src/wp-includes/blocks.php

    diff --git a/src/wp-includes/blocks.php b/src/wp-includes/blocks.php
    index 1a8f3459c5..7a66781974 100644
    a b function get_block_metadata_i18n_schema() { 
    375375        return $i18n_block_schema;
    376376}
    377377
     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 $source    The source identifier for the metadata within the namespace.
     388 *                          This can be a unique identifier for your plugin's blocks.
     389 * @param array  $metadata  The block metadata to be registered.
     390 */
     391function wp_register_block_metadata( $source, $metadata ) {
     392        WP_Block_Metadata_Registry::register( $source, $metadata );
     393}
     394
    378395/**
    379396 * Registers a block type from the metadata stored in the `block.json` file.
    380397 *
    function get_block_metadata_i18n_schema() { 
    387404 * @since 6.5.0 Added support for `allowedBlocks`, `viewScriptModule`, and `viewStyle` fields.
    388405 * @since 6.7.0 Allow PHP filename as `variations` argument.
    389406 *
    390  * @param string $file_or_folder Path to the JSON file with metadata definition for
     407 * @param string $file_or_metadata_source Path to the JSON file with metadata definition for
    391408 *                               the block or path to the folder where the `block.json` file is located.
    392409 *                               If providing the path to a JSON file, the filename must end with `block.json`.
     410 *                               Alternatively, it can be a metadata source identifier
     411 *                               (previously registered with `wp_register_block_metadata`).
    393412 * @param array  $args           Optional. Array of block type arguments. Accepts any public property
    394413 *                               of `WP_Block_Type`. See WP_Block_Type::__construct() for information
    395414 *                               on accepted arguments. Default empty array.
    396415 * @return WP_Block_Type|false The registered block type on success, or false on failure.
    397416 */
    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;
     417function register_block_type_from_metadata( $file_or_metadata_source, $args = array() ) {
     418        $metadata = array();
    413419
    414         $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;
     420        // Determine if we're dealing with a file/folder or a metadata source
     421        if ( WP_Block_Metadata_Registry::has_metadata( $file_or_metadata_source ) ) {
     422                $metadata_source = $file_or_metadata_source;
     423                $file_or_folder = null;
     424        } else {
     425                $metadata_source = null;
     426                $file_or_folder = $file_or_metadata_source;
    419427        }
    420428
    421         // Try to get metadata from the static cache for core blocks.
    422         $metadata = array();
     429        $is_core_block = $file_or_folder && str_starts_with( $file_or_folder, ABSPATH . WPINC );
     430
    423431        if ( $is_core_block ) {
    424                 $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 ];
     432                $core_block_name = 'core/' . str_replace( ABSPATH . WPINC . '/blocks/', '', $file_or_folder );
     433                $metadata = WP_Block_Metadata_Registry::get_metadata( $core_block_name );
     434
     435                if ( null === $metadata ) {
     436                        // Load core metadata if not already registered.
     437                        $core_blocks_meta = require ABSPATH . WPINC . '/blocks/blocks-json.php';
     438                        foreach ( $core_blocks_meta as $block_name => $block_meta ) {
     439                                $block_name = 'core/' . $block_name;
     440                                wp_register_block_metadata( $block_name, $block_meta );
     441                        }
     442                        $metadata = WP_Block_Metadata_Registry::get_metadata( $core_block_name );
    427443                }
     444        } elseif ( $metadata_source ) {
     445                $metadata = WP_Block_Metadata_Registry::get_metadata( $metadata_source );
    428446        }
    429447
    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 ) );
     448        // If metadata is not found in the registry, read from JSON file.
     449        $metadata_file_exists = false;
     450        if ( empty( $metadata ) && $file_or_folder ) {
     451                $metadata_file = ( ! str_ends_with( $file_or_folder, 'block.json' ) ) ?
     452                        trailingslashit( $file_or_folder ) . 'block.json' :
     453                        $file_or_folder;
     454
     455                $metadata_file_exists = file_exists( $metadata_file );
     456                if ( $metadata_file_exists ) {
     457                        $metadata = wp_json_file_decode( $metadata_file, array( 'associative' => true ) );
     458                } else if ( ! $metadata_file_exists && empty( $args['name'] ) ) {
     459                        return false;
     460                }
    433461        }
    434462
    435463        if ( ! is_array( $metadata ) || ( empty( $metadata['name'] ) && empty( $args['name'] ) ) ) {
    function register_block_type_from_metadata( $file_or_folder, $args = array() ) { 
    716744 *
    717745 * @since 5.0.0
    718746 * @since 5.8.0 First parameter now accepts a path to the `block.json` file.
     747 * @since x.x.x First parameter now also accepts a metadata source identifier.
    719748 *
    720749 * @param string|WP_Block_Type $block_type Block type name including namespace, or alternatively
    721750 *                                         a path to the JSON file with metadata definition for the block,
    722751 *                                         or a path to the folder where the `block.json` file is located,
     752 *                                         or a metadata source identifier (previously registered with
     753 *                                         `wp_register_block_metadata`),
    723754 *                                         or a complete WP_Block_Type instance.
    724755 *                                         In case a WP_Block_Type is provided, the $args parameter will be ignored.
    725756 * @param array                $args       Optional. Array of block type arguments. Accepts any public property
    function register_block_type_from_metadata( $file_or_folder, $args = array() ) { 
    729760 * @return WP_Block_Type|false The registered block type on success, or false on failure.
    730761 */
    731762function register_block_type( $block_type, $args = array() ) {
    732         if ( is_string( $block_type ) && file_exists( $block_type ) ) {
     763        $passed_metadata_source = false;
     764        if ( WP_Block_Metadata_Registry::has_metadata( $block_type ) && ( empty( $args ) || is_array( $args ) ) ) {
     765                $passed_metadata_source = true;
     766        }
     767
     768        if ( is_string( $block_type ) &&
     769                 ( $passed_metadata_source || file_exists( $block_type ) ) ) {
    733770                return register_block_type_from_metadata( $block_type, $args );
    734771        }
    735772
  • 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..5a3a4cb335
    - +  
     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 */
     15class WP_Block_Metadata_Registry {
     16
     17        /**
     18         * Container for storing block metadata.
     19         *
     20         * @since 6.X.0
     21         * @var array
     22         */
     23        private static $metadata = array();
     24
     25        /**
     26         * Registers block metadata for a given source.
     27         *
     28         * @since 6.X.0
     29         *
     30         * @param string $source   The source identifier for the metadata.
     31         * @param array  $metadata The block metadata.
     32         */
     33        public static function register( $source, $metadata ) {
     34                self::$metadata[ $source ] = $metadata;
     35        }
     36
     37        /**
     38         * Retrieves block metadata for a given source.
     39         *
     40         * @since 6.X.0
     41         *
     42         * @param string $source The source identifier for the metadata.
     43         * @return array|null    The block metadata for the source, or null if not found.
     44         */
     45        public static function get_metadata( $source ) {
     46                return isset( self::$metadata[ $source ] ) ? self::$metadata[ $source ] : null;
     47        }
     48
     49        /**
     50         * Checks if metadata exists for a given source.
     51         *
     52         * @since 6.X.0
     53         *
     54         * @param string $source The source identifier for the metadata.
     55         * @return bool          True if metadata exists for the source, false otherwise.
     56         */
     57        public static function has_metadata( $source ) {
     58                return isset( self::$metadata[ $source ] );
     59        }
     60
     61        /**
     62         * Private constructor to prevent instantiation.
     63         */
     64        private function __construct() {
     65                // Prevent instantiation
     66        }
     67}
  • 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'; 
    353353require ABSPATH . WPINC . '/class-wp-block-type-registry.php';
    354354require ABSPATH . WPINC . '/class-wp-block.php';
    355355require ABSPATH . WPINC . '/class-wp-block-list.php';
     356require ABSPATH . WPINC . '/class-wp-block-metadata-registry.php';
    356357require ABSPATH . WPINC . '/class-wp-block-parser-block.php';
    357358require ABSPATH . WPINC . '/class-wp-block-parser-frame.php';
    358359require 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..f371eca6cd 100644
    a b class Tests_Blocks_Register extends WP_UnitTestCase { 
    15011501                        $block_type->block_hooks
    15021502                );
    15031503        }
     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                WP_Block_Metadata_Registry::register( 'test/block-from-registry', $metadata );
     1523
     1524                $result = register_block_type_from_metadata( 'test/block-from-registry', array() );
     1525
     1526                $this->assertInstanceOf( 'WP_Block_Type', $result );
     1527                $this->assertEquals( 'test/block-from-registry', $result->name );
     1528        }
     1529
     1530        /**
     1531         * Tests registering a block type from a `block.json` file.
     1532         *
     1533         * This test ensures that `register_block_type_from_metadata()` can still register
     1534         * a block type using metadata from a `block.json` file when no `$metadata_source`
     1535         * argument is provided.
     1536         *
     1537         * @covers ::register_block_type_from_metadata
     1538         */
     1539        public function test_register_block_type_from_json_file() {
     1540                $temp_dir   = get_temp_dir();
     1541                $block_json = $temp_dir . 'block.json';
     1542                file_put_contents(
     1543                        $block_json,
     1544                        json_encode(
     1545                                array(
     1546                                        'name'  => 'test/json-block',
     1547                                        'title' => 'Test JSON Block',
     1548                                )
     1549                        )
     1550                );
     1551
     1552                $result = register_block_type_from_metadata( $temp_dir );
     1553
     1554                $this->assertInstanceOf( 'WP_Block_Type', $result );
     1555                $this->assertEquals( 'test/json-block', $result->name );
     1556
     1557                unlink( $block_json );
     1558        }
    15041559}
  • 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..8d4f9a9bb7
    - +  
     1<?php
     2
     3/**
     4 * Tests for WP_Block_Metadata_Registry class.
     5 *
     6 * @group blocks
     7 */
     8class Tests_Blocks_WpBlockMetadataRegistry extends WP_UnitTestCase {
     9        public function test_register_and_get_metadata() {
     10                $source   = 'test-source';
     11                $metadata = array(
     12                        'name'  => 'test-block',
     13                        'title' => 'Test Block',
     14                );
     15
     16                WP_Block_Metadata_Registry::register( $source, $metadata );
     17
     18                $retrieved_metadata = WP_Block_Metadata_Registry::get_metadata( $source );
     19                $this->assertEquals( $metadata, $retrieved_metadata );
     20        }
     21
     22        public function test_get_nonexistent_metadata() {
     23                $retrieved_metadata = WP_Block_Metadata_Registry::get_metadata( 'nonexistent', 'nonexistent' );
     24                $this->assertNull( $retrieved_metadata );
     25        }
     26}