[ 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 $tag = $translations . $ie_conditional_prefix . $before_script; 429 $tag .= wp_get_script_tag( $attr ); 430 $tag .= $after_script . $ie_conditional_suffix; 431 432 /** 433 * Filters the HTML script tag of an enqueued script. 434 * 435 * @since 4.1.0 436 * 437 * @param string $tag The `<script>` tag for the enqueued script. 438 * @param string $handle The script's registered handle. 439 * @param string $src The script's source URL. 440 */ 441 $tag = apply_filters( 'script_loader_tag', $tag, $handle, $src ); 442 443 if ( $this->do_concat ) { 444 $this->print_html .= $tag; 445 } else { 446 echo $tag; 447 } 448 449 return true; 450 } 451 452 /** 453 * Adds extra code to a registered script. 454 * 455 * @since 4.5.0 456 * 457 * @param string $handle Name of the script to add the inline script to. 458 * Must be lowercase. 459 * @param string $data String containing the JavaScript to be added. 460 * @param string $position Optional. Whether to add the inline script 461 * before the handle or after. Default 'after'. 462 * @return bool True on success, false on failure. 463 */ 464 public function add_inline_script( $handle, $data, $position = 'after' ) { 465 if ( ! $data ) { 466 return false; 467 } 468 469 if ( 'after' !== $position ) { 470 $position = 'before'; 471 } 472 473 $script = (array) $this->get_data( $handle, $position ); 474 $script[] = $data; 475 476 return $this->add_data( $handle, $position, $script ); 477 } 478 479 /** 480 * Prints inline scripts registered for a specific handle. 481 * 482 * @since 4.5.0 483 * @deprecated 6.3.0 Use methods get_inline_script_tag() or get_inline_script_data() instead. 484 * 485 * @param string $handle Name of the script to print inline scripts for. 486 * Must be lowercase. 487 * @param string $position Optional. Whether to add the inline script 488 * before the handle or after. Default 'after'. 489 * @param bool $display Optional. Whether to print the script tag 490 * instead of just returning the script data. Default true. 491 * @return string|false Script data on success, false otherwise. 492 */ 493 public function print_inline_script( $handle, $position = 'after', $display = true ) { 494 _deprecated_function( __METHOD__, '6.3.0', 'WP_Scripts::get_inline_script_data() or WP_Scripts::get_inline_script_tag()' ); 495 496 $output = $this->get_inline_script_data( $handle, $position ); 497 if ( empty( $output ) ) { 498 return false; 499 } 500 501 if ( $display ) { 502 echo $this->get_inline_script_tag( $handle, $position ); 503 } 504 return $output; 505 } 506 507 /** 508 * Gets data for inline scripts registered for a specific handle. 509 * 510 * @since 6.3.0 511 * 512 * @param string $handle Name of the script to get data for. 513 * Must be lowercase. 514 * @param string $position Optional. Whether to add the inline script 515 * before the handle or after. Default 'after'. 516 * @return string Inline script, which may be empty string. 517 */ 518 public function get_inline_script_data( $handle, $position = 'after' ) { 519 $data = $this->get_data( $handle, $position ); 520 if ( empty( $data ) || ! is_array( $data ) ) { 521 return ''; 522 } 523 524 return trim( implode( "\n", $data ), "\n" ); 525 } 526 527 /** 528 * Gets tags for inline scripts registered for a specific handle. 529 * 530 * @since 6.3.0 531 * 532 * @param string $handle Name of the script to get associated inline script tag for. 533 * Must be lowercase. 534 * @param string $position Optional. Whether to get tag for inline 535 * scripts in the before or after position. Default 'after'. 536 * @return string Inline script, which may be empty string. 537 */ 538 public function get_inline_script_tag( $handle, $position = 'after' ) { 539 $js = $this->get_inline_script_data( $handle, $position ); 540 if ( empty( $js ) ) { 541 return ''; 542 } 543 544 $id = "{$handle}-js-{$position}"; 545 546 return wp_get_inline_script_tag( $js, compact( 'id' ) ); 547 } 548 549 /** 550 * Localizes a script, only if the script has already been added. 551 * 552 * @since 2.1.0 553 * 554 * @param string $handle Name of the script to attach data to. 555 * @param string $object_name Name of the variable that will contain the data. 556 * @param array $l10n Array of data to localize. 557 * @return bool True on success, false on failure. 558 */ 559 public function localize( $handle, $object_name, $l10n ) { 560 if ( 'jquery' === $handle ) { 561 $handle = 'jquery-core'; 562 } 563 564 if ( is_array( $l10n ) && isset( $l10n['l10n_print_after'] ) ) { // back compat, preserve the code in 'l10n_print_after' if present. 565 $after = $l10n['l10n_print_after']; 566 unset( $l10n['l10n_print_after'] ); 567 } 568 569 if ( ! is_array( $l10n ) ) { 570 _doing_it_wrong( 571 __METHOD__, 572 sprintf( 573 /* translators: 1: $l10n, 2: wp_add_inline_script() */ 574 __( 'The %1$s parameter must be an array. To pass arbitrary data to scripts, use the %2$s function instead.' ), 575 '<code>$l10n</code>', 576 '<code>wp_add_inline_script()</code>' 577 ), 578 '5.7.0' 579 ); 580 581 if ( false === $l10n ) { 582 // This should really not be needed, but is necessary for backward compatibility. 583 $l10n = array( $l10n ); 584 } 585 } 586 587 if ( is_string( $l10n ) ) { 588 $l10n = html_entity_decode( $l10n, ENT_QUOTES, 'UTF-8' ); 589 } elseif ( is_array( $l10n ) ) { 590 foreach ( $l10n as $key => $value ) { 591 if ( ! is_scalar( $value ) ) { 592 continue; 593 } 594 595 $l10n[ $key ] = html_entity_decode( (string) $value, ENT_QUOTES, 'UTF-8' ); 596 } 597 } 598 599 $script = "var $object_name = " . wp_json_encode( $l10n ) . ';'; 600 601 if ( ! empty( $after ) ) { 602 $script .= "\n$after;"; 603 } 604 605 $data = $this->get_data( $handle, 'data' ); 606 607 if ( ! empty( $data ) ) { 608 $script = "$data\n$script"; 609 } 610 611 return $this->add_data( $handle, 'data', $script ); 612 } 613 614 /** 615 * Sets handle group. 616 * 617 * @since 2.8.0 618 * 619 * @see WP_Dependencies::set_group() 620 * 621 * @param string $handle Name of the item. Should be unique. 622 * @param bool $recursion Internal flag that calling function was called recursively. 623 * @param int|false $group Optional. Group level: level (int), no groups (false). 624 * Default false. 625 * @return bool Not already in the group or a lower group. 626 */ 627 public function set_group( $handle, $recursion, $group = false ) { 628 if ( isset( $this->registered[ $handle ]->args ) && 1 === $this->registered[ $handle ]->args ) { 629 $calculated_group = 1; 630 } else { 631 $calculated_group = (int) $this->get_data( $handle, 'group' ); 632 } 633 634 if ( false !== $group && $calculated_group > $group ) { 635 $calculated_group = $group; 636 } 637 638 return parent::set_group( $handle, $recursion, $calculated_group ); 639 } 640 641 /** 642 * Sets a translation textdomain. 643 * 644 * @since 5.0.0 645 * @since 5.1.0 The `$domain` parameter was made optional. 646 * 647 * @param string $handle Name of the script to register a translation domain to. 648 * @param string $domain Optional. Text domain. Default 'default'. 649 * @param string $path Optional. The full file path to the directory containing translation files. 650 * @return bool True if the text domain was registered, false if not. 651 */ 652 public function set_translations( $handle, $domain = 'default', $path = '' ) { 653 if ( ! isset( $this->registered[ $handle ] ) ) { 654 return false; 655 } 656 657 /** @var \_WP_Dependency $obj */ 658 $obj = $this->registered[ $handle ]; 659 660 if ( ! in_array( 'wp-i18n', $obj->deps, true ) ) { 661 $obj->deps[] = 'wp-i18n'; 662 } 663 664 return $obj->set_translations( $domain, $path ); 665 } 666 667 /** 668 * Prints translations set for a specific handle. 669 * 670 * @since 5.0.0 671 * 672 * @param string $handle Name of the script to add the inline script to. 673 * Must be lowercase. 674 * @param bool $display Optional. Whether to print the script 675 * instead of just returning it. Default true. 676 * @return string|false Script on success, false otherwise. 677 */ 678 public function print_translations( $handle, $display = true ) { 679 if ( ! isset( $this->registered[ $handle ] ) || empty( $this->registered[ $handle ]->textdomain ) ) { 680 return false; 681 } 682 683 $domain = $this->registered[ $handle ]->textdomain; 684 $path = ''; 685 686 if ( isset( $this->registered[ $handle ]->translations_path ) ) { 687 $path = $this->registered[ $handle ]->translations_path; 688 } 689 690 $json_translations = load_script_textdomain( $handle, $domain, $path ); 691 692 if ( ! $json_translations ) { 693 return false; 694 } 695 696 $output = <<<JS 697 ( function( domain, translations ) { 698 var localeData = translations.locale_data[ domain ] || translations.locale_data.messages; 699 localeData[""].domain = domain; 700 wp.i18n.setLocaleData( localeData, domain ); 701 } )( "{$domain}", {$json_translations} ); 702 JS; 703 704 if ( $display ) { 705 wp_print_inline_script_tag( $output, array( 'id' => "{$handle}-js-translations" ) ); 706 } 707 708 return $output; 709 } 710 711 /** 712 * Determines script dependencies. 713 * 714 * @since 2.1.0 715 * 716 * @see WP_Dependencies::all_deps() 717 * 718 * @param string|string[] $handles Item handle (string) or item handles (array of strings). 719 * @param bool $recursion Optional. Internal flag that function is calling itself. 720 * Default false. 721 * @param int|false $group Optional. Group level: level (int), no groups (false). 722 * Default false. 723 * @return bool True on success, false on failure. 724 */ 725 public function all_deps( $handles, $recursion = false, $group = false ) { 726 $result = parent::all_deps( $handles, $recursion, $group ); 727 if ( ! $recursion ) { 728 /** 729 * Filters the list of script dependencies left to print. 730 * 731 * @since 2.3.0 732 * 733 * @param string[] $to_do An array of script dependency handles. 734 */ 735 $this->to_do = apply_filters( 'print_scripts_array', $this->to_do ); 736 } 737 return $result; 738 } 739 740 /** 741 * Processes items and dependencies for the head group. 742 * 743 * @since 2.8.0 744 * 745 * @see WP_Dependencies::do_items() 746 * 747 * @return string[] Handles of items that have been processed. 748 */ 749 public function do_head_items() { 750 $this->do_items( false, 0 ); 751 return $this->done; 752 } 753 754 /** 755 * Processes items and dependencies for the footer group. 756 * 757 * @since 2.8.0 758 * 759 * @see WP_Dependencies::do_items() 760 * 761 * @return string[] Handles of items that have been processed. 762 */ 763 public function do_footer_items() { 764 $this->do_items( false, 1 ); 765 return $this->done; 766 } 767 768 /** 769 * Whether a handle's source is in a default directory. 770 * 771 * @since 2.8.0 772 * 773 * @param string $src The source of the enqueued script. 774 * @return bool True if found, false if not. 775 */ 776 public function in_default_dir( $src ) { 777 if ( ! $this->default_dirs ) { 778 return true; 779 } 780 781 if ( str_starts_with( $src, '/' . WPINC . '/js/l10n' ) ) { 782 return false; 783 } 784 785 foreach ( (array) $this->default_dirs as $test ) { 786 if ( str_starts_with( $src, $test ) ) { 787 return true; 788 } 789 } 790 return false; 791 } 792 793 /** 794 * This overrides the add_data method from WP_Dependencies, to support normalizing of $args. 795 * 796 * @since 6.3.0 797 * 798 * @param string $handle Name of the item. Should be unique. 799 * @param string $key The data key. 800 * @param mixed $value The data value. 801 * @return bool True on success, false on failure. 802 */ 803 public function add_data( $handle, $key, $value ) { 804 if ( ! isset( $this->registered[ $handle ] ) ) { 805 return false; 806 } 807 808 if ( 'strategy' === $key ) { 809 if ( ! empty( $value ) && ! $this->is_delayed_strategy( $value ) ) { 810 _doing_it_wrong( 811 __METHOD__, 812 sprintf( 813 /* translators: 1: $strategy, 2: $handle */ 814 __( 'Invalid strategy `%1$s` defined for `%2$s` during script registration.' ), 815 $value, 816 $handle 817 ), 818 '6.3.0' 819 ); 820 return false; 821 } elseif ( ! $this->registered[ $handle ]->src && $this->is_delayed_strategy( $value ) ) { 822 _doing_it_wrong( 823 __METHOD__, 824 sprintf( 825 /* translators: 1: $strategy, 2: $handle */ 826 __( 'Cannot supply a strategy `%1$s` for script `%2$s` because it is an alias (it lacks a `src` value).' ), 827 $value, 828 $handle 829 ), 830 '6.3.0' 831 ); 832 return false; 833 } 834 } 835 return parent::add_data( $handle, $key, $value ); 836 } 837 838 /** 839 * Gets all dependents of a script. 840 * 841 * @since 6.3.0 842 * 843 * @param string $handle The script handle. 844 * @return string[] Script handles. 845 */ 846 private function get_dependents( $handle ) { 847 // Check if dependents map for the handle in question is present. If so, use it. 848 if ( isset( $this->dependents_map[ $handle ] ) ) { 849 return $this->dependents_map[ $handle ]; 850 } 851 852 $dependents = array(); 853 854 // Iterate over all registered scripts, finding dependents of the script passed to this method. 855 foreach ( $this->registered as $registered_handle => $args ) { 856 if ( in_array( $handle, $args->deps, true ) ) { 857 $dependents[] = $registered_handle; 858 } 859 } 860 861 // Add the handles dependents to the map to ease future lookups. 862 $this->dependents_map[ $handle ] = $dependents; 863 864 return $dependents; 865 } 866 867 /** 868 * Checks if the strategy passed is a valid delayed (non-blocking) strategy. 869 * 870 * @since 6.3.0 871 * 872 * @param string $strategy The strategy to check. 873 * @return bool True if $strategy is one of the delayed strategies, otherwise false. 874 */ 875 private function is_delayed_strategy( $strategy ) { 876 return in_array( 877 $strategy, 878 $this->delayed_strategies, 879 true 880 ); 881 } 882 883 /** 884 * Gets the best eligible loading strategy for a script. 885 * 886 * @since 6.3.0 887 * 888 * @param string $handle The script handle. 889 * @return string The best eligible loading strategy. 890 */ 891 private function get_eligible_loading_strategy( $handle ) { 892 $intended_strategy = (string) $this->get_data( $handle, 'strategy' ); 893 894 // Bail early if there is no intended strategy. 895 if ( ! $intended_strategy ) { 896 return ''; 897 } 898 899 /* 900 * If the intended strategy is 'defer', limit the initial list of eligible 901 * strategies, since 'async' can fallback to 'defer', but not vice-versa. 902 */ 903 $initial_strategy = ( 'defer' === $intended_strategy ) ? array( 'defer' ) : null; 904 905 $eligible_strategies = $this->filter_eligible_strategies( $handle, $initial_strategy ); 906 907 // Return early once we know the eligible strategy is blocking. 908 if ( empty( $eligible_strategies ) ) { 909 return ''; 910 } 911 912 return in_array( 'async', $eligible_strategies, true ) ? 'async' : 'defer'; 913 } 914 915 /** 916 * Filter the list of eligible loading strategies for a script. 917 * 918 * @since 6.3.0 919 * 920 * @param string $handle The script handle. 921 * @param string[]|null $eligible_strategies Optional. The list of strategies to filter. Default null. 922 * @param array<string, true> $checked Optional. An array of already checked script handles, used to avoid recursive loops. 923 * @return string[] A list of eligible loading strategies that could be used. 924 */ 925 private function filter_eligible_strategies( $handle, $eligible_strategies = null, $checked = array() ) { 926 // If no strategies are being passed, all strategies are eligible. 927 if ( null === $eligible_strategies ) { 928 $eligible_strategies = $this->delayed_strategies; 929 } 930 931 // If this handle was already checked, return early. 932 if ( isset( $checked[ $handle ] ) ) { 933 return $eligible_strategies; 934 } 935 936 // Mark this handle as checked. 937 $checked[ $handle ] = true; 938 939 // If this handle isn't registered, don't filter anything and return. 940 if ( ! isset( $this->registered[ $handle ] ) ) { 941 return $eligible_strategies; 942 } 943 944 // If the handle is not enqueued, don't filter anything and return. 945 if ( ! $this->query( $handle, 'enqueued' ) ) { 946 return $eligible_strategies; 947 } 948 949 $is_alias = (bool) ! $this->registered[ $handle ]->src; 950 $intended_strategy = $this->get_data( $handle, 'strategy' ); 951 952 // For non-alias handles, an empty intended strategy filters all strategies. 953 if ( ! $is_alias && empty( $intended_strategy ) ) { 954 return array(); 955 } 956 957 // Handles with inline scripts attached in the 'after' position cannot be delayed. 958 if ( $this->has_inline_script( $handle, 'after' ) ) { 959 return array(); 960 } 961 962 // If the intended strategy is 'defer', filter out 'async'. 963 if ( 'defer' === $intended_strategy ) { 964 $eligible_strategies = array( 'defer' ); 965 } 966 967 $dependents = $this->get_dependents( $handle ); 968 969 // Recursively filter eligible strategies for dependents. 970 foreach ( $dependents as $dependent ) { 971 // Bail early once we know the eligible strategy is blocking. 972 if ( empty( $eligible_strategies ) ) { 973 return array(); 974 } 975 976 $eligible_strategies = $this->filter_eligible_strategies( $dependent, $eligible_strategies, $checked ); 977 } 978 979 return $eligible_strategies; 980 } 981 982 /** 983 * Gets data for inline scripts registered for a specific handle. 984 * 985 * @since 6.3.0 986 * 987 * @param string $handle Name of the script to get data for. Must be lowercase. 988 * @param string $position The position of the inline script. 989 * @return bool Whether the handle has an inline script (either before or after). 990 */ 991 private function has_inline_script( $handle, $position = null ) { 992 if ( $position && in_array( $position, array( 'before', 'after' ), true ) ) { 993 return (bool) $this->get_data( $handle, $position ); 994 } 995 996 return (bool) ( $this->get_data( $handle, 'before' ) || $this->get_data( $handle, 'after' ) ); 997 } 998 999 /** 1000 * Resets class properties. 1001 * 1002 * @since 2.8.0 1003 */ 1004 public function reset() { 1005 $this->do_concat = false; 1006 $this->print_code = ''; 1007 $this->concat = ''; 1008 $this->concat_version = ''; 1009 $this->print_html = ''; 1010 $this->ext_version = ''; 1011 $this->ext_handles = ''; 1012 } 1013 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated : Thu Nov 21 08:20:01 2024 | Cross-referenced by PHPXref |