[ 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          $cond_before       = '';
 296          $cond_after        = '';
 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              $cond_before = "<!--[if {$conditional}]>\n";
 324              $cond_after  = "<![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 = $cond_before . $before_script . $after_script . $cond_after;
 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              $srce = apply_filters( 'script_loader_src', $src, $handle );
 357  
 358              if (
 359                  $this->in_default_dir( $srce )
 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( $srce ) && ! $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 $cond_before;
 382          }
 383  
 384          $this->print_extra_script( $handle );
 385  
 386          if ( $has_conditional_data ) {
 387              echo $cond_after;
 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 . $cond_before . $before_script;
 429          $tag .= wp_get_script_tag( $attr );
 430          $tag .= $after_script . $cond_after;
 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              $grp = 1;
 630          } else {
 631              $grp = (int) $this->get_data( $handle, 'group' );
 632          }
 633  
 634          if ( false !== $group && $grp > $group ) {
 635              $grp = $group;
 636          }
 637  
 638          return parent::set_group( $handle, $recursion, $grp );
 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          $r = 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 $r;
 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 = (string) $this->get_data( $handle, 'strategy' );
 893  
 894          // Bail early if there is no intended strategy.
 895          if ( ! $intended ) {
 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 = ( 'defer' === $intended ) ? array( 'defer' ) : null;
 904  
 905          $eligible = $this->filter_eligible_strategies( $handle, $initial );
 906  
 907          // Return early once we know the eligible strategy is blocking.
 908          if ( empty( $eligible ) ) {
 909              return '';
 910          }
 911  
 912          return in_array( 'async', $eligible, 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 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 = null, $checked = array() ) {
 926          // If no strategies are being passed, all strategies are eligible.
 927          if ( null === $eligible ) {
 928              $eligible = $this->delayed_strategies;
 929          }
 930  
 931          // If this handle was already checked, return early.
 932          if ( isset( $checked[ $handle ] ) ) {
 933              return $eligible;
 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;
 942          }
 943  
 944          // If the handle is not enqueued, don't filter anything and return.
 945          if ( ! $this->query( $handle, 'enqueued' ) ) {
 946              return $eligible;
 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 = 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 ) ) {
 973                  return array();
 974              }
 975  
 976              $eligible = $this->filter_eligible_strategies( $dependent, $eligible, $checked );
 977          }
 978  
 979          return $eligible;
 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  }


Generated : Fri Apr 26 08:20:02 2024 Cross-referenced by PHPXref