From ffc1518f5b5ff93a9404fce81d276c52e3ff740f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Greg=20Zi=C3=83=C2=B3=C3=85=E2=80=9Akowski?= Date: Thu, 8 Feb 2024 10:41:13 +0000 Subject: [PATCH] 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. Built from https://develop.svn.wordpress.org/trunk@57565 git-svn-id: https://core.svn.wordpress.org/trunk@57066 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- wp-includes/blocks.php | 109 ++++++++++++++++-- wp-includes/class-wp-block-type.php | 8 ++ wp-includes/class-wp-block.php | 6 + .../class-wp-rest-block-types-controller.php | 12 ++ wp-includes/version.php | 2 +- 5 files changed, 129 insertions(+), 8 deletions(-) diff --git a/wp-includes/blocks.php b/wp-includes/blocks.php index b7c2c2c433..47620d7f80 100644 --- a/wp-includes/blocks.php +++ b/wp-includes/blocks.php @@ -36,6 +36,7 @@ function remove_block_asset_path_prefix( $asset_handle_or_path ) { * * @since 5.5.0 * @since 6.1.0 Added `$index` parameter. + * @since 6.5.0 Added support for `viewScriptModule` field. * * @param string $block_name Name of the block. * @param string $field_name Name of the metadata field. @@ -52,6 +53,9 @@ function generate_block_asset_handle( $block_name, $field_name, $index = 0 ) { if ( str_starts_with( $field_name, 'view' ) ) { $asset_handle .= '-view'; } + if ( str_ends_with( strtolower( $field_name ), 'scriptmodule' ) ) { + $asset_handle .= '-script-module'; + } if ( $index > 0 ) { $asset_handle .= '-' . ( $index + 1 ); } @@ -59,12 +63,13 @@ function generate_block_asset_handle( $block_name, $field_name, $index = 0 ) { } $field_mappings = array( - 'editorScript' => 'editor-script', - 'script' => 'script', - 'viewScript' => 'view-script', - 'editorStyle' => 'editor-style', - 'style' => 'style', - 'viewStyle' => 'view-style', + 'editorScript' => 'editor-script', + 'editorStyle' => 'editor-style', + 'script' => 'script', + 'style' => 'style', + 'viewScript' => 'view-script', + 'viewScriptModule' => 'view-script-module', + 'viewStyle' => 'view-style', ); $asset_handle = str_replace( '/', '-', $block_name ) . '-' . $field_mappings[ $field_name ]; @@ -122,6 +127,62 @@ function get_block_asset_url( $path ) { return plugins_url( basename( $path ), $path ); } +/** + * Finds a script module ID for the selected block metadata field. It detects + * when a path to file was provided and optionally finds a corresponding asset + * file with details necessary to register the script module under with an + * automatically generated module ID. It returns unprocessed script module + * ID otherwise. + * + * @since 6.5.0 + * + * @param array $metadata Block metadata. + * @param string $field_name Field name to pick from metadata. + * @param int $index Optional. Index of the script module ID to register when multiple + * items passed. Default 0. + * @return string|false Script module ID or false on failure. + */ +function register_block_script_module_id( $metadata, $field_name, $index = 0 ) { + if ( empty( $metadata[ $field_name ] ) ) { + return false; + } + + $module_id = $metadata[ $field_name ]; + if ( is_array( $module_id ) ) { + if ( empty( $module_id[ $index ] ) ) { + return false; + } + $module_id = $module_id[ $index ]; + } + + $module_path = remove_block_asset_path_prefix( $module_id ); + if ( $module_id === $module_path ) { + return $module_id; + } + + $path = dirname( $metadata['file'] ); + $module_asset_raw_path = $path . '/' . substr_replace( $module_path, '.asset.php', - strlen( '.js' ) ); + $module_id = generate_block_asset_handle( $metadata['name'], $field_name, $index ); + $module_asset_path = wp_normalize_path( + realpath( $module_asset_raw_path ) + ); + + $module_path_norm = wp_normalize_path( realpath( $path . '/' . $module_path ) ); + $module_uri = get_block_asset_url( $module_path_norm ); + + $module_asset = ! empty( $module_asset_path ) ? require $module_asset_path : array(); + $module_dependencies = isset( $module_asset['dependencies'] ) ? $module_asset['dependencies'] : array(); + + wp_register_script_module( + $module_id, + $module_uri, + $module_dependencies, + isset( $module_asset['version'] ) ? $module_asset['version'] : false + ); + + return $module_id; +} + /** * Finds a script handle for the selected block metadata field. It detects * when a path to file was provided and optionally finds a corresponding asset @@ -314,7 +375,7 @@ function get_block_metadata_i18n_schema() { * @since 6.1.0 Added support for `render` field. * @since 6.3.0 Added `selectors` field. * @since 6.4.0 Added support for `blockHooks` field. - * @since 6.5.0 Added support for `allowedBlocks` and `viewStyle` fields. + * @since 6.5.0 Added support for `allowedBlocks`, `viewScriptModule`, and `viewStyle` fields. * * @param string $file_or_folder Path to the JSON file with metadata definition for * the block or path to the folder where the `block.json` file is located. @@ -490,6 +551,40 @@ function register_block_type_from_metadata( $file_or_folder, $args = array() ) { } } + $module_fields = array( + 'viewScriptModule' => 'view_script_module_ids', + ); + foreach ( $module_fields as $metadata_field_name => $settings_field_name ) { + if ( ! empty( $settings[ $metadata_field_name ] ) ) { + $metadata[ $metadata_field_name ] = $settings[ $metadata_field_name ]; + } + if ( ! empty( $metadata[ $metadata_field_name ] ) ) { + $modules = $metadata[ $metadata_field_name ]; + $processed_modules = array(); + if ( is_array( $modules ) ) { + for ( $index = 0; $index < count( $modules ); $index++ ) { + $result = register_block_script_module_id( + $metadata, + $metadata_field_name, + $index + ); + if ( $result ) { + $processed_modules[] = $result; + } + } + } else { + $result = register_block_script_module_id( + $metadata, + $metadata_field_name + ); + if ( $result ) { + $processed_modules[] = $result; + } + } + $settings[ $settings_field_name ] = $processed_modules; + } + } + $style_fields = array( 'editorStyle' => 'editor_style_handles', 'style' => 'style_handles', diff --git a/wp-includes/class-wp-block-type.php b/wp-includes/class-wp-block-type.php index 33825a7888..63496d4102 100644 --- a/wp-includes/class-wp-block-type.php +++ b/wp-includes/class-wp-block-type.php @@ -226,6 +226,14 @@ class WP_Block_Type { */ public $view_script_handles = array(); + /** + * Block type front end only script module IDs. + * + * @since 6.5.0 + * @var string[] + */ + public $view_script_module_ids = array(); + /** * Block type editor only style handles. * diff --git a/wp-includes/class-wp-block.php b/wp-includes/class-wp-block.php index a965ef1372..4369223f42 100644 --- a/wp-includes/class-wp-block.php +++ b/wp-includes/class-wp-block.php @@ -470,6 +470,12 @@ public function render( $options = array() ) { } } + if ( ! empty( $this->block_type->view_script_module_ids ) ) { + foreach ( $this->block_type->view_script_module_ids as $view_script_module_id ) { + wp_enqueue_script_module( $view_script_module_id ); + } + } + if ( ( ! empty( $this->block_type->style_handles ) ) ) { foreach ( $this->block_type->style_handles as $style_handle ) { wp_enqueue_style( $style_handle ); diff --git a/wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php b/wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php index 7bf2f6af4a..9577ebe800 100644 --- a/wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php +++ b/wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php @@ -240,6 +240,7 @@ public function get_item( $request ) { * @since 5.5.0 * @since 5.9.0 Renamed `$block_type` to `$item` to match parent class for PHP 8 named parameter support. * @since 6.3.0 Added `selectors` field. + * @since 6.5.0 Added `view_script_module_ids` field. * * @param WP_Block_Type $item Block type data. * @param WP_REST_Request $request Full details about the request. @@ -291,6 +292,7 @@ public function prepare_item_for_response( $item, $request ) { 'editor_script_handles', 'script_handles', 'view_script_handles', + 'view_script_module_ids', 'editor_style_handles', 'style_handles', 'view_style_handles', @@ -584,6 +586,16 @@ public function get_item_schema() { 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), + 'view_script_module_ids' => array( + 'description' => __( 'Public facing script module IDs.' ), + 'type' => array( 'array' ), + 'default' => array(), + 'items' => array( + 'type' => 'string', + ), + 'context' => array( 'embed', 'view', 'edit' ), + 'readonly' => true, + ), 'editor_style_handles' => array( 'description' => __( 'Editor style handles.' ), 'type' => array( 'array' ), diff --git a/wp-includes/version.php b/wp-includes/version.php index 932cfd2de1..c810a9a2a5 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -16,7 +16,7 @@ * * @global string $wp_version */ -$wp_version = '6.5-alpha-57564'; +$wp_version = '6.5-alpha-57565'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.