[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/ -> class-wp-scripts.php (source)

   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 . '&amp;' . $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  }


Generated : Thu Sep 4 08:20:02 2025 Cross-referenced by PHPXref