Skip to content

Commit

Permalink
Blocks: Add handling for block.json viewScriptModule (#58731)
Browse files Browse the repository at this point in the history
Support `viewScriptModule` block.json field for registering blocks from metadata.

#57437 added `viewModule` support, but the Modules API changed in core to refer to "script modules."

---

- `viewModule` is deprecated but supported.
- `viewScriptModule` support is added.

If both fields are present, `viewScriptModule` will be used.

Two REST API fields are included for block types with the same information. `view_module_ids` (deprecated) and `view_script_module_ids`.
  • Loading branch information
sirreal committed Feb 7, 2024
1 parent 10ee33b commit 1bdb445
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 19 deletions.
33 changes: 28 additions & 5 deletions docs/reference-guides/block-api/block-metadata.md
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,26 @@ It's possible to pass a script handle registered with the [`wp_register_script`]

_Note: An option to pass also an array of view scripts exists since WordPress `6.1.0`._

### View script

- Type: `WPDefinedAsset`|`WPDefinedAsset[]` ([learn more](#wpdefinedasset))
- Optional
- Localized: No
- Property: `viewScript`
- Since: `WordPress 5.9.0`

```json
{ "viewScriptModule": [ "file:./view.js", "example-shared-script-module-id" ] }
```

Block type frontend script module definition. They will be enqueued only when viewing the content on the front of the site.

It's possible to pass a script module ID registered with the [`wp_register_script_module`](https://developer.wordpress.org/reference/functions/wp_register_script_module/) function, a path to a JavaScript module relative to the `block.json` file, or a list with a mix of both ([learn more](#wpdefinedasset)).

WordPress scripts and WordPress script modules are not compatible at the moment. If frontend view assets depend on WordPress scripts, `viewScript` should be used. If they depend on WordPress script modules —the Interactivity API at this time— `viewScriptModule` should be used. In the future, it will be possible to depend on scripts from script modules.

_Note: Available since WordPress `6.5.0`._

### Editor style

- Type: `WPDefinedAsset`|`WPDefinedAsset[]` ([learn more](#wpdefinedasset))
Expand Down Expand Up @@ -625,7 +645,7 @@ In `block.json`:

### `WPDefinedAsset`

It extends `WPDefinedPath` for JavaScript and CSS files. An alternative to the file path would be a script or style handle name referencing an already registered asset using WordPress helpers.
It extends `WPDefinedPath` for JavaScript and CSS files. An alternative to the file path would be a script handle, script module ID, or style handle referencing an already registered asset using WordPress helpers.

**Example:**

Expand All @@ -635,21 +655,24 @@ In `block.json`:
{
"editorScript": "file:./index.js",
"script": "file:./script.js",
"viewScript": [ "file:./view.js", "example-shared-view-script" ],
"viewScriptModule": [
"file:./view.js",
"example-registered-script-module-id"
],
"editorStyle": "file:./index.css",
"style": [ "file:./style.css", "example-shared-style" ],
"viewStyle": [ "file:./view.css", "example-view-style" ]
}
```

In the context of WordPress, when a block is registered with PHP, it will automatically register all scripts and styles that are found in the `block.json` file and use file paths rather than asset handles.
In the context of WordPress, when a block is registered with PHP, it will automatically register all scripts, script modules, and styles that are found in the `block.json` file and use file paths rather than asset handles.

That's why, the `WPDefinedAsset` type has to offer a way to mirror also the shape of params necessary to register scripts and styles using [`wp_register_script`](https://developer.wordpress.org/reference/functions/wp_register_script/) and [`wp_register_style`](https://developer.wordpress.org/reference/functions/wp_register_style/), and then assign these as handles associated with your block using the `script`, `style`, `editor_script`, and `editor_style` block type registration settings.
That's why the `WPDefinedAsset` type has to offer a way to mirror the parameters necessary to register scripts, script modules, and styles using [`wp_register_script`](https://developer.wordpress.org/reference/functions/wp_register_script/), [`wp_register_script_module`](https://developer.wordpress.org/reference/functions/wp_register_script_module/), and [`wp_register_style`](https://developer.wordpress.org/reference/functions/wp_register_style/), and then assign these as handles or script module IDs associated with the block.

It's possible to provide an object which takes the following shape:

- `handle` (`string`) - the name of the script. If omitted, it will be auto-generated.
- `dependencies` (`string[]`) - an array of registered script handles this script depends on. Default value: `[]`.
- `dependencies` (`string[]`|`{ id: string, import?: 'dynamic'|'static' }[]`) - an array of registered script handles this script depends on. Script modules may use a simple string for static dependencies or the object form to indicate a dynamic dependency. Dynamic dependencies are dependencies that may or may not be used at runtime and are typically used with the dynamic `import('module-id')` syntax. Default value: `[]`.
- `version` (`string`|`false`|`null`) - string specifying the script version number, if it has one, which is added to the URL as a query string for cache busting purposes. If the version is set to `false`, a version number is automatically added equal to current installed WordPress version. If set to `null`, no version is added. Default value: `false`.

The definition is stored inside separate PHP file which ends with `.asset.php` and is located next to the JS/CSS file listed in `block.json`. WordPress will automatically detect this file through pattern matching. This option is the preferred one as it is expected it will become an option to auto-generate those asset files with `@wordpress/scripts` package.
Expand Down
45 changes: 31 additions & 14 deletions lib/experimental/script-modules.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
*/
function gutenberg_filter_block_type_metadata_settings_register_modules( $settings, $metadata = null ) {
$module_fields = array(
'viewModule' => 'view_module_ids',
// @todo remove viewModule support in Gutenberg >= 17.8 (replaced by viewScriptModule).
'viewModule' => 'view_script_module_ids',
'viewScriptModule' => 'view_script_module_ids',
);
foreach ( $module_fields as $metadata_field_name => $settings_field_name ) {
if ( ! empty( $settings[ $metadata_field_name ] ) ) {
Expand Down Expand Up @@ -49,19 +51,19 @@ function gutenberg_filter_block_type_metadata_settings_register_modules( $settin
* @param array $parsed_block The full block, including name and attributes.
* @param WP_Block $block_instance The block instance.
*/
function gutenberg_filter_render_block_enqueue_view_modules( $block_content, $parsed_block, $block_instance ) {
function gutenberg_filter_render_block_enqueue_view_script_modules( $block_content, $parsed_block, $block_instance ) {
$block_type = $block_instance->block_type;

if ( ! empty( $block_type->view_module_ids ) ) {
foreach ( $block_type->view_module_ids as $module_id ) {
if ( ! empty( $block_type->view_script_module_ids ) ) {
foreach ( $block_type->view_script_module_ids as $module_id ) {
wp_enqueue_script_module( $module_id );
}
}

return $block_content;
}

add_filter( 'render_block', 'gutenberg_filter_render_block_enqueue_view_modules', 10, 3 );
add_filter( 'render_block', 'gutenberg_filter_render_block_enqueue_view_script_modules', 10, 3 );

/**
* Finds a module ID for the selected block metadata field. It detects
Expand Down Expand Up @@ -159,7 +161,9 @@ function gutenberg_generate_block_asset_module_id( $block_name, $field_name, $in
}

$field_mappings = array(
'viewModule' => 'view-module',
// @todo remove viewModule support in Gutenberg >= 17.8 (replaced by viewScriptModule).
'viewModule' => 'view-script-module',
'viewScriptModule' => 'view-script-module',
);
$asset_handle = str_replace( '/', '-', $block_name ) .
'-' . $field_mappings[ $field_name ];
Expand All @@ -172,29 +176,42 @@ function gutenberg_generate_block_asset_module_id( $block_name, $field_name, $in
/**
* Registers a REST field for block types to provide view module IDs.
*
* Adds the `view_module_ids` field to block type objects in the REST API, which
* Adds the `view_script_module_ids` and `view_module_ids` (deprecated) field to block type objects in the REST API, which
* lists the script module IDs for any script modules associated with the
* block's viewModule(s) key.
*
* @since 6.5.0
* block's viewScriptModule key.
*/
function gutenberg_register_view_module_ids_rest_field() {
function gutenberg_register_view_script_module_ids_rest_field() {
// @todo remove view_module_ids support in Gutenberg >= 17.8 (replaced by view_script_module_ids).
register_rest_field(
'block-type',
'view_module_ids',
array(
'get_callback' => function ( $item ) {
$block_type = WP_Block_Type_Registry::get_instance()->get_registered( $item['name'] );
if ( isset( $block_type->view_module_ids ) ) {
return $block_type->view_module_ids;
if ( isset( $block_type->view_script_module_ids ) ) {
return $block_type->view_script_module_ids;
}
return array();
},
)
);

register_rest_field(
'block-type',
'view_script_module_ids',
array(
'get_callback' => function ( $item ) {
$block_type = WP_Block_Type_Registry::get_instance()->get_registered( $item['name'] );
if ( isset( $block_type->view_script_module_ids ) ) {
return $block_type->view_script_module_ids;
}
return array();
},
)
);
}

add_action( 'rest_api_init', 'gutenberg_register_view_module_ids_rest_field' );
add_action( 'rest_api_init', 'gutenberg_register_view_script_module_ids_rest_field' );

/**
* Registers the module if no module with that module identifier has already
Expand Down

0 comments on commit 1bdb445

Please sign in to comment.