| [ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Dependencies API: WP_Scripts class 4 * 5 * @since 2.6.0 6 * 7 * @package WordPress 8 * @subpackage Dependencies 9 */ 10 11 /** 12 * Core class used to register scripts. 13 * 14 * @since 2.1.0 15 * 16 * @see WP_Dependencies 17 */ 18 class WP_Scripts extends WP_Dependencies { 19 /** 20 * Base URL for scripts. 21 * 22 * Full URL with trailing slash. 23 * 24 * @since 2.6.0 25 * @see wp_default_scripts() 26 * @var string|null 27 */ 28 public $base_url; 29 30 /** 31 * URL of the content directory. 32 * 33 * @since 2.8.0 34 * @see wp_default_scripts() 35 * @var string|null 36 */ 37 public $content_url; 38 39 /** 40 * Default version string for scripts. 41 * 42 * @since 2.6.0 43 * @see wp_default_scripts() 44 * @var string|null 45 */ 46 public $default_version; 47 48 /** 49 * Holds handles of scripts which are enqueued in footer. 50 * 51 * @since 2.8.0 52 * @var string[] 53 */ 54 public $in_footer = array(); 55 56 /** 57 * Holds a list of script handles which will be concatenated. 58 * 59 * @since 2.8.0 60 * @deprecated 7.2.0 Scripts are no longer concatenated. 61 * @var string 62 */ 63 public $concat = ''; 64 65 /** 66 * Holds a string which contains script handles and their version. 67 * 68 * @since 2.8.0 69 * @deprecated 3.4.0 70 * @var string 71 */ 72 public $concat_version = ''; 73 74 /** 75 * Whether to perform concatenation. 76 * 77 * @since 2.8.0 78 * @deprecated 7.2.0 Scripts are no longer concatenated. 79 * @var bool 80 */ 81 public $do_concat = false; 82 83 /** 84 * Holds HTML markup of scripts and additional data if concatenation 85 * is enabled. 86 * 87 * @since 2.8.0 88 * @deprecated 7.2.0 Scripts are no longer concatenated. 89 * @var string 90 */ 91 public $print_html = ''; 92 93 /** 94 * Holds inline code if concatenation is enabled. 95 * 96 * @since 2.8.0 97 * @deprecated 7.2.0 Scripts are no longer concatenated. 98 * @var string 99 */ 100 public $print_code = ''; 101 102 /** 103 * Holds a list of script handles which are not in the default directory 104 * if concatenation is enabled. 105 * 106 * Unused in core. 107 * 108 * @since 2.8.0 109 * @deprecated 7.2.0 Scripts are no longer concatenated. 110 * @var string 111 */ 112 public $ext_handles = ''; 113 114 /** 115 * Holds a string which contains handles and versions of scripts which 116 * are not in the default directory if concatenation is enabled. 117 * 118 * Unused in core. 119 * 120 * @since 2.8.0 121 * @deprecated 7.2.0 Scripts are no longer concatenated. 122 * @var string 123 */ 124 public $ext_version = ''; 125 126 /** 127 * List of default directories. 128 * 129 * Only the deprecated {@see WP_Scripts::in_default_dir()} reads this, but 130 * {@see wp_default_scripts()} still sets it for plugins that read it. 131 * 132 * @since 2.8.0 133 * @deprecated 7.2.0 Scripts are no longer concatenated. 134 * @see WP_Scripts::in_default_dir() 135 * @see wp_default_scripts() 136 * @var string[]|null 137 */ 138 public $default_dirs; 139 140 /** 141 * Holds a mapping of dependents (as handles) for a given script handle. 142 * Used to optimize recursive dependency tree checks. 143 * 144 * @since 6.3.0 145 * @var array<string, string[]> 146 */ 147 private $dependents_map = array(); 148 149 /** 150 * Holds a reference to the delayed (non-blocking) script loading strategies. 151 * Used by methods that validate loading strategies. 152 * 153 * @since 6.3.0 154 * @var string[] 155 */ 156 private $delayed_strategies = array( 'defer', 'async' ); 157 158 /** 159 * Constructor. 160 * 161 * @since 2.6.0 162 */ 163 public function __construct() { 164 $this->init(); 165 add_action( 'init', array( $this, 'init' ), 0 ); 166 } 167 168 /** 169 * Initialize the class. 170 * 171 * @since 3.4.0 172 */ 173 public function init() { 174 /** 175 * Fires when the WP_Scripts instance is initialized. 176 * 177 * @since 2.6.0 178 * 179 * @param WP_Scripts $wp_scripts WP_Scripts instance (passed by reference). 180 */ 181 do_action_ref_array( 'wp_default_scripts', array( &$this ) ); 182 } 183 184 /** 185 * Prints scripts. 186 * 187 * Prints the scripts passed to it or the print queue. Also prints all necessary dependencies. 188 * 189 * @since 2.1.0 190 * @since 2.8.0 Added the `$group` parameter. 191 * 192 * @param string|string[]|false $handles Optional. Scripts to be printed: queue (false), 193 * single script (string), or multiple scripts (array of strings). 194 * Default false. 195 * @param int|false $group Optional. Group level: level (int), no groups (false). 196 * Default false. 197 * @return string[] Handles of scripts that have been printed. 198 */ 199 public function print_scripts( $handles = false, $group = false ) { 200 return $this->do_items( $handles, $group ); 201 } 202 203 /** 204 * Prints extra scripts of a registered script. 205 * 206 * @since 2.1.0 207 * @since 2.8.0 Added the `$display` parameter. 208 * @deprecated 3.3.0 209 * 210 * @see print_extra_script() 211 * 212 * @param string $handle The script's registered handle. 213 * @param bool $display Optional. Whether to print the extra script 214 * instead of just returning it. Default true. 215 * @return bool|string|null Null if no data exists, extra scripts if `$display` is false, 216 * true otherwise. 217 * @phpstan-return ( $display is true ? true|null : string|null ) 218 */ 219 public function print_scripts_l10n( $handle, $display = true ) { 220 _deprecated_function( __FUNCTION__, '3.3.0', 'WP_Scripts::print_extra_script()' ); 221 return $this->print_extra_script( $handle, $display ); 222 } 223 224 /** 225 * Prints extra scripts of a registered script. 226 * 227 * @since 3.3.0 228 * 229 * @param string $handle The script's registered handle. 230 * @param bool $display Optional. Whether to print the extra script 231 * instead of just returning it. Default true. 232 * @return bool|string|null Null if no data exists, extra scripts if `$display` is false, 233 * true otherwise. 234 * @phpstan-return ( $display is true ? true|null : string|null ) 235 */ 236 public function print_extra_script( $handle, $display = true ) { 237 $output = $this->get_data( $handle, 'data' ); 238 if ( ! is_string( $output ) || ! $output ) { 239 return null; 240 } 241 242 $output .= sprintf( 243 "\n//# sourceURL=%s", 244 rawurlencode( "{$handle}-js-extra" ) 245 ); 246 247 if ( ! $display ) { 248 return $output; 249 } 250 251 wp_print_inline_script_tag( $output, array( 'id' => "{$handle}-js-extra" ) ); 252 253 return true; 254 } 255 256 /** 257 * Checks whether all dependents of a given handle are in the footer. 258 * 259 * If there are no dependents, this is considered the same as if all dependents were in the footer. 260 * 261 * @since 6.4.0 262 * 263 * @param string $handle Script handle. 264 * @return bool Whether all dependents are in the footer. 265 */ 266 private function are_all_dependents_in_footer( $handle ) { 267 foreach ( $this->get_dependents( $handle ) as $dep ) { 268 if ( isset( $this->groups[ $dep ] ) && 0 === $this->groups[ $dep ] ) { 269 return false; 270 } 271 } 272 return true; 273 } 274 275 /** 276 * Processes a script dependency. 277 * 278 * @since 2.6.0 279 * @since 2.8.0 Added the `$group` parameter. 280 * 281 * @see WP_Dependencies::do_item() 282 * 283 * @param string $handle The script's registered handle. 284 * @param int|false $group Optional. Group level: level (int), no groups (false). 285 * Default false. 286 * @return bool True on success, false on failure. 287 */ 288 public function do_item( $handle, $group = false ) { 289 if ( ! parent::do_item( $handle ) ) { 290 return false; 291 } 292 293 if ( 0 === $group && $this->groups[ $handle ] > 0 ) { 294 $this->in_footer[] = $handle; 295 return false; 296 } 297 298 if ( false === $group && in_array( $handle, $this->in_footer, true ) ) { 299 $this->in_footer = array_diff( $this->in_footer, (array) $handle ); 300 } 301 302 $obj = $this->registered[ $handle ]; 303 if ( $obj->extra['conditional'] ?? false ) { 304 return false; 305 } 306 307 $src = $obj->src; 308 $strategy = $this->get_eligible_loading_strategy( $handle ); 309 $intended_strategy = (string) $this->get_data( $handle, 'strategy' ); 310 311 if ( ! $this->is_delayed_strategy( $intended_strategy ) ) { 312 $intended_strategy = ''; 313 } 314 315 /* 316 * Move this script to the footer if: 317 * 1. The script is in the header group. 318 * 2. The current output is the header. 319 * 3. The intended strategy is delayed. 320 * 4. The actual strategy is not delayed. 321 * 5. All dependent scripts are in the footer. 322 */ 323 if ( 324 0 === $group && 325 0 === $this->groups[ $handle ] && 326 $intended_strategy && 327 ! $this->is_delayed_strategy( $strategy ) && 328 $this->are_all_dependents_in_footer( $handle ) 329 ) { 330 $this->in_footer[] = $handle; 331 return false; 332 } 333 334 $before_script = $this->get_inline_script_tag( $handle, 'before' ); 335 $after_script = $this->get_inline_script_tag( $handle, 'after' ); 336 337 if ( $before_script || $after_script ) { 338 $inline_script_tag = $before_script . $after_script; 339 } else { 340 $inline_script_tag = ''; 341 } 342 343 $translations = $this->print_translations( $handle, false ); 344 if ( $translations ) { 345 /* 346 * The sourceURL comment is not included by WP_Scripts::print_translations() 347 * when `$display` is `false` to prevent issues where the script tag contents are used 348 * by extenders for other purposes, for example concatenated with other script content. 349 * 350 * Include the sourceURL comment here as it would be when printed directly. 351 */ 352 $source_url = rawurlencode( "{$handle}-js-translations" ); 353 $translations .= "\n//# sourceURL={$source_url}"; 354 $translations = wp_get_inline_script_tag( $translations, array( 'id' => "{$handle}-js-translations" ) ); 355 } 356 357 $this->print_extra_script( $handle ); 358 359 // A single item may alias a set of items, by having dependencies, but no source. 360 if ( ! $src ) { 361 if ( $inline_script_tag ) { 362 echo $inline_script_tag; 363 } 364 365 return true; 366 } 367 368 $src = esc_url_raw( $this->get_src( $handle ) ); 369 370 if ( ! $src ) { 371 return true; 372 } 373 374 $attr = array( 375 'src' => $src, 376 'id' => "{$handle}-js", 377 ); 378 if ( $strategy ) { 379 $attr[ $strategy ] = true; 380 } 381 if ( $intended_strategy ) { 382 $attr['data-wp-strategy'] = $intended_strategy; 383 } 384 385 // Determine fetchpriority. 386 $original_fetchpriority = $obj->extra['fetchpriority'] ?? null; 387 if ( null === $original_fetchpriority || ! $this->is_valid_fetchpriority( $original_fetchpriority ) ) { 388 $original_fetchpriority = 'auto'; 389 } 390 $actual_fetchpriority = $this->get_highest_fetchpriority_with_dependents( $handle ); 391 if ( null === $actual_fetchpriority ) { 392 // If null, it's likely this script was not explicitly enqueued, so in this case use the original priority. 393 $actual_fetchpriority = $original_fetchpriority; 394 } 395 if ( is_string( $actual_fetchpriority ) && 'auto' !== $actual_fetchpriority ) { 396 $attr['fetchpriority'] = $actual_fetchpriority; 397 } 398 399 if ( $original_fetchpriority !== $actual_fetchpriority ) { 400 $attr['data-wp-fetchpriority'] = $original_fetchpriority; 401 } 402 403 $tag = $translations . $before_script; 404 $tag .= wp_get_script_tag( $attr ); 405 $tag .= $after_script; 406 407 /** 408 * Filters the HTML script tag of an enqueued script. 409 * 410 * @since 4.1.0 411 * 412 * @param string $tag The `<script>` tag for the enqueued script. 413 * @param string $handle The script's registered handle. 414 * @param string $src The script's source URL. 415 */ 416 $tag = apply_filters( 'script_loader_tag', $tag, $handle, $src ); 417 418 echo $tag; 419 420 return true; 421 } 422 423 /** 424 * Gets the URL a registered script is loaded from. 425 * 426 * This is the URL printed in the script's `src` attribute, including the version query 427 * argument and any arguments added to the handle, after the {@see 'script_loader_src'} filter. 428 * Like {@see WP_Script_Modules::get_src()}, it is neither sanitized nor escaped, so a caller 429 * can pass it through esc_url_raw(), as WP_Scripts::do_item() does, or esc_url(), once. 430 * 431 * @since 7.2.0 432 * 433 * @param string $handle Script handle. 434 * @return string Script URL, or an empty string when the script is not registered, has no 435 * source of its own because it only aliases other scripts, or was filtered away. 436 */ 437 public function get_src( string $handle ): string { 438 if ( ! isset( $this->registered[ $handle ] ) ) { 439 return ''; 440 } 441 442 $obj = $this->registered[ $handle ]; 443 $src = $obj->src; 444 445 if ( ! $src || ! is_string( $src ) ) { 446 return ''; 447 } 448 449 if ( ! preg_match( '|^(https?:)?//|', $src ) && ! ( $this->content_url && str_starts_with( $src, $this->content_url ) ) ) { 450 $src = $this->base_url . $src; 451 } 452 453 $ver_to_add = ''; 454 if ( empty( $obj->ver ) && null !== $obj->ver && is_string( $this->default_version ) ) { 455 $ver_to_add = $this->default_version; 456 } elseif ( is_scalar( $obj->ver ) ) { 457 $ver_to_add = (string) $obj->ver; 458 } 459 460 $added_args = (string) ( $this->args[ $handle ] ?? '' ); 461 462 if ( '' !== $ver_to_add || '' !== $added_args ) { 463 $fragment = strstr( $src, '#' ); 464 if ( false !== $fragment ) { 465 $src = substr( $src, 0, -strlen( $fragment ) ); 466 } 467 468 if ( '' !== $ver_to_add ) { 469 $src .= ( str_contains( $src, '?' ) ? '&' : '?' ) . 'ver=' . rawurlencode( $ver_to_add ); 470 } 471 if ( '' !== $added_args ) { 472 $src .= ( str_contains( $src, '?' ) ? '&' : '?' ) . $added_args; 473 } 474 475 if ( false !== $fragment ) { 476 $src .= $fragment; 477 } 478 } 479 480 /** 481 * Filters the script loader source. 482 * 483 * @since 2.2.0 484 * 485 * @param string $src Script loader source path. 486 * @param string $handle Script handle. 487 */ 488 $src = apply_filters( 'script_loader_src', $src, $handle ); 489 490 return is_string( $src ) ? $src : ''; 491 } 492 493 /** 494 * Adds extra code to a registered script. 495 * 496 * @since 4.5.0 497 * 498 * @param string $handle Name of the script to add the inline script to. 499 * Must be lowercase. 500 * @param string $data String containing the JavaScript to be added. 501 * @param string $position Optional. Whether to add the inline script 502 * before the handle or after. Default 'after'. 503 * @return bool True on success, false on failure. 504 */ 505 public function add_inline_script( $handle, $data, $position = 'after' ) { 506 if ( ! $data ) { 507 return false; 508 } 509 510 if ( 'after' !== $position ) { 511 $position = 'before'; 512 } 513 514 $script = $this->get_data( $handle, $position ); 515 $script = false === $script ? array() : (array) $script; 516 $script[] = $data; 517 518 return $this->add_data( $handle, $position, $script ); 519 } 520 521 /** 522 * Prints inline scripts registered for a specific handle. 523 * 524 * @since 4.5.0 525 * @deprecated 6.3.0 Use methods get_inline_script_tag() or get_inline_script_data() instead. 526 * 527 * @param string $handle Name of the script to print inline scripts for. 528 * Must be lowercase. 529 * @param string $position Optional. Whether to add the inline script 530 * before the handle or after. Default 'after'. 531 * @param bool $display Optional. Whether to print the script tag 532 * instead of just returning the script data. Default true. 533 * @return string|false Script data on success, false otherwise. 534 */ 535 public function print_inline_script( $handle, $position = 'after', $display = true ) { 536 _deprecated_function( __METHOD__, '6.3.0', 'WP_Scripts::get_inline_script_data() or WP_Scripts::get_inline_script_tag()' ); 537 538 $output = $this->get_inline_script_data( $handle, $position ); 539 if ( empty( $output ) ) { 540 return false; 541 } 542 543 if ( $display ) { 544 echo $this->get_inline_script_tag( $handle, $position ); 545 } 546 return $output; 547 } 548 549 /** 550 * Gets data for inline scripts registered for a specific handle. 551 * 552 * @since 6.3.0 553 * 554 * @param string $handle Name of the script to get data for. 555 * Must be lowercase. 556 * @param string $position Optional. Whether to add the inline script 557 * before the handle or after. Default 'after'. 558 * @return string Inline script, which may be empty string. 559 */ 560 public function get_inline_script_data( $handle, $position = 'after' ) { 561 $data = $this->get_data( $handle, $position ); 562 if ( empty( $data ) || ! is_array( $data ) ) { 563 return ''; 564 } 565 566 $data[] = sprintf( 567 '//# sourceURL=%s', 568 rawurlencode( "{$handle}-js-{$position}" ) 569 ); 570 571 return trim( implode( "\n", $data ), "\n" ); 572 } 573 574 /** 575 * Gets tags for inline scripts registered for a specific handle. 576 * 577 * @since 6.3.0 578 * 579 * @param string $handle Name of the script to get associated inline script tag for. 580 * Must be lowercase. 581 * @param string $position Optional. Whether to get tag for inline 582 * scripts in the before or after position. Default 'after'. 583 * @return string Inline script, which may be empty string. 584 */ 585 public function get_inline_script_tag( $handle, $position = 'after' ) { 586 $js = $this->get_inline_script_data( $handle, $position ); 587 if ( empty( $js ) ) { 588 return ''; 589 } 590 591 $id = "{$handle}-js-{$position}"; 592 593 return wp_get_inline_script_tag( $js, compact( 'id' ) ); 594 } 595 596 /** 597 * Localizes a script, only if the script has already been added. 598 * 599 * @since 2.1.0 600 * 601 * @param string $handle Name of the script to attach data to. 602 * @param string $object_name Name of the variable that will contain the data. 603 * @param array<string, mixed> $l10n Array of data to localize. 604 * @return bool True on success, false on failure. 605 */ 606 public function localize( $handle, $object_name, $l10n ) { 607 if ( 'jquery' === $handle ) { 608 $handle = 'jquery-core'; 609 } 610 611 if ( is_array( $l10n ) && isset( $l10n['l10n_print_after'] ) ) { // back compat, preserve the code in 'l10n_print_after' if present. 612 $after = $l10n['l10n_print_after']; 613 unset( $l10n['l10n_print_after'] ); 614 } 615 616 if ( ! is_array( $l10n ) ) { 617 _doing_it_wrong( 618 __METHOD__, 619 sprintf( 620 /* translators: 1: $l10n, 2: wp_add_inline_script() */ 621 __( 'The %1$s parameter must be an array. To pass arbitrary data to scripts, use the %2$s function instead.' ), 622 '<code>$l10n</code>', 623 '<code>wp_add_inline_script()</code>' 624 ), 625 '5.7.0' 626 ); 627 628 if ( false === $l10n ) { 629 // This should really not be needed, but is necessary for backward compatibility. 630 $l10n = array( $l10n ); 631 } 632 } 633 634 if ( is_string( $l10n ) ) { 635 $l10n = html_entity_decode( $l10n, ENT_QUOTES, 'UTF-8' ); 636 } elseif ( is_array( $l10n ) ) { 637 foreach ( $l10n as $key => $value ) { 638 if ( ! is_scalar( $value ) ) { 639 continue; 640 } 641 642 $l10n[ $key ] = html_entity_decode( (string) $value, ENT_QUOTES, 'UTF-8' ); 643 } 644 } 645 646 $script = "var $object_name = " . wp_json_encode( $l10n, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ) . ';'; 647 648 if ( ! empty( $after ) ) { 649 $script .= "\n$after;"; 650 } 651 652 $data = $this->get_data( $handle, 'data' ); 653 654 if ( ! empty( $data ) ) { 655 $script = "$data\n$script"; 656 } 657 658 return $this->add_data( $handle, 'data', $script ); 659 } 660 661 /** 662 * Sets handle group. 663 * 664 * @since 2.8.0 665 * 666 * @see WP_Dependencies::set_group() 667 * 668 * @param string $handle Name of the item. Should be unique. 669 * @param bool $recursion Internal flag that calling function was called recursively. 670 * @param int|false $group Optional. Group level: level (int), no groups (false). 671 * Default false. 672 * @return bool Not already in the group or a lower group. 673 */ 674 public function set_group( $handle, $recursion, $group = false ) { 675 if ( isset( $this->registered[ $handle ]->args ) && 1 === $this->registered[ $handle ]->args ) { 676 $calculated_group = 1; 677 } else { 678 $calculated_group = (int) $this->get_data( $handle, 'group' ); 679 } 680 681 if ( false !== $group && $calculated_group > $group ) { 682 $calculated_group = $group; 683 } 684 685 return parent::set_group( $handle, $recursion, $calculated_group ); 686 } 687 688 /** 689 * Sets a translation textdomain. 690 * 691 * @since 5.0.0 692 * @since 5.1.0 The `$domain` parameter was made optional. 693 * 694 * @param string $handle Name of the script to register a translation domain to. 695 * @param string $domain Optional. Text domain. Default 'default'. 696 * @param string $path Optional. The full file path to the directory containing translation files. 697 * @return bool True if the text domain was registered, false if not. 698 */ 699 public function set_translations( $handle, $domain = 'default', $path = '' ) { 700 if ( ! isset( $this->registered[ $handle ] ) ) { 701 return false; 702 } 703 704 /** @var \_WP_Dependency $obj */ 705 $obj = $this->registered[ $handle ]; 706 707 if ( ! in_array( 'wp-i18n', $obj->deps, true ) ) { 708 $obj->deps[] = 'wp-i18n'; 709 } 710 711 return $obj->set_translations( $domain, $path ); 712 } 713 714 /** 715 * Prints translations set for a specific handle. 716 * 717 * @since 5.0.0 718 * 719 * @param string $handle Name of the script to add the inline script to. 720 * Must be lowercase. 721 * @param bool $display Optional. Whether to print the script 722 * instead of just returning it. Default true. 723 * @return string|false Script on success, false otherwise. 724 */ 725 public function print_translations( $handle, $display = true ) { 726 if ( ! isset( $this->registered[ $handle ] ) || empty( $this->registered[ $handle ]->textdomain ) ) { 727 return false; 728 } 729 730 $domain = $this->registered[ $handle ]->textdomain; 731 $path = ''; 732 733 if ( isset( $this->registered[ $handle ]->translations_path ) ) { 734 $path = $this->registered[ $handle ]->translations_path; 735 } 736 737 $json_translations = load_script_textdomain( $handle, $domain, $path ); 738 739 if ( ! $json_translations ) { 740 return false; 741 } 742 743 $output = <<<JS 744 ( function( domain, translations ) { 745 var localeData = translations.locale_data[ domain ] || translations.locale_data.messages; 746 localeData[""].domain = domain; 747 wp.i18n.setLocaleData( localeData, domain ); 748 } )( "{$domain}", {$json_translations} ); 749 JS; 750 751 if ( $display ) { 752 $source_url = rawurlencode( "{$handle}-js-translations" ); 753 $output .= "\n//# sourceURL={$source_url}"; 754 wp_print_inline_script_tag( $output, array( 'id' => "{$handle}-js-translations" ) ); 755 } 756 757 return $output; 758 } 759 760 /** 761 * Determines script dependencies. 762 * 763 * @since 2.1.0 764 * 765 * @see WP_Dependencies::all_deps() 766 * 767 * @param string|string[] $handles Item handle (string) or item handles (array of strings). 768 * @param bool $recursion Optional. Internal flag that function is calling itself. 769 * Default false. 770 * @param int|false $group Optional. Group level: level (int), no groups (false). 771 * Default false. 772 * @return bool True on success, false on failure. 773 */ 774 public function all_deps( $handles, $recursion = false, $group = false ) { 775 $result = parent::all_deps( $handles, $recursion, $group ); 776 if ( ! $recursion ) { 777 /** 778 * Filters the list of script dependencies left to print. 779 * 780 * @since 2.3.0 781 * 782 * @param string[] $to_do An array of script dependency handles. 783 */ 784 $this->to_do = apply_filters( 'print_scripts_array', $this->to_do ); 785 } 786 return $result; 787 } 788 789 /** 790 * Processes items and dependencies for the head group. 791 * 792 * @since 2.8.0 793 * 794 * @see WP_Dependencies::do_items() 795 * 796 * @return string[] Handles of items that have been processed. 797 */ 798 public function do_head_items() { 799 $this->do_items( false, 0 ); 800 return $this->done; 801 } 802 803 /** 804 * Processes items and dependencies for the footer group. 805 * 806 * @since 2.8.0 807 * 808 * @see WP_Dependencies::do_items() 809 * 810 * @return string[] Handles of items that have been processed. 811 */ 812 public function do_footer_items() { 813 $this->do_items( false, 1 ); 814 return $this->done; 815 } 816 817 /** 818 * Whether a handle's source is in a default directory. 819 * 820 * @since 2.8.0 821 * @deprecated 7.2.0 Scripts are no longer concatenated. 822 * 823 * @param string $src The source of the enqueued script. 824 * @return bool True if found, false if not. 825 */ 826 public function in_default_dir( $src ) { 827 _deprecated_function( __METHOD__, '7.2.0' ); 828 829 if ( ! $this->default_dirs ) { 830 return true; 831 } 832 833 if ( str_starts_with( $src, '/' . WPINC . '/js/l10n' ) ) { 834 return false; 835 } 836 837 return array_any( (array) $this->default_dirs, fn( $test ) => str_starts_with( $src, $test ) ); 838 } 839 840 /** 841 * This overrides the add_data method from WP_Dependencies, to support normalizing of $args. 842 * 843 * @since 6.3.0 844 * 845 * @param string $handle Name of the item. Should be unique. 846 * @param string $key The data key. 847 * @param mixed $value The data value. 848 * @return bool True on success, false on failure. 849 */ 850 public function add_data( $handle, $key, $value ) { 851 if ( ! isset( $this->registered[ $handle ] ) ) { 852 return false; 853 } 854 855 if ( 'conditional' === $key ) { 856 // If a dependency is declared by a conditional script, remove it. 857 $this->registered[ $handle ]->deps = array(); 858 } 859 860 if ( 'strategy' === $key ) { 861 if ( ! empty( $value ) && ! $this->is_delayed_strategy( $value ) ) { 862 _doing_it_wrong( 863 __METHOD__, 864 sprintf( 865 /* translators: 1: $strategy, 2: $handle */ 866 __( 'Invalid strategy `%1$s` defined for `%2$s` during script registration.' ), 867 is_string( $value ) ? $value : gettype( $value ), 868 $handle 869 ), 870 '6.3.0' 871 ); 872 return false; 873 } elseif ( ! $this->registered[ $handle ]->src && $this->is_delayed_strategy( $value ) ) { 874 _doing_it_wrong( 875 __METHOD__, 876 sprintf( 877 /* translators: 1: $strategy, 2: $handle */ 878 __( 'Cannot supply a strategy `%1$s` for script `%2$s` because it is an alias (it lacks a `src` value).' ), 879 is_string( $value ) ? $value : gettype( $value ), 880 $handle 881 ), 882 '6.3.0' 883 ); 884 return false; 885 } 886 } elseif ( 'fetchpriority' === $key ) { 887 if ( empty( $value ) ) { 888 $value = 'auto'; 889 } 890 if ( ! $this->is_valid_fetchpriority( $value ) ) { 891 _doing_it_wrong( 892 __METHOD__, 893 sprintf( 894 /* translators: 1: $fetchpriority, 2: $handle */ 895 __( 'Invalid fetchpriority `%1$s` defined for `%2$s` during script registration.' ), 896 is_string( $value ) ? $value : gettype( $value ), 897 $handle 898 ), 899 '6.9.0' 900 ); 901 return false; 902 } elseif ( ! $this->registered[ $handle ]->src ) { 903 _doing_it_wrong( 904 __METHOD__, 905 sprintf( 906 /* translators: 1: $fetchpriority, 2: $handle */ 907 __( 'Cannot supply a fetchpriority `%1$s` for script `%2$s` because it is an alias (it lacks a `src` value).' ), 908 is_string( $value ) ? $value : gettype( $value ), 909 $handle 910 ), 911 '6.9.0' 912 ); 913 return false; 914 } 915 } elseif ( 'module_dependencies' === $key ) { 916 if ( ! is_array( $value ) ) { 917 _doing_it_wrong( 918 __METHOD__, 919 sprintf( 920 /* translators: 1: 'module_dependencies', 2: Script handle. */ 921 __( 'The value for "%1$s" must be an array for the "%2$s" script.' ), 922 'module_dependencies', 923 $handle 924 ), 925 '7.0.0' 926 ); 927 return false; 928 } 929 930 $sanitized_value = array(); 931 $has_invalid_ids = false; 932 foreach ( $value as $module ) { 933 if ( 934 is_string( $module ) || 935 ( is_array( $module ) && isset( $module['id'] ) && is_string( $module['id'] ) ) 936 ) { 937 $sanitized_value[] = $module; 938 } else { 939 $has_invalid_ids = true; 940 } 941 } 942 943 if ( $has_invalid_ids ) { 944 _doing_it_wrong( 945 __METHOD__, 946 sprintf( 947 /* translators: 1: Script handle, 2: 'module_dependencies' */ 948 __( 'The script handle "%1$s" has one or more of its script module dependencies ("%2$s") which are invalid.' ), 949 $handle, 950 'module_dependencies' 951 ), 952 '7.0.0' 953 ); 954 } 955 956 $value = $sanitized_value; 957 } 958 return parent::add_data( $handle, $key, $value ); 959 } 960 961 /** 962 * Gets all dependents of a script. 963 * 964 * This is not recursive. 965 * 966 * @since 6.3.0 967 * 968 * @param string $handle The script handle. 969 * @return string[] Script handles. 970 */ 971 private function get_dependents( $handle ) { 972 // Check if dependents map for the handle in question is present. If so, use it. 973 if ( isset( $this->dependents_map[ $handle ] ) ) { 974 return $this->dependents_map[ $handle ]; 975 } 976 977 $dependents = array(); 978 979 // Iterate over all registered scripts, finding dependents of the script passed to this method. 980 foreach ( $this->registered as $registered_handle => $args ) { 981 if ( in_array( $handle, $args->deps, true ) ) { 982 $dependents[] = $registered_handle; 983 } 984 } 985 986 // Add the handles dependents to the map to ease future lookups. 987 $this->dependents_map[ $handle ] = $dependents; 988 989 return $dependents; 990 } 991 992 /** 993 * Checks if the strategy passed is a valid delayed (non-blocking) strategy. 994 * 995 * @since 6.3.0 996 * 997 * @param string|mixed $strategy The strategy to check. 998 * @return bool True if $strategy is one of the delayed strategies, otherwise false. 999 */ 1000 private function is_delayed_strategy( $strategy ): bool { 1001 return in_array( 1002 $strategy, 1003 $this->delayed_strategies, 1004 true 1005 ); 1006 } 1007 1008 /** 1009 * Checks if the provided fetchpriority is valid. 1010 * 1011 * @since 6.9.0 1012 * 1013 * @param string|mixed $priority Fetch priority. 1014 * @return bool Whether valid fetchpriority. 1015 */ 1016 private function is_valid_fetchpriority( $priority ): bool { 1017 return in_array( $priority, array( 'auto', 'low', 'high' ), true ); 1018 } 1019 1020 /** 1021 * Gets the best eligible loading strategy for a script. 1022 * 1023 * @since 6.3.0 1024 * 1025 * @param string $handle The script handle. 1026 * @return string The best eligible loading strategy. 1027 */ 1028 private function get_eligible_loading_strategy( $handle ) { 1029 $intended_strategy = (string) $this->get_data( $handle, 'strategy' ); 1030 1031 // Bail early if there is no intended strategy. 1032 if ( ! $intended_strategy ) { 1033 return ''; 1034 } 1035 1036 /* 1037 * If the intended strategy is 'defer', limit the initial list of eligible 1038 * strategies, since 'async' can fallback to 'defer', but not vice-versa. 1039 */ 1040 $initial_strategy = ( 'defer' === $intended_strategy ) ? array( 'defer' ) : null; 1041 1042 $eligible_strategies = $this->filter_eligible_strategies( $handle, $initial_strategy ); 1043 1044 // Return early once we know the eligible strategy is blocking. 1045 if ( empty( $eligible_strategies ) ) { 1046 return ''; 1047 } 1048 1049 return in_array( 'async', $eligible_strategies, true ) ? 'async' : 'defer'; 1050 } 1051 1052 /** 1053 * Filter the list of eligible loading strategies for a script. 1054 * 1055 * @since 6.3.0 1056 * 1057 * @param string $handle The script handle. 1058 * @param string[]|null $eligible_strategies Optional. The list of strategies to filter. Default null. 1059 * @param array<string, true> $checked Optional. An array of already checked script handles, used to avoid recursive loops. 1060 * @param array<string, string[]> $stored_results Optional. An array of already computed eligible loading strategies by handle, used to increase performance in large dependency lists. 1061 * @return string[] A list of eligible loading strategies that could be used. 1062 */ 1063 private function filter_eligible_strategies( $handle, $eligible_strategies = null, $checked = array(), array &$stored_results = array() ) { 1064 if ( isset( $stored_results[ $handle ] ) ) { 1065 return $stored_results[ $handle ]; 1066 } 1067 1068 // If no strategies are being passed, all strategies are eligible. 1069 if ( null === $eligible_strategies ) { 1070 $eligible_strategies = $this->delayed_strategies; 1071 } 1072 1073 // If this handle was already checked, return early. 1074 if ( isset( $checked[ $handle ] ) ) { 1075 return $eligible_strategies; 1076 } 1077 1078 // Mark this handle as checked. 1079 $checked[ $handle ] = true; 1080 1081 // If this handle isn't registered, don't filter anything and return. 1082 if ( ! isset( $this->registered[ $handle ] ) ) { 1083 return $eligible_strategies; 1084 } 1085 1086 // If the handle is not enqueued, don't filter anything and return. 1087 if ( ! $this->query( $handle, 'enqueued' ) ) { 1088 return $eligible_strategies; 1089 } 1090 1091 $is_alias = (bool) ! $this->registered[ $handle ]->src; 1092 $intended_strategy = $this->get_data( $handle, 'strategy' ); 1093 1094 // For non-alias handles, an empty intended strategy filters all strategies. 1095 if ( ! $is_alias && empty( $intended_strategy ) ) { 1096 return array(); 1097 } 1098 1099 // Handles with inline scripts attached in the 'after' position cannot be delayed. 1100 if ( $this->has_inline_script( $handle, 'after' ) ) { 1101 return array(); 1102 } 1103 1104 // If the intended strategy is 'defer', filter out 'async'. 1105 if ( 'defer' === $intended_strategy ) { 1106 $eligible_strategies = array( 'defer' ); 1107 } 1108 1109 $dependents = $this->get_dependents( $handle ); 1110 1111 // Recursively filter eligible strategies for dependents. 1112 foreach ( $dependents as $dependent ) { 1113 // Bail early once we know the eligible strategy is blocking. 1114 if ( empty( $eligible_strategies ) ) { 1115 return array(); 1116 } 1117 1118 $eligible_strategies = $this->filter_eligible_strategies( $dependent, $eligible_strategies, $checked, $stored_results ); 1119 } 1120 $stored_results[ $handle ] = $eligible_strategies; 1121 return $eligible_strategies; 1122 } 1123 1124 /** 1125 * Gets the highest fetch priority for a given script and all of its dependent scripts. 1126 * 1127 * @since 6.9.0 1128 * @see self::filter_eligible_strategies() 1129 * @see WP_Script_Modules::get_highest_fetchpriority() 1130 * 1131 * @param string $handle Script module ID. 1132 * @param array<string, true> $checked Optional. An array of already checked script handles, used to avoid recursive loops. 1133 * @param array<string, string> $stored_results Optional. An array of already computed max priority by handle, used to increase performance in large dependency lists. 1134 * @return string|null Highest fetch priority for the script and its dependents. 1135 */ 1136 private function get_highest_fetchpriority_with_dependents( string $handle, array $checked = array(), array &$stored_results = array() ): ?string { 1137 if ( isset( $stored_results[ $handle ] ) ) { 1138 return $stored_results[ $handle ]; 1139 } 1140 1141 // If there is a recursive dependency, return early. 1142 if ( isset( $checked[ $handle ] ) ) { 1143 return null; 1144 } 1145 1146 // Mark this handle as checked to guard against infinite recursion. 1147 $checked[ $handle ] = true; 1148 1149 // Abort if the script is not enqueued or a dependency of an enqueued script. 1150 if ( ! $this->query( $handle, 'enqueued' ) ) { 1151 return null; 1152 } 1153 1154 $fetchpriority = $this->get_data( $handle, 'fetchpriority' ); 1155 if ( ! $this->is_valid_fetchpriority( $fetchpriority ) ) { 1156 $fetchpriority = 'auto'; 1157 } 1158 1159 static $priorities = array( 1160 'low', 1161 'auto', 1162 'high', 1163 ); 1164 $high_priority_index = count( $priorities ) - 1; 1165 1166 $highest_priority_index = (int) array_search( $fetchpriority, $priorities, true ); 1167 if ( $highest_priority_index !== $high_priority_index ) { 1168 foreach ( $this->get_dependents( $handle ) as $dependent_handle ) { 1169 $dependent_priority = $this->get_highest_fetchpriority_with_dependents( $dependent_handle, $checked, $stored_results ); 1170 if ( is_string( $dependent_priority ) ) { 1171 $highest_priority_index = max( 1172 $highest_priority_index, 1173 (int) array_search( $dependent_priority, $priorities, true ) 1174 ); 1175 if ( $highest_priority_index === $high_priority_index ) { 1176 break; 1177 } 1178 } 1179 } 1180 } 1181 $stored_results[ $handle ] = $priorities[ $highest_priority_index ]; 1182 return $priorities[ $highest_priority_index ]; 1183 } 1184 1185 /** 1186 * Gets data for inline scripts registered for a specific handle. 1187 * 1188 * @since 6.3.0 1189 * 1190 * @param string $handle Name of the script to get data for. Must be lowercase. 1191 * @param string $position The position of the inline script. 1192 * @return bool Whether the handle has an inline script (either before or after). 1193 */ 1194 private function has_inline_script( $handle, $position = null ) { 1195 if ( $position && in_array( $position, array( 'before', 'after' ), true ) ) { 1196 return (bool) $this->get_data( $handle, $position ); 1197 } 1198 1199 return (bool) ( $this->get_data( $handle, 'before' ) || $this->get_data( $handle, 'after' ) ); 1200 } 1201 1202 /** 1203 * Resets class properties. 1204 * 1205 * @since 2.8.0 1206 */ 1207 public function reset() { 1208 $this->do_concat = false; 1209 $this->print_code = ''; 1210 $this->concat = ''; 1211 $this->concat_version = ''; 1212 $this->print_html = ''; 1213 $this->ext_version = ''; 1214 $this->ext_handles = ''; 1215 } 1216 1217 /** 1218 * Gets a script-specific dependency warning message. 1219 * 1220 * @since 6.9.1 1221 * 1222 * @param string $handle Script handle with missing dependencies. 1223 * @param string[] $missing_dependency_handles Missing dependency handles. 1224 * @return string Formatted, localized warning message. 1225 */ 1226 protected function get_dependency_warning_message( $handle, $missing_dependency_handles ) { 1227 return sprintf( 1228 /* translators: 1: Script handle, 2: List of missing dependency handles. */ 1229 __( 'The script with the handle "%1$s" was enqueued with dependencies that are not registered: %2$s.' ), 1230 $handle, 1231 implode( wp_get_list_item_separator(), $missing_dependency_handles ) 1232 ); 1233 } 1234 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated : Tue Nov 3 08:20:36 2026 | Cross-referenced by PHPXref |