[ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Script Modules API: WP_Script_Modules class. 4 * 5 * Native support for ES Modules and Import Maps. 6 * 7 * @package WordPress 8 * @subpackage Script Modules 9 */ 10 11 /** 12 * Core class used to register script modules. 13 * 14 * @since 6.5.0 15 */ 16 class WP_Script_Modules { 17 /** 18 * Holds the registered script modules, keyed by script module identifier. 19 * 20 * @since 6.5.0 21 * @var array 22 */ 23 private $registered = array(); 24 25 /** 26 * Holds the script module identifiers that were enqueued before registered. 27 * 28 * @since 6.5.0 29 * @var array<string, true> 30 */ 31 private $enqueued_before_registered = array(); 32 33 /** 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 ] ) ) { 66 $dependencies = array(); 67 foreach ( $deps as $dependency ) { 68 if ( is_array( $dependency ) ) { 69 if ( ! isset( $dependency['id'] ) ) { 70 _doing_it_wrong( __METHOD__, __( 'Missing required id key in entry among dependencies array.' ), '6.5.0' ); 71 continue; 72 } 73 $dependencies[] = array( 74 'id' => $dependency['id'], 75 'import' => isset( $dependency['import'] ) && 'dynamic' === $dependency['import'] ? 'dynamic' : 'static', 76 ); 77 } elseif ( is_string( $dependency ) ) { 78 $dependencies[] = array( 79 'id' => $dependency, 80 'import' => 'static', 81 ); 82 } else { 83 _doing_it_wrong( __METHOD__, __( 'Entries in dependencies array must be either strings or arrays with an id key.' ), '6.5.0' ); 84 } 85 } 86 87 $this->registered[ $id ] = array( 88 'src' => $src, 89 'version' => $version, 90 'enqueue' => isset( $this->enqueued_before_registered[ $id ] ), 91 'dependencies' => $dependencies, 92 ); 93 } 94 } 95 96 /** 97 * Marks the script module to be enqueued in the page. 98 * 99 * If a src is provided and the script module has not been registered yet, it 100 * will be registered. 101 * 102 * @since 6.5.0 103 * 104 * @param string $id The identifier of the script module. Should be unique. It will be used in the 105 * final import map. 106 * @param string $src Optional. Full URL of the script module, or path of the script module relative 107 * to the WordPress root directory. If it is provided and the script module has 108 * not been registered yet, it will be registered. 109 * @param array $deps { 110 * Optional. List of dependencies. 111 * 112 * @type string|array ...$0 { 113 * An array of script module identifiers of the dependencies of this script 114 * module. The dependencies can be strings or arrays. If they are arrays, 115 * they need an `id` key with the script module identifier, and can contain 116 * an `import` key with either `static` or `dynamic`. By default, 117 * dependencies that don't contain an `import` key are considered static. 118 * 119 * @type string $id The script module identifier. 120 * @type string $import Optional. Import type. May be either `static` or 121 * `dynamic`. Defaults to `static`. 122 * } 123 * } 124 * @param string|false|null $version Optional. String specifying the script module version number. Defaults to false. 125 * It is added to the URL as a query string for cache busting purposes. If $version 126 * is set to false, the version number is the currently installed WordPress version. 127 * If $version is set to null, no version is added. 128 */ 129 public function enqueue( string $id, string $src = '', array $deps = array(), $version = false ) { 130 if ( isset( $this->registered[ $id ] ) ) { 131 $this->registered[ $id ]['enqueue'] = true; 132 } elseif ( $src ) { 133 $this->register( $id, $src, $deps, $version ); 134 $this->registered[ $id ]['enqueue'] = true; 135 } else { 136 $this->enqueued_before_registered[ $id ] = true; 137 } 138 } 139 140 /** 141 * Unmarks the script module so it will no longer be enqueued in the page. 142 * 143 * @since 6.5.0 144 * 145 * @param string $id The identifier of the script module. 146 */ 147 public function dequeue( string $id ) { 148 if ( isset( $this->registered[ $id ] ) ) { 149 $this->registered[ $id ]['enqueue'] = false; 150 } 151 unset( $this->enqueued_before_registered[ $id ] ); 152 } 153 154 /** 155 * Removes a registered script module. 156 * 157 * @since 6.5.0 158 * 159 * @param string $id The identifier of the script module. 160 */ 161 public function deregister( string $id ) { 162 unset( $this->registered[ $id ] ); 163 unset( $this->enqueued_before_registered[ $id ] ); 164 } 165 166 /** 167 * Adds the hooks to print the import map, enqueued script modules and script 168 * module preloads. 169 * 170 * In classic themes, the script modules used by the blocks are not yet known 171 * when the `wp_head` actions is fired, so it needs to print everything in the 172 * footer. 173 * 174 * @since 6.5.0 175 */ 176 public function add_hooks() { 177 $position = wp_is_block_theme() ? 'wp_head' : 'wp_footer'; 178 add_action( $position, array( $this, 'print_import_map' ) ); 179 add_action( $position, array( $this, 'print_enqueued_script_modules' ) ); 180 add_action( $position, array( $this, 'print_script_module_preloads' ) ); 181 } 182 183 /** 184 * Prints the enqueued script modules using script tags with type="module" 185 * attributes. 186 * 187 * @since 6.5.0 188 */ 189 public function print_enqueued_script_modules() { 190 foreach ( $this->get_marked_for_enqueue() as $id => $script_module ) { 191 wp_print_script_tag( 192 array( 193 'type' => 'module', 194 'src' => $this->get_src( $id ), 195 'id' => $id . '-js-module', 196 ) 197 ); 198 } 199 } 200 201 /** 202 * Prints the the static dependencies of the enqueued script modules using 203 * link tags with rel="modulepreload" attributes. 204 * 205 * If a script module is marked for enqueue, it will not be preloaded. 206 * 207 * @since 6.5.0 208 */ 209 public function print_script_module_preloads() { 210 foreach ( $this->get_dependencies( array_keys( $this->get_marked_for_enqueue() ), array( 'static' ) ) as $id => $script_module ) { 211 // Don't preload if it's marked for enqueue. 212 if ( true !== $script_module['enqueue'] ) { 213 echo sprintf( 214 '<link rel="modulepreload" href="%s" id="%s">', 215 esc_url( $this->get_src( $id ) ), 216 esc_attr( $id . '-js-modulepreload' ) 217 ); 218 } 219 } 220 } 221 222 /** 223 * Prints the import map using a script tag with a type="importmap" attribute. 224 * 225 * @since 6.5.0 226 * 227 * @global WP_Scripts $wp_scripts The WP_Scripts object for printing the polyfill. 228 */ 229 public function print_import_map() { 230 $import_map = $this->get_import_map(); 231 if ( ! empty( $import_map['imports'] ) ) { 232 global $wp_scripts; 233 if ( isset( $wp_scripts ) ) { 234 wp_print_inline_script_tag( 235 wp_get_script_polyfill( 236 $wp_scripts, 237 array( 238 'HTMLScriptElement.supports && HTMLScriptElement.supports("importmap")' => 'wp-polyfill-importmap', 239 ) 240 ), 241 array( 242 'id' => 'wp-load-polyfill-importmap', 243 ) 244 ); 245 } 246 wp_print_inline_script_tag( 247 wp_json_encode( $import_map, JSON_HEX_TAG | JSON_HEX_AMP ), 248 array( 249 'type' => 'importmap', 250 'id' => 'wp-importmap', 251 ) 252 ); 253 } 254 } 255 256 /** 257 * Returns the import map array. 258 * 259 * @since 6.5.0 260 * 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 { 265 $imports = array(); 266 foreach ( $this->get_dependencies( array_keys( $this->get_marked_for_enqueue() ) ) as $id => $script_module ) { 267 $imports[ $id ] = $this->get_src( $id ); 268 } 269 return array( 'imports' => $imports ); 270 } 271 272 /** 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 { 280 $enqueued = array(); 281 foreach ( $this->registered as $id => $script_module ) { 282 if ( true === $script_module['enqueue'] ) { 283 $enqueued[ $id ] = $script_module; 284 } 285 } 286 return $enqueued; 287 } 288 289 /** 290 * Retrieves all the dependencies for the given script module identifiers, 291 * filtered by import types. 292 * 293 * It will consolidate an array containing a set of unique dependencies based 294 * on the requested import types: 'static', 'dynamic', or both. This method is 295 * recursive and also retrieves dependencies of the dependencies. 296 * 297 * @since 6.5.0 298 * 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' ) ) { 306 return array_reduce( 307 $ids, 308 function ( $dependency_script_modules, $id ) use ( $import_types ) { 309 $dependencies = array(); 310 foreach ( $this->registered[ $id ]['dependencies'] as $dependency ) { 311 if ( 312 in_array( $dependency['import'], $import_types, true ) && 313 isset( $this->registered[ $dependency['id'] ] ) && 314 ! isset( $dependency_script_modules[ $dependency['id'] ] ) 315 ) { 316 $dependencies[ $dependency['id'] ] = $this->registered[ $dependency['id'] ]; 317 } 318 } 319 return array_merge( $dependency_script_modules, $dependencies, $this->get_dependencies( array_keys( $dependencies ), $import_types ) ); 320 }, 321 array() 322 ); 323 } 324 325 /** 326 * Gets the versioned URL for a script module src. 327 * 328 * If $version is set to false, the version number is the currently installed 329 * WordPress version. If $version is set to null, no version is added. 330 * Otherwise, the string passed in $version is used. 331 * 332 * @since 6.5.0 333 * 334 * @param string $id The script module identifier. 335 * @return string The script module src with a version if relevant. 336 */ 337 private function get_src( string $id ): string { 338 if ( ! isset( $this->registered[ $id ] ) ) { 339 return ''; 340 } 341 342 $script_module = $this->registered[ $id ]; 343 $src = $script_module['src']; 344 345 if ( false === $script_module['version'] ) { 346 $src = add_query_arg( 'ver', get_bloginfo( 'version' ), $src ); 347 } elseif ( null !== $script_module['version'] ) { 348 $src = add_query_arg( 'ver', $script_module['version'], $src ); 349 } 350 351 /** 352 * Filters the script module source. 353 * 354 * @since 6.5.0 355 * 356 * @param string $src Module source url. 357 * @param string $id Module identifier. 358 */ 359 $src = apply_filters( 'script_module_loader_src', $src, $id ); 360 361 return $src; 362 } 363 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated : Sun Apr 28 08:20:02 2024 | Cross-referenced by PHPXref |