Make WordPress Core

Changeset 57565


Ignore:
Timestamp:
02/08/2024 10:39:24 AM (3 months ago)
Author:
gziolo
Message:

Editor: Add viewScriptModule handling to block.json metadata

Syncing changes from the Gutenberg plugin: https://github.com/WordPress/gutenberg/pull/57437.

Scripts and styles can be registered for blocks via block.json metadata. There is now a Modules API, but was no way to register or associate module assets with blocks via block.json.

Fixes #60233.
Props jonsurrell, gziolo, cbravobernal, luisherranz, youknowriad.

Location:
trunk
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/blocks.php

    r57559 r57565  
    3737 * @since 5.5.0
    3838 * @since 6.1.0 Added `$index` parameter.
     39 * @since 6.5.0 Added support for `viewScriptModule` field.
    3940 *
    4041 * @param string $block_name Name of the block.
     
    5354            $asset_handle .= '-view';
    5455        }
     56        if ( str_ends_with( strtolower( $field_name ), 'scriptmodule' ) ) {
     57            $asset_handle .= '-script-module';
     58        }
    5559        if ( $index > 0 ) {
    5660            $asset_handle .= '-' . ( $index + 1 );
     
    6064
    6165    $field_mappings = array(
    62         'editorScript' => 'editor-script',
    63         'script'       => 'script',
    64         'viewScript'   => 'view-script',
    65         'editorStyle'  => 'editor-style',
    66         'style'        => 'style',
    67         'viewStyle'    => 'view-style',
     66        'editorScript'     => 'editor-script',
     67        'editorStyle'      => 'editor-style',
     68        'script'           => 'script',
     69        'style'            => 'style',
     70        'viewScript'       => 'view-script',
     71        'viewScriptModule' => 'view-script-module',
     72        'viewStyle'        => 'view-style',
    6873    );
    6974    $asset_handle   = str_replace( '/', '-', $block_name ) .
     
    121126
    122127    return plugins_url( basename( $path ), $path );
     128}
     129
     130/**
     131 * Finds a script module ID for the selected block metadata field. It detects
     132 * when a path to file was provided and optionally finds a corresponding asset
     133 * file with details necessary to register the script module under with an
     134 * automatically generated module ID. It returns unprocessed script module
     135 * ID otherwise.
     136 *
     137 * @since 6.5.0
     138 *
     139 * @param array  $metadata   Block metadata.
     140 * @param string $field_name Field name to pick from metadata.
     141 * @param int    $index      Optional. Index of the script module ID to register when multiple
     142 *                           items passed. Default 0.
     143 * @return string|false Script module ID or false on failure.
     144 */
     145function register_block_script_module_id( $metadata, $field_name, $index = 0 ) {
     146    if ( empty( $metadata[ $field_name ] ) ) {
     147        return false;
     148    }
     149
     150    $module_id = $metadata[ $field_name ];
     151    if ( is_array( $module_id ) ) {
     152        if ( empty( $module_id[ $index ] ) ) {
     153            return false;
     154        }
     155        $module_id = $module_id[ $index ];
     156    }
     157
     158    $module_path = remove_block_asset_path_prefix( $module_id );
     159    if ( $module_id === $module_path ) {
     160        return $module_id;
     161    }
     162
     163    $path                  = dirname( $metadata['file'] );
     164    $module_asset_raw_path = $path . '/' . substr_replace( $module_path, '.asset.php', - strlen( '.js' ) );
     165    $module_id             = generate_block_asset_handle( $metadata['name'], $field_name, $index );
     166    $module_asset_path     = wp_normalize_path(
     167        realpath( $module_asset_raw_path )
     168    );
     169
     170    $module_path_norm = wp_normalize_path( realpath( $path . '/' . $module_path ) );
     171    $module_uri       = get_block_asset_url( $module_path_norm );
     172
     173    $module_asset        = ! empty( $module_asset_path ) ? require $module_asset_path : array();
     174    $module_dependencies = isset( $module_asset['dependencies'] ) ? $module_asset['dependencies'] : array();
     175
     176    wp_register_script_module(
     177        $module_id,
     178        $module_uri,
     179        $module_dependencies,
     180        isset( $module_asset['version'] ) ? $module_asset['version'] : false
     181    );
     182
     183    return $module_id;
    123184}
    124185
     
    315376 * @since 6.3.0 Added `selectors` field.
    316377 * @since 6.4.0 Added support for `blockHooks` field.
    317  * @since 6.5.0 Added support for `allowedBlocks` and `viewStyle` fields.
     378 * @since 6.5.0 Added support for `allowedBlocks`, `viewScriptModule`, and `viewStyle` fields.
    318379 *
    319380 * @param string $file_or_folder Path to the JSON file with metadata definition for
     
    491552    }
    492553
     554    $module_fields = array(
     555        'viewScriptModule' => 'view_script_module_ids',
     556    );
     557    foreach ( $module_fields as $metadata_field_name => $settings_field_name ) {
     558        if ( ! empty( $settings[ $metadata_field_name ] ) ) {
     559            $metadata[ $metadata_field_name ] = $settings[ $metadata_field_name ];
     560        }
     561        if ( ! empty( $metadata[ $metadata_field_name ] ) ) {
     562            $modules           = $metadata[ $metadata_field_name ];
     563            $processed_modules = array();
     564            if ( is_array( $modules ) ) {
     565                for ( $index = 0; $index < count( $modules ); $index++ ) {
     566                    $result = register_block_script_module_id(
     567                        $metadata,
     568                        $metadata_field_name,
     569                        $index
     570                    );
     571                    if ( $result ) {
     572                        $processed_modules[] = $result;
     573                    }
     574                }
     575            } else {
     576                $result = register_block_script_module_id(
     577                    $metadata,
     578                    $metadata_field_name
     579                );
     580                if ( $result ) {
     581                    $processed_modules[] = $result;
     582                }
     583            }
     584            $settings[ $settings_field_name ] = $processed_modules;
     585        }
     586    }
     587
    493588    $style_fields = array(
    494589        'editorStyle' => 'editor_style_handles',
  • trunk/src/wp-includes/class-wp-block-type.php

    r57521 r57565  
    226226     */
    227227    public $view_script_handles = array();
     228
     229    /**
     230     * Block type front end only script module IDs.
     231     *
     232     * @since 6.5.0
     233     * @var string[]
     234     */
     235    public $view_script_module_ids = array();
    228236
    229237    /**
  • trunk/src/wp-includes/class-wp-block.php

    r57562 r57565  
    471471        }
    472472
     473        if ( ! empty( $this->block_type->view_script_module_ids ) ) {
     474            foreach ( $this->block_type->view_script_module_ids as $view_script_module_id ) {
     475                wp_enqueue_script_module( $view_script_module_id );
     476            }
     477        }
     478
    473479        if ( ( ! empty( $this->block_type->style_handles ) ) ) {
    474480            foreach ( $this->block_type->style_handles as $style_handle ) {
  • trunk/src/wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php

    r57521 r57565  
    241241     * @since 5.9.0 Renamed `$block_type` to `$item` to match parent class for PHP 8 named parameter support.
    242242     * @since 6.3.0 Added `selectors` field.
     243     * @since 6.5.0 Added `view_script_module_ids` field.
    243244     *
    244245     * @param WP_Block_Type   $item    Block type data.
     
    292293                'script_handles',
    293294                'view_script_handles',
     295                'view_script_module_ids',
    294296                'editor_style_handles',
    295297                'style_handles',
     
    585587                    'readonly'    => true,
    586588                ),
     589                'view_script_module_ids'   => array(
     590                    'description' => __( 'Public facing script module IDs.' ),
     591                    'type'        => array( 'array' ),
     592                    'default'     => array(),
     593                    'items'       => array(
     594                        'type' => 'string',
     595                    ),
     596                    'context'     => array( 'embed', 'view', 'edit' ),
     597                    'readonly'    => true,
     598                ),
    587599                'editor_style_handles'  => array(
    588600                    'description' => __( 'Editor style handles.' ),
  • trunk/tests/phpunit/data/blocks/notice/block.json

    r57493 r57565  
    6969    "script": "tests-notice-script",
    7070    "viewScript": [ "tests-notice-view-script", "tests-notice-view-script-2" ],
     71    "viewScriptModule": [ "tests-notice-view-script-module", "tests-notice-view-script-module-2" ],
    7172    "editorStyle": "tests-notice-editor-style",
    7273    "style": [ "tests-notice-style", "tests-notice-style-2" ],
  • trunk/tests/phpunit/tests/blocks/register.php

    r57559 r57565  
    139139    /**
    140140     * @ticket 50263
     141     * @ticket 60233
    141142     */
    142143    public function test_generate_block_asset_handle() {
     
    154155            'unit-tests-my-block-view-script-100',
    155156            generate_block_asset_handle( $block_name, 'viewScript', 99 )
     157        );
     158        $this->assertSame(
     159            'unit-tests-my-block-view-script-module',
     160            generate_block_asset_handle( $block_name, 'viewScriptModule' )
     161        );
     162        $this->assertSame(
     163            'unit-tests-my-block-view-script-module-2',
     164            generate_block_asset_handle( $block_name, 'viewScriptModule', 1 )
     165        );
     166        $this->assertSame(
     167            'unit-tests-my-block-view-script-module-100',
     168            generate_block_asset_handle( $block_name, 'viewScriptModule', 99 )
    156169        );
    157170        $this->assertSame(
     
    200213
    201214    /**
     215     * @ticket 60233
     216     */
     217    public function test_generate_block_asset_handle_core_block_module() {
     218        $block_name = 'core/paragraph';
     219
     220        $this->assertSame(
     221            'wp-block-paragraph-editor-script-module',
     222            generate_block_asset_handle( $block_name, 'editorScriptModule' )
     223        );
     224        $this->assertSame(
     225            'wp-block-paragraph-editor-script-module-2',
     226            generate_block_asset_handle( $block_name, 'editorScriptModule', 1 )
     227        );
     228        $this->assertSame(
     229            'wp-block-paragraph-editor-script-module-100',
     230            generate_block_asset_handle( $block_name, 'editorScriptModule', 99 )
     231        );
     232
     233        $this->assertSame(
     234            'wp-block-paragraph-view-script-module',
     235            generate_block_asset_handle( $block_name, 'viewScriptModule' )
     236        );
     237        $this->assertSame(
     238            'wp-block-paragraph-view-script-module-2',
     239            generate_block_asset_handle( $block_name, 'viewScriptModule', 1 )
     240        );
     241        $this->assertSame(
     242            'wp-block-paragraph-view-script-module-100',
     243            generate_block_asset_handle( $block_name, 'viewScriptModule', 99 )
     244        );
     245
     246        $this->assertSame(
     247            'wp-block-paragraph-script-module',
     248            generate_block_asset_handle( $block_name, 'scriptModule' )
     249        );
     250        $this->assertSame(
     251            'wp-block-paragraph-script-module-2',
     252            generate_block_asset_handle( $block_name, 'scriptModule', 1 )
     253        );
     254        $this->assertSame(
     255            'wp-block-paragraph-script-module-100',
     256            generate_block_asset_handle( $block_name, 'scriptModule', 99 )
     257        );
     258    }
     259
     260    /**
    202261     * @ticket 50263
    203262     */
     
    233292
    234293    /**
     294     * @ticket 60233
     295     */
     296    public function test_field_not_found_register_block_script_module_id() {
     297        $result = register_block_script_module_id( array(), 'viewScriptModule' );
     298
     299        $this->assertFalse( $result );
     300    }
     301
     302    /**
     303     * @ticket 60233
     304     */
     305    public function test_empty_string_value_do_not_register_block_script_module_id() {
     306        $metadata = array( 'viewScriptModule' => '' );
     307        $result   = register_block_script_module_id( $metadata, 'viewScriptModule' );
     308
     309        $this->assertFalse( $result );
     310    }
     311
     312    /**
     313     * @ticket 60233
     314     */
     315    public function test_empty_array_value_do_not_register_block_script_module_id() {
     316        $metadata = array( 'viewScriptModule' => array() );
     317        $result   = register_block_script_module_id( $metadata, 'viewScriptModule' );
     318
     319        $this->assertFalse( $result );
     320    }
     321
     322    /**
     323     * @ticket 60233
     324     */
     325    public function test_wrong_array_index_do_not_register_block_script_module_id() {
     326        $metadata = array( 'viewScriptModule' => array( 'test-module_id' ) );
     327        $result   = register_block_script_module_id( $metadata, 'script', 1 );
     328
     329        $this->assertFalse( $result );
     330    }
     331
     332    /**
     333     * @ticket 60233
     334     */
     335    public function test_missing_asset_file_register_block_script_module_id() {
     336        $metadata = array(
     337            'file'             => __FILE__,
     338            'name'             => 'unit-tests/test-block',
     339            'viewScriptModule' => 'file:./blocks/notice/missing-asset.js',
     340        );
     341        $result   = register_block_script_module_id( $metadata, 'viewScriptModule' );
     342
     343        $this->assertSame( 'unit-tests-test-block-view-script-module', $result );
     344    }
     345
     346    /**
     347     * @ticket 60233
     348     */
     349    public function test_handle_passed_register_block_script_module_id() {
     350        $metadata = array(
     351            'viewScriptModule' => 'test-script-module-id',
     352        );
     353        $result   = register_block_script_module_id( $metadata, 'viewScriptModule' );
     354
     355        $this->assertSame( 'test-script-module-id', $result );
     356    }
     357
     358    /**
     359     * @ticket 60233
     360     */
     361    public function test_handles_passed_register_block_script_module_ids() {
     362        $metadata = array(
     363            'viewScriptModule' => array( 'test-id', 'test-id-other' ),
     364        );
     365
     366        $result = register_block_script_module_id( $metadata, 'viewScriptModule' );
     367        $this->assertSame( 'test-id', $result );
     368
     369        $result = register_block_script_module_id( $metadata, 'viewScriptModule', 1 );
     370        $this->assertSame( 'test-id-other', $result );
     371    }
     372
     373    /**
     374     * @ticket 60233
     375     */
     376    public function test_success_register_block_script_module_id() {
     377        $metadata = array(
     378            'file'             => DIR_TESTDATA . '/blocks/notice/block.json',
     379            'name'             => 'unit-tests/test-block',
     380            'viewScriptModule' => 'file:./block.js',
     381        );
     382        $result   = register_block_script_module_id( $metadata, 'viewScriptModule' );
     383
     384        $this->assertSame( 'unit-tests-test-block-view-script-module', $result );
     385
     386        // Test the behavior directly within the unit test
     387        $this->assertFalse(
     388            strpos(
     389                wp_normalize_path( realpath( dirname( $metadata['file'] ) . '/' . $metadata['viewScriptModule'] ) ),
     390                trailingslashit( wp_normalize_path( get_template_directory() ) )
     391            ) === 0
     392        );
     393
     394        $this->assertFalse(
     395            strpos(
     396                wp_normalize_path( realpath( dirname( $metadata['file'] ) . '/' . $metadata['viewScriptModule'] ) ),
     397                trailingslashit( wp_normalize_path( get_stylesheet_directory() ) )
     398            ) === 0
     399        );
     400    }
     401
     402    /**
    235403     * @ticket 50263
    236404     */
     
    246414    public function test_handles_passed_register_block_script_handles() {
    247415        $metadata = array(
    248             'script' => array( 'test-script-handle', 'test-script-handle-2' ),
     416            'script' => array( 'test-script-handle', 'test-script-handle-other' ),
    249417        );
    250418
     
    253421
    254422        $result = register_block_script_handle( $metadata, 'script', 1 );
    255         $this->assertSame( 'test-script-handle-2', $result, 1 );
     423        $this->assertSame( 'test-script-handle-other', $result );
    256424    }
    257425
     
    752920     * @ticket 57585
    753921     * @ticket 59797
     922     * @ticket 60233
    754923     */
    755924    public function test_block_registers_with_metadata_fixture() {
     
    8551024        );
    8561025        $this->assertSameSets(
     1026            array( 'tests-notice-view-script-module', 'tests-notice-view-script-module-2' ),
     1027            $result->view_script_module_ids
     1028        );
     1029        $this->assertSameSets(
    8571030            array( 'tests-notice-editor-style' ),
    8581031            $result->editor_style_handles
  • trunk/tests/phpunit/tests/rest-api/rest-block-type-controller.php

    r57521 r57565  
    262262        $this->assertSameSets( array(), $data['script_handles'] );
    263263        $this->assertSameSets( array(), $data['view_script_handles'] );
     264        $this->assertSameSets( array(), $data['view_script_module_ids'] );
    264265        $this->assertSameSets( array(), $data['editor_style_handles'] );
    265266        $this->assertSameSets( array(), $data['style_handles'] );
     
    340341        $this->assertSameSets( array(), $data['script_handles'] );
    341342        $this->assertSameSets( array(), $data['view_script_handles'] );
     343        $this->assertSameSets( array(), $data['view_script_module_ids'] );
    342344        $this->assertSameSets( array(), $data['editor_style_handles'] );
    343345        $this->assertSameSets( array(), $data['style_handles'] );
     
    563565        $data       = $response->get_data();
    564566        $properties = $data['schema']['properties'];
    565         $this->assertCount( 32, $properties );
     567        $this->assertCount( 33, $properties );
    566568        $this->assertArrayHasKey( 'api_version', $properties );
    567569        $this->assertArrayHasKey( 'name', $properties );
     
    587589        $this->assertArrayHasKey( 'script_handles', $properties );
    588590        $this->assertArrayHasKey( 'view_script_handles', $properties );
     591        $this->assertArrayHasKey( 'view_script_module_ids', $properties );
    589592        $this->assertArrayHasKey( 'editor_style_handles', $properties );
    590593        $this->assertArrayHasKey( 'style_handles', $properties );
     
    719722            'script_handles',
    720723            'view_script_handles',
     724            'view_script_module_ids',
    721725            'editor_style_handles',
    722726            'style_handles',
Note: See TracChangeset for help on using the changeset viewer.