diff --git a/lib/compat/wordpress-6.5/class-wp-navigation-block-renderer.php b/lib/compat/wordpress-6.5/class-wp-navigation-block-renderer.php index 9c270f59fa220..4a00578d3f273 100644 --- a/lib/compat/wordpress-6.5/class-wp-navigation-block-renderer.php +++ b/lib/compat/wordpress-6.5/class-wp-navigation-block-renderer.php @@ -82,13 +82,13 @@ private static function has_submenus( $inner_blocks ) { } /** - * Determine whether to load the view script. + * Determine whether the navigation blocks is interactive. * * @param array $attributes The block attributes. * @param WP_Block_List $inner_blocks The list of inner blocks. * @return bool Returns whether or not to load the view script. */ - private static function should_load_view_script( $attributes, $inner_blocks ) { + private static function is_interactive( $attributes, $inner_blocks ) { $has_submenus = static::has_submenus( $inner_blocks ); $is_responsive_menu = static::is_responsive( $attributes ); return ( $has_submenus && ( $attributes['openSubmenusOnClick'] || $attributes['showSubmenuIcon'] ) ) || $is_responsive_menu; @@ -129,8 +129,8 @@ private static function get_markup_for_inner_block( $inner_block ) { * @return string Returns the html for the inner blocks of the navigation block. */ private static function get_inner_blocks_html( $attributes, $inner_blocks ) { - $has_submenus = static::has_submenus( $inner_blocks ); - $should_load_view_script = static::should_load_view_script( $attributes, $inner_blocks ); + $has_submenus = static::has_submenus( $inner_blocks ); + $is_interactive = static::is_interactive( $attributes, $inner_blocks ); $style = static::get_styles( $attributes ); $class = static::get_classes( $attributes ); @@ -168,7 +168,7 @@ private static function get_inner_blocks_html( $attributes, $inner_blocks ) { } // Add directives to the submenu if needed. - if ( $has_submenus && $should_load_view_script ) { + if ( $has_submenus && $is_interactive ) { $tags = new WP_HTML_Tag_Processor( $inner_blocks_html ); $inner_blocks_html = gutenberg_block_core_navigation_add_directives_to_submenu( $tags, $attributes ); } @@ -402,9 +402,9 @@ private static function get_styles( $attributes ) { * @return string Returns the container markup. */ private static function get_responsive_container_markup( $attributes, $inner_blocks, $inner_blocks_html ) { - $should_load_view_script = static::should_load_view_script( $attributes, $inner_blocks ); - $colors = gutenberg_block_core_navigation_build_css_colors( $attributes ); - $modal_unique_id = wp_unique_id( 'modal-' ); + $is_interactive = static::is_interactive( $attributes, $inner_blocks ); + $colors = gutenberg_block_core_navigation_build_css_colors( $attributes ); + $modal_unique_id = wp_unique_id( 'modal-' ); $responsive_container_classes = array( 'wp-block-navigation__responsive-container', @@ -432,7 +432,7 @@ private static function get_responsive_container_markup( $attributes, $inner_blo $responsive_container_directives = ''; $responsive_dialog_directives = ''; $close_button_directives = ''; - if ( $should_load_view_script ) { + if ( $is_interactive ) { $open_button_directives = ' data-wp-on--click="actions.openMenuOnClick" data-wp-on--keydown="actions.handleMenuKeydown" @@ -495,12 +495,12 @@ private static function get_responsive_container_markup( $attributes, $inner_blo * @return string Returns the navigation block markup. */ private static function get_nav_wrapper_attributes( $attributes, $inner_blocks ) { - $nav_menu_name = static::get_unique_navigation_name( $attributes ); - $should_load_view_script = static::should_load_view_script( $attributes, $inner_blocks ); - $is_responsive_menu = static::is_responsive( $attributes ); - $style = static::get_styles( $attributes ); - $class = static::get_classes( $attributes ); - $wrapper_attributes = get_block_wrapper_attributes( + $nav_menu_name = static::get_unique_navigation_name( $attributes ); + $is_interactive = static::is_interactive( $attributes, $inner_blocks ); + $is_responsive_menu = static::is_responsive( $attributes ); + $style = static::get_styles( $attributes ); + $class = static::get_classes( $attributes ); + $wrapper_attributes = get_block_wrapper_attributes( array( 'class' => $class, 'style' => $style, @@ -509,7 +509,7 @@ private static function get_nav_wrapper_attributes( $attributes, $inner_blocks ) ); if ( $is_responsive_menu ) { - $nav_element_directives = static::get_nav_element_directives( $should_load_view_script, $attributes ); + $nav_element_directives = static::get_nav_element_directives( $is_interactive, $attributes ); $wrapper_attributes .= ' ' . $nav_element_directives; } @@ -517,13 +517,14 @@ private static function get_nav_wrapper_attributes( $attributes, $inner_blocks ) } /** - * Get the nav element directives + * Gets the nav element directives. * - * @param bool $should_load_view_script Whether or not the view script should be loaded. + * @param bool $is_interactive Whether the block is interactive. + * @param array $attributes The block attributes. * @return string the directives for the navigation element. */ - private static function get_nav_element_directives( $should_load_view_script, $attributes ) { - if ( ! $should_load_view_script ) { + private static function get_nav_element_directives( $is_interactive, $attributes ) { + if ( ! $is_interactive ) { return ''; } // When adding to this array be mindful of security concerns. @@ -541,8 +542,10 @@ private static function get_nav_element_directives( $should_load_view_script, $a data-wp-context=\'' . $nav_element_context . '\' '; - // When the navigation overlayMenu attribute is set to "always" - // we don't need to use JavaScript to collapse the menu as we set the class manually. + /* + * When the navigation's 'overlayMenu' attribute is set to 'always', JavaScript + * is not needed for collapsing the menu because the class is set manually. + */ if ( ! static::is_always_overlay( $attributes ) ) { $nav_element_directives .= 'data-wp-init="callbacks.initNav"'; $nav_element_directives .= ' '; // space separator @@ -553,37 +556,15 @@ private static function get_nav_element_directives( $should_load_view_script, $a } /** - * Handle view script loading. + * Handle view script module loading. * * @param array $attributes The block attributes. * @param WP_Block $block The parsed block. * @param WP_Block_List $inner_blocks The list of inner blocks. */ - private static function handle_view_script_loading( $attributes, $block, $inner_blocks ) { - $should_load_view_script = static::should_load_view_script( $attributes, $inner_blocks ); - $is_gutenberg_plugin = defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN; - $view_js_file = 'wp-block-navigation-view'; - $script_handles = $block->block_type->view_script_handles; - - if ( $is_gutenberg_plugin ) { - if ( $should_load_view_script ) { - gutenberg_enqueue_module( '@wordpress/block-library/navigation-block' ); - } - // Remove the view script because we are using the module. - $block->block_type->view_script_handles = array_diff( $script_handles, array( $view_js_file ) ); - } else { - // If the script already exists, there is no point in removing it from viewScript. - if ( ! wp_script_is( $view_js_file ) ) { - - // If the script is not needed, and it is still in the `view_script_handles`, remove it. - if ( ! $should_load_view_script && in_array( $view_js_file, $script_handles, true ) ) { - $block->block_type->view_script_handles = array_diff( $script_handles, array( $view_js_file ) ); - } - // If the script is needed, but it was previously removed, add it again. - if ( $should_load_view_script && ! in_array( $view_js_file, $script_handles, true ) ) { - $block->block_type->view_script_handles = array_merge( $script_handles, array( $view_js_file ) ); - } - } + private static function handle_view_script_module_loading( $attributes, $block, $inner_blocks ) { + if ( static::is_interactive( $attributes, $inner_blocks ) ) { + wp_enqueue_script_module( '@wordpress/block-library/navigation-block' ); } } @@ -653,7 +634,7 @@ public static function render( $attributes, $content, $block ) { return ''; } - static::handle_view_script_loading( $attributes, $block, $inner_blocks ); + static::handle_view_script_module_loading( $attributes, $block, $inner_blocks ); return sprintf( '', diff --git a/lib/compat/wordpress-6.5/class-wp-script-modules.php b/lib/compat/wordpress-6.5/class-wp-script-modules.php new file mode 100644 index 0000000000000..f6a2a348f92ef --- /dev/null +++ b/lib/compat/wordpress-6.5/class-wp-script-modules.php @@ -0,0 +1,323 @@ + + */ + private $enqueued_before_registered = array(); + + /** + * Registers the script module if no script module with that script module + * identifier has already been registered. + * + * @since 6.5.0 + * + * @param string $id The identifier of the script module. Should be unique. It will be used in the + * final import map. + * @param string $src Optional. Full URL of the script module, or path of the script module relative + * to the WordPress root directory. If it is provided and the script module has + * not been registered yet, it will be registered. + * @param array $deps { + * Optional. List of dependencies. + * + * @type string|array $0... { + * An array of script module identifiers of the dependencies of this script + * module. The dependencies can be strings or arrays. If they are arrays, + * they need an `id` key with the script module identifier, and can contain + * an `import` key with either `static` or `dynamic`. By default, + * dependencies that don't contain an `import` key are considered static. + * + * @type string $id The script module identifier. + * @type string $import Optional. Import type. May be either `static` or + * `dynamic`. Defaults to `static`. + * } + * } + * @param string|false|null $version Optional. String specifying the script module version number. Defaults to false. + * It is added to the URL as a query string for cache busting purposes. If $version + * is set to false, the version number is the currently installed WordPress version. + * If $version is set to null, no version is added. + */ + public function register( string $id, string $src, array $deps = array(), $version = false ) { + if ( ! isset( $this->registered[ $id ] ) ) { + $dependencies = array(); + foreach ( $deps as $dependency ) { + if ( is_array( $dependency ) ) { + if ( ! isset( $dependency['id'] ) ) { + _doing_it_wrong( __METHOD__, __( 'Missing required id key in entry among dependencies array.' ), '6.5.0' ); + continue; + } + $dependencies[] = array( + 'id' => $dependency['id'], + 'import' => isset( $dependency['import'] ) && 'dynamic' === $dependency['import'] ? 'dynamic' : 'static', + ); + } elseif ( is_string( $dependency ) ) { + $dependencies[] = array( + 'id' => $dependency, + 'import' => 'static', + ); + } else { + _doing_it_wrong( __METHOD__, __( 'Entries in dependencies array must be either strings or arrays with an id key.' ), '6.5.0' ); + } + } + + $this->registered[ $id ] = array( + 'src' => $src, + 'version' => $version, + 'enqueue' => isset( $this->enqueued_before_registered[ $id ] ), + 'dependencies' => $dependencies, + ); + } + } + + /** + * Marks the script module to be enqueued in the page. + * + * If a src is provided and the script module has not been registered yet, it + * will be registered. + * + * @since 6.5.0 + * + * @param string $id The identifier of the script module. Should be unique. It will be used in the + * final import map. + * @param string $src Optional. Full URL of the script module, or path of the script module relative + * to the WordPress root directory. If it is provided and the script module has + * not been registered yet, it will be registered. + * @param array $deps { + * Optional. List of dependencies. + * + * @type string|array $0... { + * An array of script module identifiers of the dependencies of this script + * module. The dependencies can be strings or arrays. If they are arrays, + * they need an `id` key with the script module identifier, and can contain + * an `import` key with either `static` or `dynamic`. By default, + * dependencies that don't contain an `import` key are considered static. + * + * @type string $id The script module identifier. + * @type string $import Optional. Import type. May be either `static` or + * `dynamic`. Defaults to `static`. + * } + * } + * @param string|false|null $version Optional. String specifying the script module version number. Defaults to false. + * It is added to the URL as a query string for cache busting purposes. If $version + * is set to false, the version number is the currently installed WordPress version. + * If $version is set to null, no version is added. + */ + public function enqueue( string $id, string $src = '', array $deps = array(), $version = false ) { + if ( isset( $this->registered[ $id ] ) ) { + $this->registered[ $id ]['enqueue'] = true; + } elseif ( $src ) { + $this->register( $id, $src, $deps, $version ); + $this->registered[ $id ]['enqueue'] = true; + } else { + $this->enqueued_before_registered[ $id ] = true; + } + } + + /** + * Unmarks the script module so it will no longer be enqueued in the page. + * + * @since 6.5.0 + * + * @param string $id The identifier of the script module. + */ + public function dequeue( string $id ) { + if ( isset( $this->registered[ $id ] ) ) { + $this->registered[ $id ]['enqueue'] = false; + } + unset( $this->enqueued_before_registered[ $id ] ); + } + + /** + * Adds the hooks to print the import map, enqueued script modules and script + * module preloads. + * + * In classic themes, the script modules used by the blocks are not yet known + * when the `wp_head` actions is fired, so it needs to print everything in the + * footer. + * + * @since 6.5.0 + */ + public function add_hooks() { + $position = wp_is_block_theme() ? 'wp_head' : 'wp_footer'; + add_action( $position, array( $this, 'print_import_map' ) ); + add_action( $position, array( $this, 'print_enqueued_script_modules' ) ); + add_action( $position, array( $this, 'print_script_module_preloads' ) ); + } + + /** + * Prints the enqueued script modules using script tags with type="module" + * attributes. + * + * @since 6.5.0 + */ + public function print_enqueued_script_modules() { + foreach ( $this->get_marked_for_enqueue() as $id => $script_module ) { + wp_print_script_tag( + array( + 'type' => 'module', + 'src' => $this->get_versioned_src( $script_module ), + 'id' => $id . '-js-module', + ) + ); + } + } + + /** + * Prints the the static dependencies of the enqueued script modules using + * link tags with rel="modulepreload" attributes. + * + * If a script module is marked for enqueue, it will not be preloaded. + * + * @since 6.5.0 + */ + public function print_script_module_preloads() { + foreach ( $this->get_dependencies( array_keys( $this->get_marked_for_enqueue() ), array( 'static' ) ) as $id => $script_module ) { + // Don't preload if it's marked for enqueue. + if ( true !== $script_module['enqueue'] ) { + echo sprintf( + '', + esc_url( $this->get_versioned_src( $script_module ) ), + esc_attr( $id . '-js-modulepreload' ) + ); + } + } + } + + /** + * Prints the import map using a script tag with a type="importmap" attribute. + * + * @since 6.5.0 + */ + public function print_import_map() { + $import_map = $this->get_import_map(); + if ( ! empty( $import_map['imports'] ) ) { + wp_print_inline_script_tag( + wp_json_encode( $import_map, JSON_HEX_TAG | JSON_HEX_AMP ), + array( + 'type' => 'importmap', + 'id' => 'wp-importmap', + ) + ); + } + } + + /** + * Returns the import map array. + * + * @since 6.5.0 + * + * @return array Array with an `imports` key mapping to an array of script module identifiers and their respective + * URLs, including the version query. + */ + private function get_import_map(): array { + $imports = array(); + foreach ( $this->get_dependencies( array_keys( $this->get_marked_for_enqueue() ) ) as $id => $script_module ) { + $imports[ $id ] = $this->get_versioned_src( $script_module ); + } + return array( 'imports' => $imports ); + } + + /** + * Retrieves the list of script modules marked for enqueue. + * + * @since 6.5.0 + * + * @return array Script modules marked for enqueue, keyed by script module identifier. + */ + private function get_marked_for_enqueue(): array { + $enqueued = array(); + foreach ( $this->registered as $id => $script_module ) { + if ( true === $script_module['enqueue'] ) { + $enqueued[ $id ] = $script_module; + } + } + return $enqueued; + } + + /** + * Retrieves all the dependencies for the given script module identifiers, + * filtered by import types. + * + * It will consolidate an array containing a set of unique dependencies based + * on the requested import types: 'static', 'dynamic', or both. This method is + * recursive and also retrieves dependencies of the dependencies. + * + * @since 6.5.0 + * + + * @param string[] $ids The identifiers of the script modules for which to gather dependencies. + * @param array $import_types Optional. Import types of dependencies to retrieve: 'static', 'dynamic', or both. + * Default is both. + * @return array List of dependencies, keyed by script module identifier. + */ + private function get_dependencies( array $ids, array $import_types = array( 'static', 'dynamic' ) ) { + return array_reduce( + $ids, + function ( $dependency_script_modules, $id ) use ( $import_types ) { + $dependencies = array(); + foreach ( $this->registered[ $id ]['dependencies'] as $dependency ) { + if ( + in_array( $dependency['import'], $import_types, true ) && + isset( $this->registered[ $dependency['id'] ] ) && + ! isset( $dependency_script_modules[ $dependency['id'] ] ) + ) { + $dependencies[ $dependency['id'] ] = $this->registered[ $dependency['id'] ]; + } + } + return array_merge( $dependency_script_modules, $dependencies, $this->get_dependencies( array_keys( $dependencies ), $import_types ) ); + }, + array() + ); + } + + /** + * Gets the versioned URL for a script module src. + * + * If $version is set to false, the version number is the currently installed + * WordPress version. If $version is set to null, no version is added. + * Otherwise, the string passed in $version is used. + * + * @since 6.5.0 + * + * @param array $script_module The script module. + * @return string The script module src with a version if relevant. + */ + private function get_versioned_src( array $script_module ): string { + $args = array(); + if ( false === $script_module['version'] ) { + $args['ver'] = get_bloginfo( 'version' ); + } elseif ( null !== $script_module['version'] ) { + $args['ver'] = $script_module['version']; + } + if ( $args ) { + return add_query_arg( $args, $script_module['src'] ); + } + return $script_module['src']; + } + } +} diff --git a/lib/compat/wordpress-6.5/scripts-modules.php b/lib/compat/wordpress-6.5/scripts-modules.php new file mode 100644 index 0000000000000..ba329b255b196 --- /dev/null +++ b/lib/compat/wordpress-6.5/scripts-modules.php @@ -0,0 +1,119 @@ +add_hooks(); + } + return $instance; + } +} + +if ( ! function_exists( 'wp_register_script_module' ) ) { + /** + * Registers the script module if no script module with that script module + * identifier has already been registered. + * + * @since 6.5.0 + * + * @param string $id The identifier of the script module. Should be unique. It will be used in the + * final import map. + * @param string $src Optional. Full URL of the script module, or path of the script module relative + * to the WordPress root directory. If it is provided and the script module has + * not been registered yet, it will be registered. + * @param array $deps { + * Optional. List of dependencies. + * + * @type string|array $0... { + * An array of script module identifiers of the dependencies of this script + * module. The dependencies can be strings or arrays. If they are arrays, + * they need an `id` key with the script module identifier, and can contain + * an `import` key with either `static` or `dynamic`. By default, + * dependencies that don't contain an `import` key are considered static. + * + * @type string $id The script module identifier. + * @type string $import Optional. Import type. May be either `static` or + * `dynamic`. Defaults to `static`. + * } + * } + * @param string|false|null $version Optional. String specifying the script module version number. Defaults to false. + * It is added to the URL as a query string for cache busting purposes. If $version + * is set to false, the version number is the currently installed WordPress version. + * If $version is set to null, no version is added. + */ + function wp_register_script_module( string $id, string $src, array $deps = array(), $version = false ) { + wp_script_modules()->register( $id, $src, $deps, $version ); + } +} + +if ( ! function_exists( 'wp_enqueue_script_module' ) ) { + /** + * Marks the script module to be enqueued in the page. + * + * If a src is provided and the script module has not been registered yet, it + * will be registered. + * + * @since 6.5.0 + * + * @param string $id The identifier of the script module. Should be unique. It will be used in the + * final import map. + * @param string $src Optional. Full URL of the script module, or path of the script module relative + * to the WordPress root directory. If it is provided and the script module has + * not been registered yet, it will be registered. + * @param array $deps { + * Optional. List of dependencies. + * + * @type string|array $0... { + * An array of script module identifiers of the dependencies of this script + * module. The dependencies can be strings or arrays. If they are arrays, + * they need an `id` key with the script module identifier, and can contain + * an `import` key with either `static` or `dynamic`. By default, + * dependencies that don't contain an `import` key are considered static. + * + * @type string $id The script module identifier. + * @type string $import Optional. Import type. May be either `static` or + * `dynamic`. Defaults to `static`. + * } + * } + * @param string|false|null $version Optional. String specifying the script module version number. Defaults to false. + * It is added to the URL as a query string for cache busting purposes. If $version + * is set to false, the version number is the currently installed WordPress version. + * If $version is set to null, no version is added. + */ + function wp_enqueue_script_module( string $id, string $src = '', array $deps = array(), $version = false ) { + wp_script_modules()->enqueue( $id, $src, $deps, $version ); + } +} + +if ( ! function_exists( 'wp_dequeue_script_module' ) ) { + /** + * Unmarks the script module so it is no longer enqueued in the page. + * + * @since 6.5.0 + * + * @param string $id The identifier of the script module. + */ + function wp_dequeue_script_module( string $id ) { + wp_script_modules()->dequeue( $id ); + } +} diff --git a/lib/experimental/interactivity-api/modules.php b/lib/experimental/interactivity-api/modules.php index 0695da26f4b1b..f40a81bc334e6 100644 --- a/lib/experimental/interactivity-api/modules.php +++ b/lib/experimental/interactivity-api/modules.php @@ -8,9 +8,12 @@ /** * Register the `@wordpress/interactivity` module. + * + * !! This will be removed once https://github.com/WordPress/gutenberg/pull/58066 + * is merged. */ function gutenberg_register_interactivity_module() { - gutenberg_register_module( + wp_register_script_module( '@wordpress/interactivity', gutenberg_url( '/build/interactivity/index.min.js' ), array(), diff --git a/lib/experimental/modules/class-gutenberg-modules.php b/lib/experimental/modules/class-gutenberg-modules.php deleted file mode 100644 index f773e2c998c23..0000000000000 --- a/lib/experimental/modules/class-gutenberg-modules.php +++ /dev/null @@ -1,470 +0,0 @@ - $dependency['id'], - 'type' => isset( $dependency['type'] ) && 'dynamic' === $dependency['type'] ? 'dynamic' : 'static', - ); - } elseif ( is_string( $dependency ) ) { - $deps[] = array( - 'id' => $dependency, - 'type' => 'static', - ); - } - } - - self::$registered[ $module_identifier ] = array( - 'src' => $src, - 'version' => $version, - 'enqueued' => in_array( $module_identifier, self::$enqueued_modules_before_register, true ), - 'dependencies' => $deps, - ); - } - } - - /** - * Marks the module to be enqueued in the page. - * - * @param string $module_identifier The identifier of the module. - */ - public static function enqueue( $module_identifier ) { - if ( isset( self::$registered[ $module_identifier ] ) ) { - self::$registered[ $module_identifier ]['enqueued'] = true; - } elseif ( ! in_array( $module_identifier, self::$enqueued_modules_before_register, true ) ) { - self::$enqueued_modules_before_register[] = $module_identifier; - } - } - - /** - * Unmarks the module so it is no longer enqueued in the page. - * - * @param string $module_identifier The identifier of the module. - */ - public static function dequeue( $module_identifier ) { - if ( isset( self::$registered[ $module_identifier ] ) ) { - self::$registered[ $module_identifier ]['enqueued'] = false; - } - $key = array_search( $module_identifier, self::$enqueued_modules_before_register, true ); - if ( false !== $key ) { - array_splice( self::$enqueued_modules_before_register, $key, 1 ); - } - } - - /** - * Returns the import map array. - * - * @return array Array with an 'imports' key mapping to an array of module identifiers and their respective source URLs, including the version query. - */ - public static function get_import_map() { - $imports = array(); - foreach ( self::get_dependencies( array_keys( self::get_enqueued() ) ) as $module_identifier => $module ) { - $imports[ $module_identifier ] = $module['src'] . self::get_version_query_string( $module['version'] ); - } - return array( 'imports' => $imports ); - } - - /** - * Prints the import map using a script tag with an type="importmap" attribute. - */ - public static function print_import_map() { - $import_map = self::get_import_map(); - if ( ! empty( $import_map['imports'] ) ) { - echo ''; - } - } - - /** - * Prints all the enqueued modules using ' - ); - } - - /** - * Gets the version of a module. - * - * If SCRIPT_DEBUG is true, the version is the current timestamp. If $version - * is set to false, the version number is the currently installed WordPress - * version. If $version is set to null, no version is added. - * - * @param array $version The version of the module. - * @return string A string presenting the version. - */ - private static function get_version_query_string( $version ) { - if ( defined( 'SCRIPT_DEBUG ' ) && SCRIPT_DEBUG ) { - return '?ver=' . time(); - } elseif ( false === $version ) { - return '?ver=' . get_bloginfo( 'version' ); - } elseif ( null !== $version ) { - return '?ver=' . $version; - } - return ''; - } - - /** - * Retrieves an array of enqueued modules. - * - * @return array Array of modules keyed by module identifier. - */ - private static function get_enqueued() { - $enqueued = array(); - foreach ( self::$registered as $module_identifier => $module ) { - if ( true === $module['enqueued'] ) { - $enqueued[ $module_identifier ] = $module; - } - } - return $enqueued; - } - - /** - * Retrieves all the dependencies for given modules depending on type. - * - * This method is recursive to also retrieve dependencies of the dependencies. - * It will consolidate an array containing unique dependencies based on the - * requested types ('static' or 'dynamic'). - * - * @param array $module_identifiers The identifiers of the modules for which to gather dependencies. - * @param array $types Optional. Types of dependencies to retrieve: 'static', 'dynamic', or both. Default is both. - * @return array Array of modules keyed by module identifier. - */ - private static function get_dependencies( $module_identifiers, $types = array( 'static', 'dynamic' ) ) { - return array_reduce( - $module_identifiers, - function ( $dependency_modules, $module_identifier ) use ( $types ) { - $dependencies = array(); - foreach ( self::$registered[ $module_identifier ]['dependencies'] as $dependency ) { - if ( - in_array( $dependency['type'], $types, true ) && - isset( self::$registered[ $dependency['id'] ] ) && - ! isset( $dependency_modules[ $dependency['id'] ] ) - ) { - $dependencies[ $dependency['id'] ] = self::$registered[ $dependency['id'] ]; - } - } - return array_merge( $dependency_modules, $dependencies, self::get_dependencies( array_keys( $dependencies ), $types ) ); - }, - array() - ); - } -} - -/** - * Registers the module if no module with that module identifier has already - * been registered. - * - * @param string $module_identifier The identifier of the module. Should be unique. It will be used in the final import map. - * @param string $src Full URL of the module, or path of the script relative to the WordPress root directory. - * @param array $dependencies Optional. An array of module identifiers of the dependencies of this module. The dependencies can be strings or arrays. If they are arrays, they need an `id` key with the module identifier, and can contain a `type` key with either `static` or `dynamic`. By default, dependencies that don't contain a type are considered static. - * @param string|false|null $version Optional. String specifying module version number. Defaults to false. It is added to the URL as a query string for cache busting purposes. If SCRIPT_DEBUG is true, the version is the current timestamp. If $version is set to false, the version number is the currently installed WordPress version. If $version is set to null, no version is added. - */ -function gutenberg_register_module( $module_identifier, $src, $dependencies = array(), $version = false ) { - Gutenberg_Modules::register( $module_identifier, $src, $dependencies, $version ); -} - -/** - * Marks the module to be enqueued in the page. - * - * @param string $module_identifier The identifier of the module. - */ -function gutenberg_enqueue_module( $module_identifier ) { - Gutenberg_Modules::enqueue( $module_identifier ); -} - -/** - * Unmarks the module so it is not longer enqueued in the page. - * - * @param string $module_identifier The identifier of the module. - */ -function gutenberg_dequeue_module( $module_identifier ) { - Gutenberg_Modules::dequeue( $module_identifier ); -} - -$modules_position = wp_is_block_theme() ? 'wp_head' : 'wp_footer'; -// Prints the import map in the head tag in block themes. Otherwise in the footer. -add_action( $modules_position, array( 'Gutenberg_Modules', 'print_import_map' ) ); - -// Prints the enqueued modules in the head tag in block themes. Otherwise in the footer. -add_action( $modules_position, array( 'Gutenberg_Modules', 'print_enqueued_modules' ) ); - -// Prints the preloaded modules in the head tag in block themes. Otherwise in the footer. -add_action( $modules_position, array( 'Gutenberg_Modules', 'print_module_preloads' ) ); - -// Prints the script that loads the import map polyfill in the footer. -add_action( 'wp_head', array( 'Gutenberg_Modules', 'print_import_map_polyfill' ), 11 ); - -/** - * Add module fields from block metadata to WP_Block_Type settings. - * - * This filter allows us to register modules from block metadata and attach additional fields to - * WP_Block_Type instances. - * - * @param array $settings Array of determined settings for registering a block type. - * @param array $metadata Metadata provided for registering a block type. - */ -function gutenberg_filter_block_type_metadata_settings_register_modules( $settings, $metadata = null ) { - $module_fields = array( - 'viewModule' => 'view_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++ ) { - $processed_modules[] = gutenberg_register_block_module_id( - $metadata, - $metadata_field_name, - $index - ); - } - } else { - $processed_modules[] = gutenberg_register_block_module_id( - $metadata, - $metadata_field_name - ); - } - $settings[ $settings_field_name ] = $processed_modules; - } - } - - return $settings; -} - -add_filter( 'block_type_metadata_settings', 'gutenberg_filter_block_type_metadata_settings_register_modules', 10, 2 ); - -/** - * Enqueue modules associated with the block. - * - * @param string $block_content The block content. - * @param array $block The full block, including name and attributes. - * @param WP_Block $instance The block instance. - */ -function gutenberg_filter_render_block_enqueue_view_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 ) { - gutenberg_enqueue_module( $module_id ); - } - } - - return $block_content; -} - -add_filter( 'render_block', 'gutenberg_filter_render_block_enqueue_view_modules', 10, 3 ); - -/** - * Finds a module ID for the selected block metadata field. It detects - * when a path to file was provided and finds a corresponding asset file - * with details necessary to register the module under an automatically - * generated module ID. - * - * This is analogous to the `register_block_script_handle` in WordPress Core. - * - * @param array $metadata Block metadata. - * @param string $field_name Field name to pick from metadata. - * @param int $index Optional. Index of the script to register when multiple items passed. - * Default 0. - * @return string Module ID. - */ -function gutenberg_register_block_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 = gutenberg_generate_block_asset_module_id( $metadata['name'], $field_name, $index ); - $module_asset_path = wp_normalize_path( realpath( $module_asset_raw_path ) ); - - if ( empty( $module_asset_path ) ) { - _doing_it_wrong( - __FUNCTION__, - sprintf( - // This string is from WordPress Core. See `register_block_script_handle`. - // Translators: This is a translation from WordPress Core (default). No need to translate. - __( 'The asset file (%1$s) for the "%2$s" defined in "%3$s" block definition is missing.', 'default' ), - $module_asset_raw_path, - $field_name, - $metadata['name'] - ), - '6.5.0' - ); - return false; - } - - $module_path_norm = wp_normalize_path( realpath( $path . '/' . $module_path ) ); - $module_uri = get_block_asset_url( $module_path_norm ); - $module_asset = require $module_asset_path; - $module_dependencies = isset( $module_asset['dependencies'] ) ? $module_asset['dependencies'] : array(); - - gutenberg_register_module( - $module_id, - $module_uri, - $module_dependencies, - isset( $module_asset['version'] ) ? $module_asset['version'] : false - ); - - return $module_id; -} - -/** - * Generates the module ID for an asset based on the name of the block - * and the field name provided. - * - * This is analogous to the `generate_block_asset_handle` in WordPress Core. - * - * @param string $block_name Name of the block. - * @param string $field_name Name of the metadata field. - * @param int $index Optional. Index of the asset when multiple items passed. - * Default 0. - * @return string Generated module ID for the block's field. - */ -function gutenberg_generate_block_asset_module_id( $block_name, $field_name, $index = 0 ) { - if ( str_starts_with( $block_name, 'core/' ) ) { - $asset_handle = str_replace( 'core/', 'wp-block-', $block_name ); - if ( str_starts_with( $field_name, 'editor' ) ) { - $asset_handle .= '-editor'; - } - if ( str_starts_with( $field_name, 'view' ) ) { - $asset_handle .= '-view'; - } - if ( $index > 0 ) { - $asset_handle .= '-' . ( $index + 1 ); - } - return $asset_handle; - } - - $field_mappings = array( - 'viewModule' => 'view-module', - ); - $asset_handle = str_replace( '/', '-', $block_name ) . - '-' . $field_mappings[ $field_name ]; - if ( $index > 0 ) { - $asset_handle .= '-' . ( $index + 1 ); - } - return $asset_handle; -} - -function gutenberg_register_view_module_ids_rest_field() { - 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; - } - return array(); - }, - ) - ); -} - -add_action( 'rest_api_init', 'gutenberg_register_view_module_ids_rest_field' ); diff --git a/lib/experimental/script-modules.php b/lib/experimental/script-modules.php new file mode 100644 index 0000000000000..1f481a8098b20 --- /dev/null +++ b/lib/experimental/script-modules.php @@ -0,0 +1,234 @@ + 'view_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++ ) { + $processed_modules[] = gutenberg_register_block_module_id( + $metadata, + $metadata_field_name, + $index + ); + } + } else { + $processed_modules[] = gutenberg_register_block_module_id( + $metadata, + $metadata_field_name + ); + } + $settings[ $settings_field_name ] = $processed_modules; + } + } + + return $settings; +} + +add_filter( 'block_type_metadata_settings', 'gutenberg_filter_block_type_metadata_settings_register_modules', 10, 2 ); + +/** + * Enqueue modules associated with the block. + * + * @param string $block_content The block content. + * @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 ) { + $block_type = $block_instance->block_type; + + if ( ! empty( $block_type->view_module_ids ) ) { + foreach ( $block_type->view_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 ); + +/** + * Finds a module ID for the selected block metadata field. It detects + * when a path to file was provided and finds a corresponding asset file + * with details necessary to register the module under an automatically + * generated module ID. + * + * This is analogous to the `register_block_script_handle` in WordPress Core. + * + * @param array $metadata Block metadata. + * @param string $field_name Field name to pick from metadata. + * @param int $index Optional. Index of the script to register when multiple items passed. + * Default 0. + * @return string Module ID. + */ +function gutenberg_register_block_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 = gutenberg_generate_block_asset_module_id( $metadata['name'], $field_name, $index ); + $module_asset_path = wp_normalize_path( realpath( $module_asset_raw_path ) ); + + if ( empty( $module_asset_path ) ) { + _doing_it_wrong( + __FUNCTION__, + sprintf( + // This string is from WordPress Core. See `register_block_script_handle`. + // Translators: This is a translation from WordPress Core (default). No need to translate. + __( 'The asset file (%1$s) for the "%2$s" defined in "%3$s" block definition is missing.', 'default' ), + $module_asset_raw_path, + $field_name, + $metadata['name'] + ), + '6.5.0' + ); + return false; + } + + $module_path_norm = wp_normalize_path( realpath( $path . '/' . $module_path ) ); + $module_uri = get_block_asset_url( $module_path_norm ); + $module_asset = require $module_asset_path; + $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; +} + +/** + * Generates the module ID for an asset based on the name of the block + * and the field name provided. + * + * This is analogous to the `generate_block_asset_handle` in WordPress Core. + * + * @param string $block_name Name of the block. + * @param string $field_name Name of the metadata field. + * @param int $index Optional. Index of the asset when multiple items passed. + * Default 0. + * @return string Generated module ID for the block's field. + */ +function gutenberg_generate_block_asset_module_id( $block_name, $field_name, $index = 0 ) { + if ( str_starts_with( $block_name, 'core/' ) ) { + $asset_handle = str_replace( 'core/', 'wp-block-', $block_name ); + if ( str_starts_with( $field_name, 'editor' ) ) { + $asset_handle .= '-editor'; + } + if ( str_starts_with( $field_name, 'view' ) ) { + $asset_handle .= '-view'; + } + if ( $index > 0 ) { + $asset_handle .= '-' . ( $index + 1 ); + } + return $asset_handle; + } + + $field_mappings = array( + 'viewModule' => 'view-module', + ); + $asset_handle = str_replace( '/', '-', $block_name ) . + '-' . $field_mappings[ $field_name ]; + if ( $index > 0 ) { + $asset_handle .= '-' . ( $index + 1 ); + } + return $asset_handle; +} + +/** + * 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 + * lists the script module IDs for any script modules associated with the + * block's viewModule(s) key. + * + * @since 6.5.0 + */ +function gutenberg_register_view_module_ids_rest_field() { + 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; + } + return array(); + }, + ) + ); +} + +add_action( 'rest_api_init', 'gutenberg_register_view_module_ids_rest_field' ); + +/** + * Registers the module if no module with that module identifier has already + * been registered. + * + * @param string $module_identifier The identifier of the module. Should be unique. It will be used in the final import map. + * @param string $src Full URL of the module, or path of the script relative to the WordPress root directory. + * @param array $dependencies Optional. An array of module identifiers of the dependencies of this module. The dependencies can be strings or arrays. If they are arrays, they need an `id` key with the module identifier, and can contain an `import` key with either `static` or `dynamic`. By default, dependencies that don't contain an import are considered static. + * @param string|false|null $version Optional. String specifying module version number. Defaults to false. It is added to the URL as a query string for cache busting purposes. If $version is set to false, the version number is the currently installed WordPress version. If $version is set to null, no version is added. + * @deprecated 17.6.0 gutenberg_register_module is deprecated. Please use wp_register_script_module instead. + */ +function gutenberg_register_module( $module_identifier, $src = '', $dependencies = array(), $version = false ) { + _deprecated_function( __FUNCTION__, 'Gutenberg 17.6.0', 'wp_register_script_module' ); + wp_script_modules()->register( $module_identifier, $src, $dependencies, $version ); +} + +/** + * Marks the module to be enqueued in the page. + * + * @param string $module_identifier The identifier of the module. + * @deprecated 17.6.0 gutenberg_enqueue_module is deprecated. Please use wp_enqueue_script_module instead. + */ +function gutenberg_enqueue_module( $module_identifier ) { + _deprecated_function( __FUNCTION__, 'Gutenberg 17.6.0', 'wp_enqueue_script_module' ); + wp_script_modules()->enqueue( $module_identifier ); +} + +/** + * Unmarks the module so it is not longer enqueued in the page. + * + * @param string $module_identifier The identifier of the module. + * @deprecated 17.6.0 gutenberg_dequeue_module is deprecated. Please use wp_dequeue_script_module instead. + */ +function gutenberg_dequeue_module( $module_identifier ) { + _deprecated_function( __FUNCTION__, 'Gutenberg 17.6.0', 'wp_dequeue_script_module' ); + wp_script_modules()->dequeue( $module_identifier ); +} diff --git a/lib/load.php b/lib/load.php index 2dd33962e355b..73e6824ab0c9e 100644 --- a/lib/load.php +++ b/lib/load.php @@ -108,6 +108,8 @@ function gutenberg_is_experiment_enabled( $name ) { require __DIR__ . '/compat/wordpress-6.5/block-patterns.php'; require __DIR__ . '/compat/wordpress-6.5/class-wp-navigation-block-renderer.php'; require __DIR__ . '/compat/wordpress-6.5/kses.php'; +require __DIR__ . '/compat/wordpress-6.5/class-wp-script-modules.php'; +require __DIR__ . '/compat/wordpress-6.5/scripts-modules.php'; // Experimental features. require __DIR__ . '/experimental/block-editor-settings-mobile.php'; @@ -116,6 +118,7 @@ function gutenberg_is_experiment_enabled( $name ) { require __DIR__ . '/experimental/kses.php'; require __DIR__ . '/experimental/l10n.php'; require __DIR__ . '/experimental/synchronization.php'; +require __DIR__ . '/experimental/script-modules.php'; if ( gutenberg_is_experiment_enabled( 'gutenberg-no-tinymce' ) ) { require __DIR__ . '/experimental/disable-tinymce.php'; @@ -134,8 +137,6 @@ function gutenberg_is_experiment_enabled( $name ) { require __DIR__ . '/experimental/interactivity-api/directives/wp-text.php'; require __DIR__ . '/experimental/interactivity-api/directives/wp-interactive.php'; -require __DIR__ . '/experimental/modules/class-gutenberg-modules.php'; - // Fonts API / Font Face. remove_action( 'plugins_loaded', '_wp_theme_json_webfonts_handler' ); // Turns off WordPress 6.0's stopgap handler. diff --git a/packages/block-library/src/file/block.json b/packages/block-library/src/file/block.json index 9dc6677e4adce..fd5da67d284f4 100644 --- a/packages/block-library/src/file/block.json +++ b/packages/block-library/src/file/block.json @@ -72,7 +72,6 @@ }, "interactivity": true }, - "viewScript": "file:./view.min.js", "editorStyle": "wp-block-file-editor", "style": "wp-block-file" } diff --git a/packages/block-library/src/file/index.php b/packages/block-library/src/file/index.php index 5910a63e6cf18..24eaff8bac622 100644 --- a/packages/block-library/src/file/index.php +++ b/packages/block-library/src/file/index.php @@ -14,35 +14,8 @@ * * @return string Returns the block content. */ -function render_block_core_file( $attributes, $content, $block ) { - $is_gutenberg_plugin = defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN; - $should_load_view_script = ! empty( $attributes['displayPreview'] ); - $view_js_file = 'wp-block-file-view'; - $script_handles = $block->block_type->view_script_handles; - - if ( $is_gutenberg_plugin ) { - if ( $should_load_view_script ) { - gutenberg_enqueue_module( '@wordpress/block-library/file-block' ); - } - // Remove the view script because we are using the module. - $block->block_type->view_script_handles = array_diff( $script_handles, array( $view_js_file ) ); - } else { - // If the script already exists, there is no point in removing it from viewScript. - if ( ! wp_script_is( $view_js_file ) ) { - - // If the script is not needed, and it is still in the `view_script_handles`, remove it. - if ( ! $should_load_view_script && in_array( $view_js_file, $script_handles, true ) ) { - $block->block_type->view_script_handles = array_diff( $script_handles, array( $view_js_file ) ); - } - // If the script is needed, but it was previously removed, add it again. - if ( $should_load_view_script && ! in_array( $view_js_file, $script_handles, true ) ) { - $block->block_type->view_script_handles = array_merge( $script_handles, array( $view_js_file ) ); - } - } - } - +function render_block_core_file( $attributes, $content ) { // Update object's aria-label attribute if present in block HTML. - // Match an aria-label attribute from an object tag. $pattern = '@aria-label="(?[^"]+)?")@i'; $content = preg_replace_callback( @@ -63,8 +36,10 @@ static function ( $matches ) { $content ); - // If it uses the Interactivity API, add the directives. - if ( $should_load_view_script ) { + // If it's interactive, enqueue the script module and add the directives. + if ( ! empty( $attributes['displayPreview'] ) ) { + wp_enqueue_script_module( '@wordpress/block-library/file-block' ); + $processor = new WP_HTML_Tag_Processor( $content ); $processor->next_tag(); $processor->set_attribute( 'data-wp-interactive', '{"namespace":"core/file"}' ); @@ -77,25 +52,6 @@ static function ( $matches ) { return $content; } -/** - * Ensure that the view script has the `wp-interactivity` dependency. - * - * @since 6.4.0 - * - * @global WP_Scripts $wp_scripts - */ -function block_core_file_ensure_interactivity_dependency() { - global $wp_scripts; - if ( - isset( $wp_scripts->registered['wp-block-file-view'] ) && - ! in_array( 'wp-interactivity', $wp_scripts->registered['wp-block-file-view']->deps, true ) - ) { - $wp_scripts->registered['wp-block-file-view']->deps[] = 'wp-interactivity'; - } -} - -add_action( 'wp_print_scripts', 'block_core_file_ensure_interactivity_dependency' ); - /** * Registers the `core/file` block on server. */ @@ -107,13 +63,11 @@ function register_block_core_file() { ) ); - if ( defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN ) { - gutenberg_register_module( - '@wordpress/block-library/file-block', - gutenberg_url( '/build/interactivity/file.min.js' ), - array( '@wordpress/interactivity' ), - defined( 'GUTENBERG_VERSION' ) ? GUTENBERG_VERSION : get_bloginfo( 'version' ) - ); - } + wp_register_script_module( + '@wordpress/block-library/file-block', + gutenberg_url( '/build/interactivity/file.min.js' ), + array( '@wordpress/interactivity' ), + defined( 'GUTENBERG_VERSION' ) ? GUTENBERG_VERSION : get_bloginfo( 'version' ) + ); } add_action( 'init', 'register_block_core_file' ); diff --git a/packages/block-library/src/image/block.json b/packages/block-library/src/image/block.json index a9357d28815b6..d60bcadf0eec7 100644 --- a/packages/block-library/src/image/block.json +++ b/packages/block-library/src/image/block.json @@ -134,6 +134,5 @@ { "name": "rounded", "label": "Rounded" } ], "editorStyle": "wp-block-image-editor", - "style": "wp-block-image", - "viewScript": "file:./view.min.js" + "style": "wp-block-image" } diff --git a/packages/block-library/src/image/index.php b/packages/block-library/src/image/index.php index add8e5989ab7d..3297c57d9eab3 100644 --- a/packages/block-library/src/image/index.php +++ b/packages/block-library/src/image/index.php @@ -37,10 +37,6 @@ function render_block_core_image( $attributes, $content, $block ) { $link_destination = isset( $attributes['linkDestination'] ) ? $attributes['linkDestination'] : 'none'; $lightbox_settings = block_core_image_get_lightbox_settings( $block->parsed_block ); - $is_gutenberg_plugin = defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN; - $view_js_file_handle = 'wp-block-image-view'; - $script_handles = $block->block_type->view_script_handles; - /* * If the lightbox is enabled and the image is not linked, add the filter * and the JavaScript view file. @@ -51,34 +47,22 @@ function render_block_core_image( $attributes, $content, $block ) { isset( $lightbox_settings['enabled'] ) && true === $lightbox_settings['enabled'] ) { - if ( $is_gutenberg_plugin ) { - gutenberg_enqueue_module( '@wordpress/block-library/image' ); - // Remove the view script because we are using the module. - $block->block_type->view_script_handles = array_diff( $script_handles, array( $view_js_file_handle ) ); - } elseif ( ! in_array( $view_js_file_handle, $script_handles, true ) ) { - $block->block_type->view_script_handles = array_merge( $script_handles, array( $view_js_file_handle ) ); - } + wp_enqueue_script_module( '@wordpress/block-library/image' ); /* - * This render needs to happen in a filter with priority 15 to ensure - * that it runs after the duotone filter and that duotone styles are - * applied to the image in the lightbox. We also need to ensure that the - * lightbox works with any plugins that might use filters as well. We - * can consider removing this in the future if the way the blocks are - * rendered changes, or if a new kind of filter is introduced. + * This render needs to happen in a filter with priority 15 to ensure that + * it runs after the duotone filter and that duotone styles are applied to + * the image in the lightbox. Lightbox has to work with any plugins that + * might use filters as well. Removing this can be considered in the + * future if the way the blocks are rendered changes, or if a + * new kind of filter is introduced. */ add_filter( 'render_block_core/image', 'block_core_image_render_lightbox', 15, 2 ); } else { /* - * Remove the filter and the JavaScript view file if previously added by - * other Image blocks. + * Remove the filter if previously added by other Image blocks. */ remove_filter( 'render_block_core/image', 'block_core_image_render_lightbox', 15 ); - - // If the script is not needed, and it is still in the `view_script_handles`, remove it. - if ( in_array( $view_js_file_handle, $script_handles, true ) ) { - $block->block_type->view_script_handles = array_diff( $script_handles, array( $view_js_file_handle ) ); - } } return $processor->get_updated_html(); @@ -328,25 +312,6 @@ class="lightbox-trigger" return str_replace( '', $lightbox_html . '', $body_content ); } -/** - * Ensures that the view script has the `wp-interactivity` dependency. - * - * @since 6.4.0 - * - * @global WP_Scripts $wp_scripts - */ -function block_core_image_ensure_interactivity_dependency() { - global $wp_scripts; - if ( - isset( $wp_scripts->registered['wp-block-image-view'] ) && - ! in_array( 'wp-interactivity', $wp_scripts->registered['wp-block-image-view']->deps, true ) - ) { - $wp_scripts->registered['wp-block-image-view']->deps[] = 'wp-interactivity'; - } -} - -add_action( 'wp_print_scripts', 'block_core_image_ensure_interactivity_dependency' ); - /** * Registers the `core/image` block on server. */ @@ -358,13 +323,11 @@ function register_block_core_image() { ) ); - if ( defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN ) { - gutenberg_register_module( - '@wordpress/block-library/image', - gutenberg_url( '/build/interactivity/image.min.js' ), - array( '@wordpress/interactivity' ), - defined( 'GUTENBERG_VERSION' ) ? GUTENBERG_VERSION : get_bloginfo( 'version' ) - ); - } + wp_register_script_module( + '@wordpress/block-library/image', + gutenberg_url( '/build/interactivity/image.min.js' ), + array( '@wordpress/interactivity' ), + defined( 'GUTENBERG_VERSION' ) ? GUTENBERG_VERSION : get_bloginfo( 'version' ) + ); } add_action( 'init', 'register_block_core_image' ); diff --git a/packages/block-library/src/navigation/block.json b/packages/block-library/src/navigation/block.json index 9ec919ae38d1f..36817a5e1c35b 100644 --- a/packages/block-library/src/navigation/block.json +++ b/packages/block-library/src/navigation/block.json @@ -136,7 +136,6 @@ "interactivity": true, "renaming": false }, - "viewScript": "file:./view.min.js", "editorStyle": "wp-block-navigation-editor", "style": "wp-block-navigation" } diff --git a/packages/block-library/src/navigation/index.php b/packages/block-library/src/navigation/index.php index 3af85afd92522..29546f22c69e3 100644 --- a/packages/block-library/src/navigation/index.php +++ b/packages/block-library/src/navigation/index.php @@ -427,14 +427,12 @@ function register_block_core_navigation() { ) ); - if ( defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN ) { - gutenberg_register_module( - '@wordpress/block-library/navigation-block', - gutenberg_url( '/build/interactivity/navigation.min.js' ), - array( '@wordpress/interactivity' ), - defined( 'GUTENBERG_VERSION' ) ? GUTENBERG_VERSION : get_bloginfo( 'version' ) - ); - } + wp_register_script_module( + '@wordpress/block-library/navigation-block', + gutenberg_url( '/build/interactivity/navigation.min.js' ), + array( '@wordpress/interactivity' ), + defined( 'GUTENBERG_VERSION' ) ? GUTENBERG_VERSION : get_bloginfo( 'version' ) + ); } add_action( 'init', 'register_block_core_navigation' ); @@ -473,25 +471,6 @@ function block_core_navigation_typographic_presets_backcompatibility( $parsed_bl add_filter( 'render_block_data', 'block_core_navigation_typographic_presets_backcompatibility' ); -/** - * Ensure that the view script has the `wp-interactivity` dependency. - * - * @since 6.4.0 - * - * @global WP_Scripts $wp_scripts - */ -function block_core_navigation_ensure_interactivity_dependency() { - global $wp_scripts; - if ( - isset( $wp_scripts->registered['wp-block-navigation-view'] ) && - ! in_array( 'wp-interactivity', $wp_scripts->registered['wp-block-navigation-view']->deps, true ) - ) { - $wp_scripts->registered['wp-block-navigation-view']->deps[] = 'wp-interactivity'; - } -} - -add_action( 'wp_print_scripts', 'block_core_navigation_ensure_interactivity_dependency' ); - /** * Turns menu item data into a nested array of parsed blocks * diff --git a/packages/block-library/src/query/block.json b/packages/block-library/src/query/block.json index d30eccf376579..6189f6f0189b7 100644 --- a/packages/block-library/src/query/block.json +++ b/packages/block-library/src/query/block.json @@ -52,6 +52,5 @@ "layout": true }, "editorStyle": "wp-block-query-editor", - "style": "wp-block-query", - "viewScript": "file:./view.min.js" + "style": "wp-block-query" } diff --git a/packages/block-library/src/query/index.php b/packages/block-library/src/query/index.php index 75b5218364d7b..f40d9df2fb06b 100644 --- a/packages/block-library/src/query/index.php +++ b/packages/block-library/src/query/index.php @@ -17,7 +17,13 @@ * @return string Returns the modified output of the query block. */ function render_block_core_query( $attributes, $content, $block ) { - if ( $attributes['enhancedPagination'] && isset( $attributes['queryId'] ) ) { + $is_interactive = isset( $attributes['enhancedPagination'] ) && true === $attributes['enhancedPagination'] && isset( $attributes['queryId'] ); + + // Enqueue the script module and add the necessary directives if the block is + // interactive. + if ( $is_interactive ) { + wp_enqueue_script_module( '@wordpress/block-library/query' ); + $p = new WP_HTML_Tag_Processor( $content ); if ( $p->next_tag() ) { // Add the necessary directives. @@ -63,43 +69,17 @@ class="wp-block-query__enhanced-pagination-animation" } } - $is_gutenberg_plugin = defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN; - $should_load_view_script = $attributes['enhancedPagination'] && isset( $attributes['queryId'] ); - $view_asset = 'wp-block-query-view'; - $script_handles = $block->block_type->view_script_handles; - - if ( $is_gutenberg_plugin ) { - if ( $should_load_view_script ) { - gutenberg_enqueue_module( '@wordpress/block-library/query' ); - } - // Remove the view script because we are using the module. - $block->block_type->view_script_handles = array_diff( $script_handles, array( $view_asset ) ); - } else { - if ( ! wp_script_is( $view_asset ) ) { - // If the script is not needed, and it is still in the `view_script_handles`, remove it. - if ( ! $should_load_view_script && in_array( $view_asset, $script_handles, true ) - ) { - $block->block_type->view_script_handles = array_diff( $script_handles, array( $view_asset ) ); - } - // If the script is needed, but it was previously removed, add it again. - if ( $should_load_view_script && ! in_array( $view_asset, $script_handles, true ) ) { - $block->block_type->view_script_handles = array_merge( $script_handles, array( $view_asset ) ); - } - } - } - + // Add the styles to the block type if the block is interactive and remove + // them if it's not. $style_asset = 'wp-block-query'; if ( ! wp_style_is( $style_asset ) ) { $style_handles = $block->block_type->style_handles; // If the styles are not needed, and they are still in the `style_handles`, remove them. - if ( - ( ! $attributes['enhancedPagination'] || ! isset( $attributes['queryId'] ) ) - && in_array( $style_asset, $style_handles, true ) - ) { + if ( ! $is_interactive && in_array( $style_asset, $style_handles, true ) ) { $block->block_type->style_handles = array_diff( $style_handles, array( $style_asset ) ); } // If the styles are needed, but they were previously removed, add them again. - if ( $attributes['enhancedPagination'] && isset( $attributes['queryId'] ) && ! in_array( $style_asset, $style_handles, true ) ) { + if ( $is_interactive && ! in_array( $style_asset, $style_handles, true ) ) { $block->block_type->style_handles = array_merge( $style_handles, array( $style_asset ) ); } } @@ -107,25 +87,6 @@ class="wp-block-query__enhanced-pagination-animation" return $content; } -/** - * Ensure that the view script has the `wp-interactivity` dependency. - * - * @since 6.4.0 - * - * @global WP_Scripts $wp_scripts - */ -function block_core_query_ensure_interactivity_dependency() { - global $wp_scripts; - if ( - isset( $wp_scripts->registered['wp-block-query-view'] ) && - ! in_array( 'wp-interactivity', $wp_scripts->registered['wp-block-query-view']->deps, true ) - ) { - $wp_scripts->registered['wp-block-query-view']->deps[] = 'wp-interactivity'; - } -} - -add_action( 'wp_print_scripts', 'block_core_query_ensure_interactivity_dependency' ); - /** * Registers the `core/query` block on the server. */ @@ -137,14 +98,12 @@ function register_block_core_query() { ) ); - if ( defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN ) { - gutenberg_register_module( - '@wordpress/block-library/query', - '/wp-content/plugins/gutenberg/build/interactivity/query.min.js', - array( '@wordpress/interactivity' ), - defined( 'GUTENBERG_VERSION' ) ? GUTENBERG_VERSION : get_bloginfo( 'version' ) - ); - } + wp_register_script_module( + '@wordpress/block-library/query', + '/wp-content/plugins/gutenberg/build/interactivity/query.min.js', + array( '@wordpress/interactivity' ), + defined( 'GUTENBERG_VERSION' ) ? GUTENBERG_VERSION : get_bloginfo( 'version' ) + ); } add_action( 'init', 'register_block_core_query' ); @@ -164,14 +123,10 @@ function block_core_query_disable_enhanced_pagination( $parsed_block ) { static $dirty_enhanced_queries = array(); static $render_query_callback = null; - $block_name = $parsed_block['blockName']; + $is_interactive = isset( $parsed_block['attrs']['enhancedPagination'] ) && true === $parsed_block['attrs']['enhancedPagination'] && isset( $parsed_block['attrs']['queryId'] ); + $block_name = $parsed_block['blockName']; - if ( - 'core/query' === $block_name && - isset( $parsed_block['attrs']['enhancedPagination'] ) && - true === $parsed_block['attrs']['enhancedPagination'] && - isset( $parsed_block['attrs']['queryId'] ) - ) { + if ( 'core/query' === $block_name && $is_interactive ) { $enhanced_query_stack[] = $parsed_block['attrs']['queryId']; if ( ! isset( $render_query_callback ) ) { @@ -186,12 +141,9 @@ function block_core_query_disable_enhanced_pagination( $parsed_block ) { * @return string Returns the modified output of the query block. */ $render_query_callback = static function ( $content, $block ) use ( &$enhanced_query_stack, &$dirty_enhanced_queries, &$render_query_callback ) { - $has_enhanced_pagination = - isset( $block['attrs']['enhancedPagination'] ) && - true === $block['attrs']['enhancedPagination'] && - isset( $block['attrs']['queryId'] ); + $is_interactive = isset( $block['attrs']['enhancedPagination'] ) && true === $block['attrs']['enhancedPagination'] && isset( $block['attrs']['queryId'] ); - if ( ! $has_enhanced_pagination ) { + if ( ! $is_interactive ) { return $content; } diff --git a/packages/block-library/src/search/block.json b/packages/block-library/src/search/block.json index 15531475adc9a..8d5e208045068 100644 --- a/packages/block-library/src/search/block.json +++ b/packages/block-library/src/search/block.json @@ -87,7 +87,6 @@ }, "html": false }, - "viewScript": "file:./view.min.js", "editorStyle": "wp-block-search-editor", "style": "wp-block-search" } diff --git a/packages/block-library/src/search/index.php b/packages/block-library/src/search/index.php index ae6ddb1c4fb37..266eb93ca82a4 100644 --- a/packages/block-library/src/search/index.php +++ b/packages/block-library/src/search/index.php @@ -16,7 +16,7 @@ * * @return string The search block markup. */ -function render_block_core_search( $attributes, $content, $block ) { +function render_block_core_search( $attributes ) { // Older versions of the Search block defaulted the label and buttonText // attributes to `__( 'Search' )` meaning that many posts contain ``. Support these by defaulting an undefined label and @@ -77,39 +77,19 @@ function render_block_core_search( $attributes, $content, $block ) { $input->set_attribute( 'value', get_search_query() ); $input->set_attribute( 'placeholder', $attributes['placeholder'] ); + // If it's interactive, enqueue the script module and add the directives. $is_expandable_searchfield = 'button-only' === $button_position; if ( $is_expandable_searchfield ) { + wp_enqueue_script_module( '@wordpress/block-library/search-block' ); + $input->set_attribute( 'data-wp-bind--aria-hidden', '!context.isSearchInputVisible' ); $input->set_attribute( 'data-wp-bind--tabindex', 'state.tabindex' ); - // Adding these attributes manually is needed until the Interactivity API SSR logic is added to core. + + // Adding these attributes manually is needed until the Interactivity API + // SSR logic is added to core. $input->set_attribute( 'aria-hidden', 'true' ); $input->set_attribute( 'tabindex', '-1' ); } - - $is_gutenberg_plugin = defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN; - $script_handles = $block->block_type->view_script_handles; - $view_js_file = 'wp-block-search-view'; - - if ( $is_gutenberg_plugin ) { - if ( $is_expandable_searchfield ) { - gutenberg_enqueue_module( '@wordpress/block-library/search-block' ); - } - // Remove the view script because we are using the module. - $block->block_type->view_script_handles = array_diff( $script_handles, array( $view_js_file ) ); - } else { - // If the script already exists, there is no point in removing it from viewScript. - if ( ! wp_script_is( $view_js_file ) ) { - - // If the script is not needed, and it is still in the `view_script_handles`, remove it. - if ( ! $is_expandable_searchfield && in_array( $view_js_file, $script_handles, true ) ) { - $block->block_type->view_script_handles = array_diff( $script_handles, array( $view_js_file ) ); - } - // If the script is needed, but it was previously removed, add it again. - if ( $is_expandable_searchfield && ! in_array( $view_js_file, $script_handles, true ) ) { - $block->block_type->view_script_handles = array_merge( $script_handles, array( $view_js_file ) ); - } - } - } } if ( count( $query_params ) > 0 ) { @@ -159,7 +139,9 @@ function render_block_core_search( $attributes, $content, $block ) { $button->set_attribute( 'data-wp-bind--aria-expanded', 'context.isSearchInputVisible' ); $button->set_attribute( 'data-wp-bind--type', 'state.type' ); $button->set_attribute( 'data-wp-on--click', 'actions.openSearchInput' ); - // Adding these attributes manually is needed until the Interactivity API SSR logic is added to core. + + // Adding these attributes manually is needed until the Interactivity + // API SSR logic is added to core. $button->set_attribute( 'aria-label', __( 'Expand search field' ) ); $button->set_attribute( 'aria-controls', 'wp-block-search__input-' . $input_id ); $button->set_attribute( 'aria-expanded', 'false' ); @@ -181,6 +163,8 @@ function render_block_core_search( $attributes, $content, $block ) { array( 'class' => $classnames ) ); $form_directives = ''; + + // If it's interactive, add the directives. if ( $is_expandable_searchfield ) { $aria_label_expanded = __( 'Submit Search' ); $aria_label_collapsed = __( 'Expand search field' ); @@ -213,14 +197,12 @@ function register_block_core_search() { ) ); - if ( defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN ) { - gutenberg_register_module( - '@wordpress/block-library/search-block', - gutenberg_url( '/build/interactivity/search.min.js' ), - array( '@wordpress/interactivity' ), - defined( 'GUTENBERG_VERSION' ) ? GUTENBERG_VERSION : get_bloginfo( 'version' ) - ); - } + wp_register_script_module( + '@wordpress/block-library/search-block', + gutenberg_url( '/build/interactivity/search.min.js' ), + array( '@wordpress/interactivity' ), + defined( 'GUTENBERG_VERSION' ) ? GUTENBERG_VERSION : get_bloginfo( 'version' ) + ); } add_action( 'init', 'register_block_core_search' ); diff --git a/packages/dependency-extraction-webpack-plugin/README.md b/packages/dependency-extraction-webpack-plugin/README.md index 6031a1d5f2568..817b3673351e5 100644 --- a/packages/dependency-extraction-webpack-plugin/README.md +++ b/packages/dependency-extraction-webpack-plugin/README.md @@ -94,14 +94,14 @@ By default, the following module requests are handled: This plugin is compatible with `externals`, but they may conflict. For example, adding `{ externals: { '@wordpress/blob': 'wp.blob' } }` to webpack configuration will effectively hide the `@wordpress/blob` module from the plugin and it will not be included in dependency lists. -### Behavior with modules +### Behavior with script modules -**Warning:** Modules support is considered experimental at this time. +**Warning:** Script modules support is considered experimental at this time. This section describes the behavior of this package to bundle ECMAScript modules and generate asset -files suitable for use with the WordPress Modules API. +files suitable for use with the WordPress Script Modules API. -Some of this plugin's options change, and webpack requires configuration to output modules. Refer to +Some of this plugin's options change, and webpack requires configuration to output script modules. Refer to [webpack's documentation](https://webpack.js.org/configuration/output/#outputmodule) for up-to-date details. ```js @@ -118,7 +118,7 @@ const webpackConfig = { plugin.constructor.name !== 'DependencyExtractionWebpackPlugin' ), new DependencyExtractionWebpackPlugin( { - // With modules, we use `requestToExternalModule`: + // With modules, use `requestToExternalModule`: requestToExternalModule( request ) { if ( request === 'my-registered-module' ) { return request; @@ -129,7 +129,7 @@ const webpackConfig = { }; ``` -Each entry point in the webpack bundle will include an asset file that declares the WordPress module dependencies that should be enqueued. This file also contains the unique version hash calculated based on the file content. +Each entry point in the webpack bundle will include an asset file that declares the WordPress script module dependencies that should be enqueued. This file also contains the unique version hash calculated based on the file content. For example: @@ -144,15 +144,15 @@ import { store, getContext } from '@wordpress/interactivity'; array('@wordpress/interactivity'), 'version' => 'dd4c2dc50d046ed9d4c063a7ca95702f'); ``` -By default, the following module requests are handled: +By default, the following script module requests are handled: | Request | | ---------------------------- | | `@wordpress/interactivity ` | -(`@wordpress/interactivity` is currently the only available WordPress module.) +(`@wordpress/interactivity` is currently the only available WordPress script module.) -**Note:** This plugin overlaps with the functionality provided by [webpack `externals`](https://webpack.js.org/configuration/externals). This plugin is intended to extract module handles from bundle compilation so that a list of module dependencies does not need to be manually maintained. If you don't need to extract a list of module dependencies, use the `externals` option directly. +**Note:** This plugin overlaps with the functionality provided by [webpack `externals`](https://webpack.js.org/configuration/externals). This plugin is intended to extract script module identifiers from bundle compilation so that a list of script module dependencies does not need to be manually maintained. If you don't need to extract a list of script module dependencies, use the `externals` option directly. This plugin is compatible with `externals`, but they may conflict. For example, adding `{ externals: { '@wordpress/blob': 'wp.blob' } }` to webpack configuration will effectively hide the `@wordpress/blob` module from the plugin and it will not be included in dependency lists. @@ -210,7 +210,7 @@ Pass `useDefaults: false` to disable the default request handling. Force `wp-polyfill` to be included in each entry point's dependency list. This would be the same as adding `import '@wordpress/polyfill';` to each entry point. -**Note**: This option is not available with modules. +**Note**: This option is not available with script modules. ##### `externalizedReport` @@ -222,7 +222,7 @@ You can provide a filename, or set it to `true` to report to a default `external ##### `requestToExternal` -**Note**: This option is not available with modules. See [`requestToExternalModule`](#requestToExternalModule) for module usage. +**Note**: This option is not available with script modules. See [`requestToExternalModule`](#requestToExternalModule) for module usage. - Type: function @@ -253,11 +253,11 @@ module.exports = { ##### `requestToExternalModule` -**Note**: This option is only available with modules. See [`requestToExternal`](#requestToExternal) for script usage. +**Note**: This option is only available with script modules. See [`requestToExternal`](#requestToExternal) for script usage. - Type: function -`requestToExternalModule` allows the module handling to be customized. The function should accept a module request string and may return a string representing the module to use. Often, the module will have the same name. +`requestToExternalModule` allows the script module handling to be customized. The function should accept a script module request string and may return a string representing the script module to use. Often, the script module will have the same name. `requestToExternalModule` provided via configuration has precedence over default external handling. Unhandled requests will be handled by the default unless `useDefaults` is set to `false`. @@ -265,9 +265,9 @@ module.exports = { /** * Externalize 'my-module' * - * @param {string} request Requested module + * @param {string} request Requested script module * - * @return {(string|boolean|undefined)} Module ID + * @return {(string|boolean|undefined)} Script module ID */ function requestToExternalModule( request ) { // Handle imports like `import myModule from 'my-module'` @@ -276,7 +276,7 @@ function requestToExternalModule( request ) { return 'myModule'; } - // If the Module ID in source is the same as the external module, we can return `true`. + // If the script module ID in source is the same as the external script module, `true` can be returned. return request === 'external-module-id-no-change-required'; } @@ -289,7 +289,7 @@ module.exports = { ##### `requestToHandle` -**Note**: This option is not available with modules. It has no corresponding module configuration. +**Note**: This option is not available with script modules. It has no corresponding module configuration. - Type: function @@ -343,7 +343,7 @@ $script_url = plugins_url( $script_path, __FILE__ ); wp_enqueue_script( 'script', $script_url, $script_asset['dependencies'], $script_asset['version'] ); ``` -Or with modules (the Module API is not yet stable): +Or with modules (the Script Module API is only available in WordPress > 6.5): ```php $module_path = 'path/to/module.js'; @@ -352,8 +352,8 @@ $module_asset = file_exists( $module_asset_path ) ? require( $module_asset_path ) : array( 'dependencies' => array(), 'version' => filemtime( $module_path ) ); $module_url = plugins_url( $module_path, __FILE__ ); -wp_register_module( 'my-module', $module_url, $module_asset['dependencies'], $module_asset['version'] ); -wp_enqueue_module( 'my-module' ); +wp_register_script_module( 'my-module', $module_url, $module_asset['dependencies'], $module_asset['version'] ); +wp_enqueue_script_module( 'my-module' ); ``` ## Contributing to this package diff --git a/packages/e2e-tests/plugins/interactive-blocks.php b/packages/e2e-tests/plugins/interactive-blocks.php index 05b591ecce378..fa93a64fe210e 100644 --- a/packages/e2e-tests/plugins/interactive-blocks.php +++ b/packages/e2e-tests/plugins/interactive-blocks.php @@ -21,12 +21,11 @@ function () { $view_file = plugin_dir_url( $block_folder ) . $name . '/' . 'view.js'; - gutenberg_register_module( + wp_register_script_module( $name . '-view', $view_file, array( '@wordpress/interactivity' ), - filemtime( $view_file ), - true + filemtime( $view_file ) ); register_block_type_from_metadata( $block_folder ); diff --git a/packages/e2e-tests/plugins/interactive-blocks/directive-bind/render.php b/packages/e2e-tests/plugins/interactive-blocks/directive-bind/render.php index efa62c3a18b7e..24e3c9343c115 100644 --- a/packages/e2e-tests/plugins/interactive-blocks/directive-bind/render.php +++ b/packages/e2e-tests/plugins/interactive-blocks/directive-bind/render.php @@ -5,7 +5,7 @@ * @package gutenberg-test-interactive-blocks */ -gutenberg_enqueue_module( 'directive-bind-view' ); +wp_enqueue_script_module( 'directive-bind-view' ); ?>
diff --git a/packages/e2e-tests/plugins/interactive-blocks/directive-body/render.php b/packages/e2e-tests/plugins/interactive-blocks/directive-body/render.php index 16178815c2486..31d5deb57eb11 100644 --- a/packages/e2e-tests/plugins/interactive-blocks/directive-body/render.php +++ b/packages/e2e-tests/plugins/interactive-blocks/directive-body/render.php @@ -5,7 +5,7 @@ * @package gutenberg-test-interactive-blocks */ -gutenberg_enqueue_module( 'directive-body-view' ); +wp_enqueue_script_module( 'directive-body-view' ); ?>
diff --git a/packages/e2e-tests/plugins/interactive-blocks/directive-context/render.php b/packages/e2e-tests/plugins/interactive-blocks/directive-context/render.php index fe9a6c4f85a16..b60be101a42d1 100644 --- a/packages/e2e-tests/plugins/interactive-blocks/directive-context/render.php +++ b/packages/e2e-tests/plugins/interactive-blocks/directive-context/render.php @@ -5,7 +5,7 @@ * @package gutenberg-test-interactive-blocks */ -gutenberg_enqueue_module( 'directive-context-view' ); +wp_enqueue_script_module( 'directive-context-view' ); ?>
diff --git a/packages/e2e-tests/plugins/interactive-blocks/directive-each/render.php b/packages/e2e-tests/plugins/interactive-blocks/directive-each/render.php index b9deee18abe57..1a48611d51ea5 100644 --- a/packages/e2e-tests/plugins/interactive-blocks/directive-each/render.php +++ b/packages/e2e-tests/plugins/interactive-blocks/directive-each/render.php @@ -5,7 +5,7 @@ * @package gutenberg-test-interactive-blocks */ -gutenberg_enqueue_module( 'directive-each-view' ); +wp_enqueue_script_module( 'directive-each-view' ); ?>
diff --git a/packages/e2e-tests/plugins/interactive-blocks/directive-init/render.php b/packages/e2e-tests/plugins/interactive-blocks/directive-init/render.php index 6ee0115ff05ba..e94c3032d9b70 100644 --- a/packages/e2e-tests/plugins/interactive-blocks/directive-init/render.php +++ b/packages/e2e-tests/plugins/interactive-blocks/directive-init/render.php @@ -5,7 +5,7 @@ * @package gutenberg-test-interactive-blocks */ -gutenberg_enqueue_module( 'directive-init-view' ); +wp_enqueue_script_module( 'directive-init-view' ); ?>
diff --git a/packages/e2e-tests/plugins/interactive-blocks/directive-key/render.php b/packages/e2e-tests/plugins/interactive-blocks/directive-key/render.php index 1a5f57b526fbf..d28002c137792 100644 --- a/packages/e2e-tests/plugins/interactive-blocks/directive-key/render.php +++ b/packages/e2e-tests/plugins/interactive-blocks/directive-key/render.php @@ -5,7 +5,7 @@ * @package gutenberg-test-interactive-blocks */ -gutenberg_enqueue_module( 'directive-key-view' ); +wp_enqueue_script_module( 'directive-key-view' ); ?>
diff --git a/packages/e2e-tests/plugins/interactive-blocks/directive-on-window/render.php b/packages/e2e-tests/plugins/interactive-blocks/directive-on-window/render.php index 9c067d33cb34a..6676012600019 100644 --- a/packages/e2e-tests/plugins/interactive-blocks/directive-on-window/render.php +++ b/packages/e2e-tests/plugins/interactive-blocks/directive-on-window/render.php @@ -5,7 +5,7 @@ * @package gutenberg-test-interactive-blocks */ -gutenberg_enqueue_module( 'directive-on-window-view' ); +wp_enqueue_script_module( 'directive-on-window-view' ); ?>
diff --git a/packages/e2e-tests/plugins/interactive-blocks/directive-on/render.php b/packages/e2e-tests/plugins/interactive-blocks/directive-on/render.php index ebf144660fd2a..edb081922fc0e 100644 --- a/packages/e2e-tests/plugins/interactive-blocks/directive-on/render.php +++ b/packages/e2e-tests/plugins/interactive-blocks/directive-on/render.php @@ -5,7 +5,7 @@ * @package gutenberg-test-interactive-blocks */ -gutenberg_enqueue_module( 'directive-on-view' ); +wp_enqueue_script_module( 'directive-on-view' ); ?>
diff --git a/packages/e2e-tests/plugins/interactive-blocks/directive-priorities/render.php b/packages/e2e-tests/plugins/interactive-blocks/directive-priorities/render.php index f082d44dd8fdf..2f98eb62aa5c6 100644 --- a/packages/e2e-tests/plugins/interactive-blocks/directive-priorities/render.php +++ b/packages/e2e-tests/plugins/interactive-blocks/directive-priorities/render.php @@ -5,7 +5,7 @@ * @package gutenberg-test-interactive-blocks */ -gutenberg_enqueue_module( 'directive-priorities-view' ); +wp_enqueue_script_module( 'directive-priorities-view' ); ?>
diff --git a/packages/e2e-tests/plugins/interactive-blocks/directive-run/render.php b/packages/e2e-tests/plugins/interactive-blocks/directive-run/render.php index a7eaaa984035e..237a3634b7452 100644 --- a/packages/e2e-tests/plugins/interactive-blocks/directive-run/render.php +++ b/packages/e2e-tests/plugins/interactive-blocks/directive-run/render.php @@ -5,7 +5,7 @@ * @package gutenberg-test-interactive-blocks */ -gutenberg_enqueue_module( 'directive-run-view' ); +wp_enqueue_script_module( 'directive-run-view' ); ?>
diff --git a/packages/e2e-tests/plugins/interactive-blocks/directive-text/render.php b/packages/e2e-tests/plugins/interactive-blocks/directive-text/render.php index 91d03b6fb8e19..428c1bfe24da2 100644 --- a/packages/e2e-tests/plugins/interactive-blocks/directive-text/render.php +++ b/packages/e2e-tests/plugins/interactive-blocks/directive-text/render.php @@ -5,7 +5,7 @@ * @package gutenberg-test-interactive-blocks */ -gutenberg_enqueue_module( 'directive-text-view' ); +wp_enqueue_script_module( 'directive-text-view' ); ?>
diff --git a/packages/e2e-tests/plugins/interactive-blocks/directive-watch/render.php b/packages/e2e-tests/plugins/interactive-blocks/directive-watch/render.php index 4fc7dd96ee883..74fb650b15388 100644 --- a/packages/e2e-tests/plugins/interactive-blocks/directive-watch/render.php +++ b/packages/e2e-tests/plugins/interactive-blocks/directive-watch/render.php @@ -5,7 +5,7 @@ * @package gutenberg-test-interactive-blocks */ -gutenberg_enqueue_module( 'directive-watch-view' ); +wp_enqueue_script_module( 'directive-watch-view' ); ?>
diff --git a/packages/e2e-tests/plugins/interactive-blocks/negation-operator/render.php b/packages/e2e-tests/plugins/interactive-blocks/negation-operator/render.php index 8d686e6c3ff46..b94b639c07985 100644 --- a/packages/e2e-tests/plugins/interactive-blocks/negation-operator/render.php +++ b/packages/e2e-tests/plugins/interactive-blocks/negation-operator/render.php @@ -5,7 +5,7 @@ * @package gutenberg-test-interactive-blocks */ -gutenberg_enqueue_module( 'negation-operator-view' ); +wp_enqueue_script_module( 'negation-operator-view' ); ?>
diff --git a/packages/e2e-tests/plugins/interactive-blocks/router-navigate/render.php b/packages/e2e-tests/plugins/interactive-blocks/router-navigate/render.php index 3fbddf623db60..560958e8a0d6b 100644 --- a/packages/e2e-tests/plugins/interactive-blocks/router-navigate/render.php +++ b/packages/e2e-tests/plugins/interactive-blocks/router-navigate/render.php @@ -7,7 +7,7 @@ * @phpcs:disable VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable */ -gutenberg_enqueue_module( 'router-navigate-view' ); +wp_enqueue_script_module( 'router-navigate-view' ); ?>
diff --git a/packages/e2e-tests/plugins/interactive-blocks/store-tag/render.php b/packages/e2e-tests/plugins/interactive-blocks/store-tag/render.php index 06deea9e1169d..874b358c93612 100644 --- a/packages/e2e-tests/plugins/interactive-blocks/store-tag/render.php +++ b/packages/e2e-tests/plugins/interactive-blocks/store-tag/render.php @@ -7,7 +7,7 @@ * @phpcs:disable VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable */ -gutenberg_enqueue_module( 'store-tag-view' ); +wp_enqueue_script_module( 'store-tag-view' ); // These variables simulates SSR. $test_store_tag_counter = 'ok' === $attributes['condition'] ? 3 : 0; diff --git a/packages/e2e-tests/plugins/interactive-blocks/tovdom-islands/render.php b/packages/e2e-tests/plugins/interactive-blocks/tovdom-islands/render.php index 1f53ca1331a37..cc16d30613e43 100644 --- a/packages/e2e-tests/plugins/interactive-blocks/tovdom-islands/render.php +++ b/packages/e2e-tests/plugins/interactive-blocks/tovdom-islands/render.php @@ -5,7 +5,7 @@ * @package gutenberg-test-interactive-blocks */ -gutenberg_enqueue_module( 'tovdom-islands-view' ); +wp_enqueue_script_module( 'tovdom-islands-view' ); ?>
diff --git a/packages/e2e-tests/plugins/interactive-blocks/tovdom/render.php b/packages/e2e-tests/plugins/interactive-blocks/tovdom/render.php index 309b42a582935..07a50745c7242 100644 --- a/packages/e2e-tests/plugins/interactive-blocks/tovdom/render.php +++ b/packages/e2e-tests/plugins/interactive-blocks/tovdom/render.php @@ -9,7 +9,7 @@ $src_proc_ins = $plugin_url . 'tovdom/processing-instructions.js'; $src_cdata = $plugin_url . 'tovdom/cdata.js'; -gutenberg_enqueue_module( 'tovdom-view' ); +wp_enqueue_script_module( 'tovdom-view' ); ?>
diff --git a/packages/e2e-tests/plugins/interactive-blocks/with-scope/render.php b/packages/e2e-tests/plugins/interactive-blocks/with-scope/render.php index e1a844e33246a..699c29aabe28c 100644 --- a/packages/e2e-tests/plugins/interactive-blocks/with-scope/render.php +++ b/packages/e2e-tests/plugins/interactive-blocks/with-scope/render.php @@ -5,7 +5,7 @@ * @package gutenberg-test-interactive-blocks */ -gutenberg_enqueue_module( 'with-scope-view' ); +wp_enqueue_script_module( 'with-scope-view' ); ?>
diff --git a/phpunit/experimental/modules/class-gutenberg-modules-test.php b/phpunit/experimental/modules/class-gutenberg-modules-test.php deleted file mode 100644 index a7f6c3b491a53..0000000000000 --- a/phpunit/experimental/modules/class-gutenberg-modules-test.php +++ /dev/null @@ -1,285 +0,0 @@ -registered = new ReflectionProperty( 'Gutenberg_Modules', 'registered' ); - $this->registered->setAccessible( true ); - $this->old_registered = $this->registered->getValue(); - $this->registered->setValue( array() ); - } - - public function tear_down() { - $this->registered->setValue( $this->old_registered ); - parent::tear_down(); - } - - public function get_enqueued_modules() { - $modules_markup = get_echo( array( 'Gutenberg_Modules', 'print_enqueued_modules' ) ); - $p = new WP_HTML_Tag_Processor( $modules_markup ); - $enqueued_modules = array(); - - while ( $p->next_tag( - array( - 'tag' => 'SCRIPT', - 'type' => 'module', - ) - ) ) { - $enqueued_modules[ $p->get_attribute( 'id' ) ] = $p->get_attribute( 'src' ); - } - - return $enqueued_modules; - } - - public function get_import_map() { - $import_map_markup = get_echo( array( 'Gutenberg_Modules', 'print_import_map' ) ); - preg_match( '/