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