Changeset 57327 for trunk/src/wp-includes/class-wp-script-modules.php
- Timestamp:
- 01/23/2024 03:32:03 AM (11 months ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-includes/class-wp-script-modules.php
r57271 r57327 1 1 <?php 2 2 /** 3 * Modules API: WP_Script_Modules class.3 * Script Modules API: WP_Script_Modules class. 4 4 * 5 5 * Native support for ES Modules and Import Maps. … … 10 10 11 11 /** 12 * Core class used to register modules.12 * Core class used to register script modules. 13 13 * 14 14 * @since 6.5.0 … … 16 16 class WP_Script_Modules { 17 17 /** 18 * Holds the registered modules, keyed bymodule identifier.18 * Holds the registered script modules, keyed by script module identifier. 19 19 * 20 20 * @since 6.5.0 … … 24 24 25 25 /** 26 * Holds the module identifiers that were enqueued before registered.27 * 28 * @since 6.5.0 29 * @var array 26 * Holds the script module identifiers that were enqueued before registered. 27 * 28 * @since 6.5.0 29 * @var array<string, true> 30 30 */ 31 31 private $enqueued_before_registered = array(); 32 32 33 33 /** 34 * Registers the module if no module with that module identifier has already 35 * been registered. 36 * 37 * @since 6.5.0 38 * 39 * @param string $module_id The identifier of the module. 40 * Should be unique. It will be used 41 * in the final import map. 42 * @param string $src Full URL of the module, or path of 43 * the module relative to the 44 * WordPress root directory. 45 * @param array<string|array{id: string, import?: 'static'|'dynamic' }> $deps Optional. An array of module 46 * identifiers of the dependencies of 47 * this module. The dependencies can 48 * be strings or arrays. If they are 49 * arrays, they need an `id` key with 50 * the module identifier, and can 51 * contain an `import` key with either 52 * `static` or `dynamic`. By default, 53 * dependencies that don't contain an 54 * `import` key are considered static. 55 * @param string|false|null $version Optional. String specifying the 56 * module version number. Defaults to 57 * false. It is added to the URL as a 58 * query string for cache busting 59 * purposes. If $version is set to 60 * false, the version number is the 61 * currently installed WordPress 62 * version. If $version is set to 63 * null, no version is added. 64 */ 65 public function register( $module_id, $src, $deps = array(), $version = false ) { 66 if ( ! isset( $this->registered[ $module_id ] ) ) { 34 * Registers the script module if no script module with that script module 35 * identifier has already been registered. 36 * 37 * @since 6.5.0 38 * 39 * @param string $id The identifier of the script module. Should be unique. It will be used in the 40 * final import map. 41 * @param string $src Optional. Full URL of the script module, or path of the script module relative 42 * to the WordPress root directory. If it is provided and the script module has 43 * not been registered yet, it will be registered. 44 * @param array $deps { 45 * Optional. List of dependencies. 46 * 47 * @type string|array $0... { 48 * An array of script module identifiers of the dependencies of this script 49 * module. The dependencies can be strings or arrays. If they are arrays, 50 * they need an `id` key with the script module identifier, and can contain 51 * an `import` key with either `static` or `dynamic`. By default, 52 * dependencies that don't contain an `import` key are considered static. 53 * 54 * @type string $id The script module identifier. 55 * @type string $import Optional. Import type. May be either `static` or 56 * `dynamic`. Defaults to `static`. 57 * } 58 * } 59 * @param string|false|null $version Optional. String specifying the script module version number. Defaults to false. 60 * It is added to the URL as a query string for cache busting purposes. If $version 61 * is set to false, the version number is the currently installed WordPress version. 62 * If $version is set to null, no version is added. 63 */ 64 public function register( string $id, string $src, array $deps = array(), $version = false ) { 65 if ( ! isset( $this->registered[ $id ] ) ) { 67 66 $dependencies = array(); 68 67 foreach ( $deps as $dependency ) { … … 86 85 } 87 86 88 $this->registered[ $ module_id ] = array(87 $this->registered[ $id ] = array( 89 88 'src' => $src, 90 89 'version' => $version, 91 'enqueue' => isset( $this->enqueued_before_registered[ $ module_id ] ),90 'enqueue' => isset( $this->enqueued_before_registered[ $id ] ), 92 91 'dependencies' => $dependencies, 93 92 'enqueued' => false, … … 98 97 99 98 /** 100 * Marks the module to be enqueued in the page the next time 101 * `prints_enqueued_modules` is called. 102 * 103 * If a src is provided and the module has not been registered yet, it will be 104 * registered. 105 * 106 * @since 6.5.0 107 * 108 * @param string $module_id The identifier of the module. 109 * Should be unique. It will be used 110 * in the final import map. 111 * @param string $src Optional. Full URL of the module, 112 * or path of the module relative to 113 * the WordPress root directory. If 114 * it is provided and the module has 115 * not been registered yet, it will be 116 * registered. 117 * @param array<string|array{id: string, import?: 'static'|'dynamic' }> $deps Optional. An array of module 118 * identifiers of the dependencies of 119 * this module. The dependencies can 120 * be strings or arrays. If they are 121 * arrays, they need an `id` key with 122 * the module identifier, and can 123 * contain an `import` key with either 124 * `static` or `dynamic`. By default, 125 * dependencies that don't contain an 126 * `import` key are considered static. 127 * @param string|false|null $version Optional. String specifying the 128 * module version number. Defaults to 129 * false. It is added to the URL as a 130 * query string for cache busting 131 * purposes. If $version is set to 132 * false, the version number is the 133 * currently installed WordPress 134 * version. If $version is set to 135 * null, no version is added. 136 */ 137 public function enqueue( $module_id, $src = '', $deps = array(), $version = false ) { 138 if ( isset( $this->registered[ $module_id ] ) ) { 139 $this->registered[ $module_id ]['enqueue'] = true; 99 * Marks the script module to be enqueued in the page the next time 100 * `print_enqueued_script_modules` is called. 101 * 102 * If a src is provided and the script module has not been registered yet, it 103 * will be registered. 104 * 105 * @since 6.5.0 106 * 107 * @param string $id The identifier of the script module. Should be unique. It will be used in the 108 * final import map. 109 * @param string $src Optional. Full URL of the script module, or path of the script module relative 110 * to the WordPress root directory. If it is provided and the script module has 111 * not been registered yet, it will be registered. 112 * @param array $deps { 113 * Optional. List of dependencies. 114 * 115 * @type string|array $0... { 116 * An array of script module identifiers of the dependencies of this script 117 * module. The dependencies can be strings or arrays. If they are arrays, 118 * they need an `id` key with the script module identifier, and can contain 119 * an `import` key with either `static` or `dynamic`. By default, 120 * dependencies that don't contain an `import` key are considered static. 121 * 122 * @type string $id The script module identifier. 123 * @type string $import Optional. Import type. May be either `static` or 124 * `dynamic`. Defaults to `static`. 125 * } 126 * } 127 * @param string|false|null $version Optional. String specifying the script module version number. Defaults to false. 128 * It is added to the URL as a query string for cache busting purposes. If $version 129 * is set to false, the version number is the currently installed WordPress version. 130 * If $version is set to null, no version is added. 131 */ 132 public function enqueue( string $id, string $src = '', array $deps = array(), $version = false ) { 133 if ( isset( $this->registered[ $id ] ) ) { 134 $this->registered[ $id ]['enqueue'] = true; 140 135 } elseif ( $src ) { 141 $this->register( $ module_id, $src, $deps, $version );142 $this->registered[ $ module_id ]['enqueue'] = true;136 $this->register( $id, $src, $deps, $version ); 137 $this->registered[ $id ]['enqueue'] = true; 143 138 } else { 144 $this->enqueued_before_registered[ $ module_id ] = true;145 } 146 } 147 148 /** 149 * Unmarks the module so it will no longer be enqueued in the page.150 * 151 * @since 6.5.0 152 * 153 * @param string $ module_id The identifier of themodule.154 */ 155 public function dequeue( $module_id ) {156 if ( isset( $this->registered[ $ module_id ] ) ) {157 $this->registered[ $ module_id ]['enqueue'] = false;158 } 159 unset( $this->enqueued_before_registered[ $ module_id ] );160 } 161 162 /** 163 * Adds the hooks to print the import map, enqueued modules and module164 * preloads.165 * 166 * It adds the actions to print the enqueued modules and module preloads to167 * both `wp_head` and `wp_footer` because in classic themes, the modules168 * used by the theme and plugins will likely be able to be printed in the169 * `head`, but the ones used by the blocks will need to be enqueued in the170 * `footer`.171 * 172 * As all modules are deferred and dependencies are handled by the browser,173 * the order of the modules is not important, but it's still better to print174 * the ones that are available when the `wp_head` is rendered, so the browser175 * s tarts downloading those as soon as possible.139 $this->enqueued_before_registered[ $id ] = true; 140 } 141 } 142 143 /** 144 * Unmarks the script module so it will no longer be enqueued in the page. 145 * 146 * @since 6.5.0 147 * 148 * @param string $id The identifier of the script module. 149 */ 150 public function dequeue( string $id ) { 151 if ( isset( $this->registered[ $id ] ) ) { 152 $this->registered[ $id ]['enqueue'] = false; 153 } 154 unset( $this->enqueued_before_registered[ $id ] ); 155 } 156 157 /** 158 * Adds the hooks to print the import map, enqueued script modules and script 159 * module preloads. 160 * 161 * It adds the actions to print the enqueued script modules and script module 162 * preloads to both `wp_head` and `wp_footer` because in classic themes, the 163 * script modules used by the theme and plugins will likely be able to be 164 * printed in the `head`, but the ones used by the blocks will need to be 165 * enqueued in the `footer`. 166 * 167 * As all script modules are deferred and dependencies are handled by the 168 * browser, the order of the script modules is not important, but it's still 169 * better to print the ones that are available when the `wp_head` is rendered, 170 * so the browser starts downloading those as soon as possible. 176 171 * 177 172 * The import map is also printed in the footer to be able to include the 178 * dependencies of all the modules, including the ones printed in the footer. 173 * dependencies of all the script modules, including the ones printed in the 174 * footer. 179 175 * 180 176 * @since 6.5.0 181 177 */ 182 178 public function add_hooks() { 183 add_action( 'wp_head', array( $this, 'print_enqueued_ modules' ) );184 add_action( 'wp_head', array( $this, 'print_ module_preloads' ) );185 add_action( 'wp_footer', array( $this, 'print_enqueued_ modules' ) );186 add_action( 'wp_footer', array( $this, 'print_ module_preloads' ) );179 add_action( 'wp_head', array( $this, 'print_enqueued_script_modules' ) ); 180 add_action( 'wp_head', array( $this, 'print_script_module_preloads' ) ); 181 add_action( 'wp_footer', array( $this, 'print_enqueued_script_modules' ) ); 182 add_action( 'wp_footer', array( $this, 'print_script_module_preloads' ) ); 187 183 add_action( 'wp_footer', array( $this, 'print_import_map' ) ); 188 184 } 189 185 190 186 /** 191 * Prints the enqueued modules using script tags with type="module"187 * Prints the enqueued script modules using script tags with type="module" 192 188 * attributes. 193 189 * 194 * If a enqueued module has already been printed, it will not be printed again195 * on subsequent calls to this function.196 * 197 * @since 6.5.0 198 */ 199 public function print_enqueued_ modules() {200 foreach ( $this->get_marked_for_enqueue() as $ module_id => $module ) {201 if ( false === $ module['enqueued'] ) {190 * If a enqueued script module has already been printed, it will not be 191 * printed again on subsequent calls to this function. 192 * 193 * @since 6.5.0 194 */ 195 public function print_enqueued_script_modules() { 196 foreach ( $this->get_marked_for_enqueue() as $id => $script_module ) { 197 if ( false === $script_module['enqueued'] ) { 202 198 // Mark it as enqueued so it doesn't get enqueued again. 203 $this->registered[ $ module_id ]['enqueued'] = true;199 $this->registered[ $id ]['enqueued'] = true; 204 200 205 201 wp_print_script_tag( 206 202 array( 207 203 'type' => 'module', 208 'src' => $this->get_versioned_src( $ module ),209 'id' => $ module_id . '-js-module',204 'src' => $this->get_versioned_src( $script_module ), 205 'id' => $id . '-js-module', 210 206 ) 211 207 ); … … 215 211 216 212 /** 217 * Prints the the static dependencies of the enqueued modules using link tags218 * with rel="modulepreload" attributes.219 * 220 * If a module is marked for enqueue, it will not be preloaded. If a preloaded221 * module has already been printed, it will not be printed again on subsequent222 * calls to this function.223 * 224 * @since 6.5.0 225 */ 226 public function print_ module_preloads() {227 foreach ( $this->get_dependencies( array_keys( $this->get_marked_for_enqueue() ), array( 'static' ) ) as $ module_id => $module ) {213 * Prints the the static dependencies of the enqueued script modules using 214 * link tags with rel="modulepreload" attributes. 215 * 216 * If a script module is marked for enqueue, it will not be preloaded. If a 217 * preloaded script module has already been printed, it will not be printed 218 * again on subsequent calls to this function. 219 * 220 * @since 6.5.0 221 */ 222 public function print_script_module_preloads() { 223 foreach ( $this->get_dependencies( array_keys( $this->get_marked_for_enqueue() ), array( 'static' ) ) as $id => $script_module ) { 228 224 // Don't preload if it's marked for enqueue or has already been preloaded. 229 if ( true !== $ module['enqueue'] && false === $module['preloaded'] ) {225 if ( true !== $script_module['enqueue'] && false === $script_module['preloaded'] ) { 230 226 // Mark it as preloaded so it doesn't get preloaded again. 231 $this->registered[ $ module_id ]['preloaded'] = true;227 $this->registered[ $id ]['preloaded'] = true; 232 228 233 229 echo sprintf( 234 230 '<link rel="modulepreload" href="%s" id="%s">', 235 esc_url( $this->get_versioned_src( $ module ) ),236 esc_attr( $ module_id . '-js-modulepreload' )231 esc_url( $this->get_versioned_src( $script_module ) ), 232 esc_attr( $id . '-js-modulepreload' ) 237 233 ); 238 234 } … … 263 259 * @since 6.5.0 264 260 * 265 * @return array Array with an `imports` key mapping to an array of module identifiers and their respective URLs,266 * including the version query.267 */ 268 private function get_import_map() {261 * @return array Array with an `imports` key mapping to an array of script module identifiers and their respective 262 * URLs, including the version query. 263 */ 264 private function get_import_map(): array { 269 265 $imports = array(); 270 foreach ( $this->get_dependencies( array_keys( $this->get_marked_for_enqueue() ) ) as $ module_id => $module ) {271 $imports[ $ module_id ] = $this->get_versioned_src( $module );266 foreach ( $this->get_dependencies( array_keys( $this->get_marked_for_enqueue() ) ) as $id => $script_module ) { 267 $imports[ $id ] = $this->get_versioned_src( $script_module ); 272 268 } 273 269 return array( 'imports' => $imports ); … … 275 271 276 272 /** 277 * Retrieves the list of modules marked for enqueue.278 * 279 * @since 6.5.0 280 * 281 * @return array Modules marked for enqueue, keyed bymodule identifier.282 */ 283 private function get_marked_for_enqueue() {273 * Retrieves the list of script modules marked for enqueue. 274 * 275 * @since 6.5.0 276 * 277 * @return array Script modules marked for enqueue, keyed by script module identifier. 278 */ 279 private function get_marked_for_enqueue(): array { 284 280 $enqueued = array(); 285 foreach ( $this->registered as $ module_id => $module ) {286 if ( true === $ module['enqueue'] ) {287 $enqueued[ $ module_id ] = $module;281 foreach ( $this->registered as $id => $script_module ) { 282 if ( true === $script_module['enqueue'] ) { 283 $enqueued[ $id ] = $script_module; 288 284 } 289 285 } … … 292 288 293 289 /** 294 * Retrieves all the dependencies for the given module identifiers, filtered295 * by import types.290 * Retrieves all the dependencies for the given script module identifiers, 291 * filtered by import types. 296 292 * 297 293 * It will consolidate an array containing a set of unique dependencies based … … 301 297 * @since 6.5.0 302 298 * 303 * @param array $module_ids The identifiers of the modules for which to gather dependencies. 304 * @param array $import_types Optional. Import types of dependencies to retrieve: 'static', 'dynamic', or both. 305 * Default is both. 306 * @return array List of dependencies, keyed by module identifier. 307 */ 308 private function get_dependencies( $module_ids, $import_types = array( 'static', 'dynamic' ) ) { 299 300 * @param string[] $ids The identifiers of the script modules for which to gather dependencies. 301 * @param array $import_types Optional. Import types of dependencies to retrieve: 'static', 'dynamic', or both. 302 * Default is both. 303 * @return array List of dependencies, keyed by script module identifier. 304 */ 305 private function get_dependencies( array $ids, array $import_types = array( 'static', 'dynamic' ) ) { 309 306 return array_reduce( 310 $ module_ids,311 function ( $dependency_ modules, $module_id ) use ( $import_types ) {307 $ids, 308 function ( $dependency_script_modules, $id ) use ( $import_types ) { 312 309 $dependencies = array(); 313 foreach ( $this->registered[ $ module_id ]['dependencies'] as $dependency ) {310 foreach ( $this->registered[ $id ]['dependencies'] as $dependency ) { 314 311 if ( 315 312 in_array( $dependency['import'], $import_types, true ) && 316 313 isset( $this->registered[ $dependency['id'] ] ) && 317 ! isset( $dependency_ modules[ $dependency['id'] ] )314 ! isset( $dependency_script_modules[ $dependency['id'] ] ) 318 315 ) { 319 316 $dependencies[ $dependency['id'] ] = $this->registered[ $dependency['id'] ]; 320 317 } 321 318 } 322 return array_merge( $dependency_ modules, $dependencies, $this->get_dependencies( array_keys( $dependencies ), $import_types ) );319 return array_merge( $dependency_script_modules, $dependencies, $this->get_dependencies( array_keys( $dependencies ), $import_types ) ); 323 320 }, 324 321 array() … … 327 324 328 325 /** 329 * Gets the versioned URL for a module src.326 * Gets the versioned URL for a script module src. 330 327 * 331 328 * If $version is set to false, the version number is the currently installed … … 335 332 * @since 6.5.0 336 333 * 337 * @param array $ module Themodule.338 * @return string The module src with a version if relevant.339 */ 340 private function get_versioned_src( array $ module ){334 * @param array $script_module The script module. 335 * @return string The script module src with a version if relevant. 336 */ 337 private function get_versioned_src( array $script_module ): string { 341 338 $args = array(); 342 if ( false === $ module['version'] ) {339 if ( false === $script_module['version'] ) { 343 340 $args['ver'] = get_bloginfo( 'version' ); 344 } elseif ( null !== $ module['version'] ) {345 $args['ver'] = $ module['version'];341 } elseif ( null !== $script_module['version'] ) { 342 $args['ver'] = $script_module['version']; 346 343 } 347 344 if ( $args ) { 348 return add_query_arg( $args, $ module['src'] );349 } 350 return $ module['src'];345 return add_query_arg( $args, $script_module['src'] ); 346 } 347 return $script_module['src']; 351 348 } 352 349 }
Note: See TracChangeset
for help on using the changeset viewer.