[ Index ]

PHP Cross Reference of WordPress

title

Body

[close]

/wp-includes/ -> script-loader.php (source)

   1  <?php
   2  /**
   3   * WordPress scripts and styles default loader.
   4   *
   5   * Several constants are used to manage the loading, concatenating and compression of scripts and CSS:
   6   * define('SCRIPT_DEBUG', true); loads the development (non-minified) versions of all scripts and CSS, and disables compression and concatenation,
   7   * define('CONCATENATE_SCRIPTS', false); disables compression and concatenation of scripts and CSS,
   8   * define('COMPRESS_SCRIPTS', false); disables compression of scripts,
   9   * define('COMPRESS_CSS', false); disables compression of CSS,
  10   * define('ENFORCE_GZIP', true); forces gzip for compression (default is deflate).
  11   *
  12   * The globals $concatenate_scripts, $compress_scripts and $compress_css can be set by plugins
  13   * to temporarily override the above settings. Also a compression test is run once and the result is saved
  14   * as option 'can_compress_scripts' (0/1). The test will run again if that option is deleted.
  15   *
  16   * @package WordPress
  17   */
  18  
  19  /** WordPress Dependency Class */
  20  require  ABSPATH . WPINC . '/class-wp-dependency.php';
  21  
  22  /** WordPress Dependencies Class */
  23  require  ABSPATH . WPINC . '/class.wp-dependencies.php';
  24  
  25  /** WordPress Scripts Class */
  26  require  ABSPATH . WPINC . '/class.wp-scripts.php';
  27  
  28  /** WordPress Scripts Functions */
  29  require  ABSPATH . WPINC . '/functions.wp-scripts.php';
  30  
  31  /** WordPress Styles Class */
  32  require  ABSPATH . WPINC . '/class.wp-styles.php';
  33  
  34  /** WordPress Styles Functions */
  35  require  ABSPATH . WPINC . '/functions.wp-styles.php';
  36  
  37  /**
  38   * Registers TinyMCE scripts.
  39   *
  40   * @since 5.0.0
  41   *
  42   * @global string $tinymce_version
  43   * @global bool   $concatenate_scripts
  44   * @global bool   $compress_scripts
  45   *
  46   * @param WP_Scripts $scripts            WP_Scripts object.
  47   * @param bool       $force_uncompressed Whether to forcibly prevent gzip compression. Default false.
  48   */
  49  function wp_register_tinymce_scripts( $scripts, $force_uncompressed = false ) {
  50      global $tinymce_version, $concatenate_scripts, $compress_scripts;
  51  
  52      $suffix     = wp_scripts_get_suffix();
  53      $dev_suffix = wp_scripts_get_suffix( 'dev' );
  54  
  55      script_concat_settings();
  56  
  57      $compressed = $compress_scripts && $concatenate_scripts && isset( $_SERVER['HTTP_ACCEPT_ENCODING'] )
  58          && false !== stripos( $_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip' ) && ! $force_uncompressed;
  59  
  60      // Load tinymce.js when running from /src, otherwise load wp-tinymce.js.gz (in production)
  61      // or tinymce.min.js (when SCRIPT_DEBUG is true).
  62      if ( $compressed ) {
  63          $scripts->add( 'wp-tinymce', includes_url( 'js/tinymce/' ) . 'wp-tinymce.js', array(), $tinymce_version );
  64      } else {
  65          $scripts->add( 'wp-tinymce-root', includes_url( 'js/tinymce/' ) . "tinymce$dev_suffix.js", array(), $tinymce_version );
  66          $scripts->add( 'wp-tinymce', includes_url( 'js/tinymce/' ) . "plugins/compat3x/plugin$dev_suffix.js", array( 'wp-tinymce-root' ), $tinymce_version );
  67      }
  68  
  69      $scripts->add( 'wp-tinymce-lists', includes_url( "js/tinymce/plugins/lists/plugin$suffix.js" ), array( 'wp-tinymce' ), $tinymce_version );
  70  }
  71  
  72  /**
  73   * Registers all the WordPress vendor scripts that are in the standardized
  74   * `js/dist/vendor/` location.
  75   *
  76   * For the order of `$scripts->add` see `wp_default_scripts`.
  77   *
  78   * @since 5.0.0
  79   *
  80   * @global WP_Locale $wp_locale WordPress date and time locale object.
  81   *
  82   * @param WP_Scripts $scripts WP_Scripts object.
  83   */
  84  function wp_default_packages_vendor( $scripts ) {
  85      global $wp_locale;
  86  
  87      $suffix = wp_scripts_get_suffix();
  88  
  89      $vendor_scripts = array(
  90          'react'       => array( 'wp-polyfill' ),
  91          'react-dom'   => array( 'react' ),
  92          'regenerator-runtime',
  93          'moment',
  94          'lodash',
  95          'wp-polyfill-fetch',
  96          'wp-polyfill-formdata',
  97          'wp-polyfill-node-contains',
  98          'wp-polyfill-url',
  99          'wp-polyfill-dom-rect',
 100          'wp-polyfill-element-closest',
 101          'wp-polyfill-object-fit',
 102          'wp-polyfill' => array( 'regenerator-runtime' ),
 103      );
 104  
 105      $vendor_scripts_versions = array(
 106          'react'                       => '17.0.1',
 107          'react-dom'                   => '17.0.1',
 108          'regenerator-runtime'         => '0.13.9',
 109          'moment'                      => '2.29.2',
 110          'lodash'                      => '4.17.19',
 111          'wp-polyfill-fetch'           => '3.6.2',
 112          'wp-polyfill-formdata'        => '4.0.10',
 113          'wp-polyfill-node-contains'   => '4.0.0',
 114          'wp-polyfill-url'             => '3.6.4',
 115          'wp-polyfill-dom-rect'        => '4.0.0',
 116          'wp-polyfill-element-closest' => '2.0.2',
 117          'wp-polyfill-object-fit'      => '2.3.5',
 118          'wp-polyfill'                 => '3.15.0',
 119      );
 120  
 121      foreach ( $vendor_scripts as $handle => $dependencies ) {
 122          if ( is_string( $dependencies ) ) {
 123              $handle       = $dependencies;
 124              $dependencies = array();
 125          }
 126  
 127          $path    = "/wp-includes/js/dist/vendor/$handle$suffix.js";
 128          $version = $vendor_scripts_versions[ $handle ];
 129  
 130          $scripts->add( $handle, $path, $dependencies, $version, 1 );
 131      }
 132  
 133      did_action( 'init' ) && $scripts->add_inline_script( 'lodash', 'window.lodash = _.noConflict();' );
 134  
 135      did_action( 'init' ) && $scripts->add_inline_script(
 136          'moment',
 137          sprintf(
 138              "moment.updateLocale( '%s', %s );",
 139              get_user_locale(),
 140              wp_json_encode(
 141                  array(
 142                      'months'         => array_values( $wp_locale->month ),
 143                      'monthsShort'    => array_values( $wp_locale->month_abbrev ),
 144                      'weekdays'       => array_values( $wp_locale->weekday ),
 145                      'weekdaysShort'  => array_values( $wp_locale->weekday_abbrev ),
 146                      'week'           => array(
 147                          'dow' => (int) get_option( 'start_of_week', 0 ),
 148                      ),
 149                      'longDateFormat' => array(
 150                          'LT'   => get_option( 'time_format', __( 'g:i a' ) ),
 151                          'LTS'  => null,
 152                          'L'    => null,
 153                          'LL'   => get_option( 'date_format', __( 'F j, Y' ) ),
 154                          'LLL'  => __( 'F j, Y g:i a' ),
 155                          'LLLL' => null,
 156                      ),
 157                  )
 158              )
 159          ),
 160          'after'
 161      );
 162  }
 163  
 164  /**
 165   * Returns contents of an inline script used in appending polyfill scripts for
 166   * browsers which fail the provided tests. The provided array is a mapping from
 167   * a condition to verify feature support to its polyfill script handle.
 168   *
 169   * @since 5.0.0
 170   *
 171   * @param WP_Scripts $scripts WP_Scripts object.
 172   * @param array      $tests   Features to detect.
 173   * @return string Conditional polyfill inline script.
 174   */
 175  function wp_get_script_polyfill( $scripts, $tests ) {
 176      $polyfill = '';
 177      foreach ( $tests as $test => $handle ) {
 178          if ( ! array_key_exists( $handle, $scripts->registered ) ) {
 179              continue;
 180          }
 181  
 182          $src = $scripts->registered[ $handle ]->src;
 183          $ver = $scripts->registered[ $handle ]->ver;
 184  
 185          if ( ! preg_match( '|^(https?:)?//|', $src ) && ! ( $scripts->content_url && 0 === strpos( $src, $scripts->content_url ) ) ) {
 186              $src = $scripts->base_url . $src;
 187          }
 188  
 189          if ( ! empty( $ver ) ) {
 190              $src = add_query_arg( 'ver', $ver, $src );
 191          }
 192  
 193          /** This filter is documented in wp-includes/class.wp-scripts.php */
 194          $src = esc_url( apply_filters( 'script_loader_src', $src, $handle ) );
 195  
 196          if ( ! $src ) {
 197              continue;
 198          }
 199  
 200          $polyfill .= (
 201              // Test presence of feature...
 202              '( ' . $test . ' ) || ' .
 203              /*
 204               * ...appending polyfill on any failures. Cautious viewers may balk
 205               * at the `document.write`. Its caveat of synchronous mid-stream
 206               * blocking write is exactly the behavior we need though.
 207               */
 208              'document.write( \'<script src="' .
 209              $src .
 210              '"></scr\' + \'ipt>\' );'
 211          );
 212      }
 213  
 214      return $polyfill;
 215  }
 216  
 217  /**
 218   * Registers development scripts that integrate with `@wordpress/scripts`.
 219   *
 220   * @see https://github.com/WordPress/gutenberg/tree/trunk/packages/scripts#start
 221   *
 222   * @since 6.0.0
 223   *
 224   * @param WP_Scripts $scripts WP_Scripts object.
 225   */
 226  function wp_register_development_scripts( $scripts ) {
 227      if (
 228          ! defined( 'SCRIPT_DEBUG' ) || ! SCRIPT_DEBUG
 229          || empty( $scripts->registered['react'] )
 230      ) {
 231          return;
 232      }
 233  
 234      $development_scripts = array(
 235          'react-refresh-entry',
 236          'react-refresh-runtime',
 237      );
 238  
 239      foreach ( $development_scripts as $script_name ) {
 240          $assets = include ABSPATH . WPINC . '/assets/script-loader-' . $script_name . '.php';
 241          if ( ! is_array( $assets ) ) {
 242              return;
 243          }
 244          $scripts->add(
 245              'wp-' . $script_name,
 246              '/wp-includes/js/dist/development/' . $script_name . '.js',
 247              $assets['dependencies'],
 248              $assets['version']
 249          );
 250      }
 251  
 252      // See https://github.com/pmmmwh/react-refresh-webpack-plugin/blob/main/docs/TROUBLESHOOTING.md#externalising-react.
 253      $scripts->registered['react']->deps[] = 'wp-react-refresh-entry';
 254  }
 255  
 256  /**
 257   * Registers all the WordPress packages scripts that are in the standardized
 258   * `js/dist/` location.
 259   *
 260   * For the order of `$scripts->add` see `wp_default_scripts`.
 261   *
 262   * @since 5.0.0
 263   *
 264   * @param WP_Scripts $scripts WP_Scripts object.
 265   */
 266  function wp_default_packages_scripts( $scripts ) {
 267      $suffix = wp_scripts_get_suffix();
 268  
 269      /*
 270       * Expects multidimensional array like:
 271       *
 272       *     'a11y.js' => array('dependencies' => array(...), 'version' => '...'),
 273       *     'annotations.js' => array('dependencies' => array(...), 'version' => '...'),
 274       *     'api-fetch.js' => array(...
 275       */
 276      $assets = include  ABSPATH . WPINC . '/assets/script-loader-packages.php';
 277  
 278      foreach ( $assets as $package_name => $package_data ) {
 279          $basename = basename( $package_name, '.js' );
 280          $handle   = 'wp-' . $basename;
 281          $path     = "/wp-includes/js/dist/{$basename}{$suffix}.js";
 282  
 283          if ( ! empty( $package_data['dependencies'] ) ) {
 284              $dependencies = $package_data['dependencies'];
 285          } else {
 286              $dependencies = array();
 287          }
 288  
 289          // Add dependencies that cannot be detected and generated by build tools.
 290          switch ( $handle ) {
 291              case 'wp-block-library':
 292                  array_push( $dependencies, 'editor' );
 293                  break;
 294              case 'wp-edit-post':
 295                  array_push( $dependencies, 'media-models', 'media-views', 'postbox', 'wp-dom-ready' );
 296                  break;
 297          }
 298  
 299          $scripts->add( $handle, $path, $dependencies, $package_data['version'], 1 );
 300  
 301          if ( in_array( 'wp-i18n', $dependencies, true ) ) {
 302              $scripts->set_translations( $handle );
 303          }
 304  
 305          /*
 306           * Manually set the text direction localization after wp-i18n is printed.
 307           * This ensures that wp.i18n.isRTL() returns true in RTL languages.
 308           * We cannot use $scripts->set_translations( 'wp-i18n' ) to do this
 309           * because WordPress prints a script's translations *before* the script,
 310           * which means, in the case of wp-i18n, that wp.i18n.setLocaleData()
 311           * is called before wp.i18n is defined.
 312           */
 313          if ( 'wp-i18n' === $handle ) {
 314              $ltr    = _x( 'ltr', 'text direction' );
 315              $script = sprintf( "wp.i18n.setLocaleData( { 'text direction\u0004ltr': [ '%s' ] } );", $ltr );
 316              $scripts->add_inline_script( $handle, $script, 'after' );
 317          }
 318      }
 319  }
 320  
 321  /**
 322   * Adds inline scripts required for the WordPress JavaScript packages.
 323   *
 324   * @since 5.0.0
 325   *
 326   * @global WP_Locale $wp_locale WordPress date and time locale object.
 327   *
 328   * @param WP_Scripts $scripts WP_Scripts object.
 329   */
 330  function wp_default_packages_inline_scripts( $scripts ) {
 331      global $wp_locale;
 332  
 333      if ( isset( $scripts->registered['wp-api-fetch'] ) ) {
 334          $scripts->registered['wp-api-fetch']->deps[] = 'wp-hooks';
 335      }
 336      $scripts->add_inline_script(
 337          'wp-api-fetch',
 338          sprintf(
 339              'wp.apiFetch.use( wp.apiFetch.createRootURLMiddleware( "%s" ) );',
 340              esc_url_raw( get_rest_url() )
 341          ),
 342          'after'
 343      );
 344      $scripts->add_inline_script(
 345          'wp-api-fetch',
 346          implode(
 347              "\n",
 348              array(
 349                  sprintf(
 350                      'wp.apiFetch.nonceMiddleware = wp.apiFetch.createNonceMiddleware( "%s" );',
 351                      wp_installing() ? '' : wp_create_nonce( 'wp_rest' )
 352                  ),
 353                  'wp.apiFetch.use( wp.apiFetch.nonceMiddleware );',
 354                  'wp.apiFetch.use( wp.apiFetch.mediaUploadMiddleware );',
 355                  sprintf(
 356                      'wp.apiFetch.nonceEndpoint = "%s";',
 357                      admin_url( 'admin-ajax.php?action=rest-nonce' )
 358                  ),
 359              )
 360          ),
 361          'after'
 362      );
 363      $scripts->add_inline_script(
 364          'wp-data',
 365          implode(
 366              "\n",
 367              array(
 368                  '( function() {',
 369                  '    var userId = ' . get_current_user_ID() . ';',
 370                  '    var storageKey = "WP_DATA_USER_" + userId;',
 371                  '    wp.data',
 372                  '        .use( wp.data.plugins.persistence, { storageKey: storageKey } );',
 373                  '    wp.data.plugins.persistence.__unstableMigrate( { storageKey: storageKey } );',
 374                  '} )();',
 375              )
 376          )
 377      );
 378  
 379      // Calculate the timezone abbr (EDT, PST) if possible.
 380      $timezone_string = get_option( 'timezone_string', 'UTC' );
 381      $timezone_abbr   = '';
 382  
 383      if ( ! empty( $timezone_string ) ) {
 384          $timezone_date = new DateTime( 'now', new DateTimeZone( $timezone_string ) );
 385          $timezone_abbr = $timezone_date->format( 'T' );
 386      }
 387  
 388      $scripts->add_inline_script(
 389          'wp-date',
 390          sprintf(
 391              'wp.date.setSettings( %s );',
 392              wp_json_encode(
 393                  array(
 394                      'l10n'     => array(
 395                          'locale'        => get_user_locale(),
 396                          'months'        => array_values( $wp_locale->month ),
 397                          'monthsShort'   => array_values( $wp_locale->month_abbrev ),
 398                          'weekdays'      => array_values( $wp_locale->weekday ),
 399                          'weekdaysShort' => array_values( $wp_locale->weekday_abbrev ),
 400                          'meridiem'      => (object) $wp_locale->meridiem,
 401                          'relative'      => array(
 402                              /* translators: %s: Duration. */
 403                              'future' => __( '%s from now' ),
 404                              /* translators: %s: Duration. */
 405                              'past'   => __( '%s ago' ),
 406                          ),
 407                      ),
 408                      'formats'  => array(
 409                          /* translators: Time format, see https://www.php.net/manual/datetime.format.php */
 410                          'time'                => get_option( 'time_format', __( 'g:i a' ) ),
 411                          /* translators: Date format, see https://www.php.net/manual/datetime.format.php */
 412                          'date'                => get_option( 'date_format', __( 'F j, Y' ) ),
 413                          /* translators: Date/Time format, see https://www.php.net/manual/datetime.format.php */
 414                          'datetime'            => __( 'F j, Y g:i a' ),
 415                          /* translators: Abbreviated date/time format, see https://www.php.net/manual/datetime.format.php */
 416                          'datetimeAbbreviated' => __( 'M j, Y g:i a' ),
 417                      ),
 418                      'timezone' => array(
 419                          'offset' => get_option( 'gmt_offset', 0 ),
 420                          'string' => $timezone_string,
 421                          'abbr'   => $timezone_abbr,
 422                      ),
 423                  )
 424              )
 425          ),
 426          'after'
 427      );
 428  
 429      // Loading the old editor and its config to ensure the classic block works as expected.
 430      $scripts->add_inline_script(
 431          'editor',
 432          'window.wp.oldEditor = window.wp.editor;',
 433          'after'
 434      );
 435  
 436      /*
 437       * wp-editor module is exposed as window.wp.editor.
 438       * Problem: there is quite some code expecting window.wp.oldEditor object available under window.wp.editor.
 439       * Solution: fuse the two objects together to maintain backward compatibility.
 440       * For more context, see https://github.com/WordPress/gutenberg/issues/33203.
 441       */
 442      $scripts->add_inline_script(
 443          'wp-editor',
 444          'Object.assign( window.wp.editor, window.wp.oldEditor );',
 445          'after'
 446      );
 447  }
 448  
 449  /**
 450   * Adds inline scripts required for the TinyMCE in the block editor.
 451   *
 452   * These TinyMCE init settings are used to extend and override the default settings
 453   * from `_WP_Editors::default_settings()` for the Classic block.
 454   *
 455   * @since 5.0.0
 456   *
 457   * @global WP_Scripts $wp_scripts
 458   */
 459  function wp_tinymce_inline_scripts() {
 460      global $wp_scripts;
 461  
 462      /** This filter is documented in wp-includes/class-wp-editor.php */
 463      $editor_settings = apply_filters( 'wp_editor_settings', array( 'tinymce' => true ), 'classic-block' );
 464  
 465      $tinymce_plugins = array(
 466          'charmap',
 467          'colorpicker',
 468          'hr',
 469          'lists',
 470          'media',
 471          'paste',
 472          'tabfocus',
 473          'textcolor',
 474          'fullscreen',
 475          'wordpress',
 476          'wpautoresize',
 477          'wpeditimage',
 478          'wpemoji',
 479          'wpgallery',
 480          'wplink',
 481          'wpdialogs',
 482          'wptextpattern',
 483          'wpview',
 484      );
 485  
 486      /** This filter is documented in wp-includes/class-wp-editor.php */
 487      $tinymce_plugins = apply_filters( 'tiny_mce_plugins', $tinymce_plugins, 'classic-block' );
 488      $tinymce_plugins = array_unique( $tinymce_plugins );
 489  
 490      $disable_captions = false;
 491      // Runs after `tiny_mce_plugins` but before `mce_buttons`.
 492      /** This filter is documented in wp-admin/includes/media.php */
 493      if ( apply_filters( 'disable_captions', '' ) ) {
 494          $disable_captions = true;
 495      }
 496  
 497      $toolbar1 = array(
 498          'formatselect',
 499          'bold',
 500          'italic',
 501          'bullist',
 502          'numlist',
 503          'blockquote',
 504          'alignleft',
 505          'aligncenter',
 506          'alignright',
 507          'link',
 508          'unlink',
 509          'wp_more',
 510          'spellchecker',
 511          'wp_add_media',
 512          'wp_adv',
 513      );
 514  
 515      /** This filter is documented in wp-includes/class-wp-editor.php */
 516      $toolbar1 = apply_filters( 'mce_buttons', $toolbar1, 'classic-block' );
 517  
 518      $toolbar2 = array(
 519          'strikethrough',
 520          'hr',
 521          'forecolor',
 522          'pastetext',
 523          'removeformat',
 524          'charmap',
 525          'outdent',
 526          'indent',
 527          'undo',
 528          'redo',
 529          'wp_help',
 530      );
 531  
 532      /** This filter is documented in wp-includes/class-wp-editor.php */
 533      $toolbar2 = apply_filters( 'mce_buttons_2', $toolbar2, 'classic-block' );
 534      /** This filter is documented in wp-includes/class-wp-editor.php */
 535      $toolbar3 = apply_filters( 'mce_buttons_3', array(), 'classic-block' );
 536      /** This filter is documented in wp-includes/class-wp-editor.php */
 537      $toolbar4 = apply_filters( 'mce_buttons_4', array(), 'classic-block' );
 538      /** This filter is documented in wp-includes/class-wp-editor.php */
 539      $external_plugins = apply_filters( 'mce_external_plugins', array(), 'classic-block' );
 540  
 541      $tinymce_settings = array(
 542          'plugins'              => implode( ',', $tinymce_plugins ),
 543          'toolbar1'             => implode( ',', $toolbar1 ),
 544          'toolbar2'             => implode( ',', $toolbar2 ),
 545          'toolbar3'             => implode( ',', $toolbar3 ),
 546          'toolbar4'             => implode( ',', $toolbar4 ),
 547          'external_plugins'     => wp_json_encode( $external_plugins ),
 548          'classic_block_editor' => true,
 549      );
 550  
 551      if ( $disable_captions ) {
 552          $tinymce_settings['wpeditimage_disable_captions'] = true;
 553      }
 554  
 555      if ( ! empty( $editor_settings['tinymce'] ) && is_array( $editor_settings['tinymce'] ) ) {
 556          array_merge( $tinymce_settings, $editor_settings['tinymce'] );
 557      }
 558  
 559      /** This filter is documented in wp-includes/class-wp-editor.php */
 560      $tinymce_settings = apply_filters( 'tiny_mce_before_init', $tinymce_settings, 'classic-block' );
 561  
 562      // Do "by hand" translation from PHP array to js object.
 563      // Prevents breakage in some custom settings.
 564      $init_obj = '';
 565      foreach ( $tinymce_settings as $key => $value ) {
 566          if ( is_bool( $value ) ) {
 567              $val       = $value ? 'true' : 'false';
 568              $init_obj .= $key . ':' . $val . ',';
 569              continue;
 570          } elseif ( ! empty( $value ) && is_string( $value ) && (
 571              ( '{' === $value[0] && '}' === $value[ strlen( $value ) - 1 ] ) ||
 572              ( '[' === $value[0] && ']' === $value[ strlen( $value ) - 1 ] ) ||
 573              preg_match( '/^\(?function ?\(/', $value ) ) ) {
 574              $init_obj .= $key . ':' . $value . ',';
 575              continue;
 576          }
 577          $init_obj .= $key . ':"' . $value . '",';
 578      }
 579  
 580      $init_obj = '{' . trim( $init_obj, ' ,' ) . '}';
 581  
 582      $script = 'window.wpEditorL10n = {
 583          tinymce: {
 584              baseURL: ' . wp_json_encode( includes_url( 'js/tinymce' ) ) . ',
 585              suffix: ' . ( SCRIPT_DEBUG ? '""' : '".min"' ) . ',
 586              settings: ' . $init_obj . ',
 587          }
 588      }';
 589  
 590      $wp_scripts->add_inline_script( 'wp-block-library', $script, 'before' );
 591  }
 592  
 593  /**
 594   * Registers all the WordPress packages scripts.
 595   *
 596   * @since 5.0.0
 597   *
 598   * @param WP_Scripts $scripts WP_Scripts object.
 599   */
 600  function wp_default_packages( $scripts ) {
 601      wp_default_packages_vendor( $scripts );
 602      wp_register_development_scripts( $scripts );
 603      wp_register_tinymce_scripts( $scripts );
 604      wp_default_packages_scripts( $scripts );
 605  
 606      if ( did_action( 'init' ) ) {
 607          wp_default_packages_inline_scripts( $scripts );
 608      }
 609  }
 610  
 611  /**
 612   * Returns the suffix that can be used for the scripts.
 613   *
 614   * There are two suffix types, the normal one and the dev suffix.
 615   *
 616   * @since 5.0.0
 617   *
 618   * @param string $type The type of suffix to retrieve.
 619   * @return string The script suffix.
 620   */
 621  function wp_scripts_get_suffix( $type = '' ) {
 622      static $suffixes;
 623  
 624      if ( null === $suffixes ) {
 625          // Include an unmodified $wp_version.
 626          require  ABSPATH . WPINC . '/version.php';
 627  
 628          $develop_src = false !== strpos( $wp_version, '-src' );
 629  
 630          if ( ! defined( 'SCRIPT_DEBUG' ) ) {
 631              define( 'SCRIPT_DEBUG', $develop_src );
 632          }
 633          $suffix     = SCRIPT_DEBUG ? '' : '.min';
 634          $dev_suffix = $develop_src ? '' : '.min';
 635  
 636          $suffixes = array(
 637              'suffix'     => $suffix,
 638              'dev_suffix' => $dev_suffix,
 639          );
 640      }
 641  
 642      if ( 'dev' === $type ) {
 643          return $suffixes['dev_suffix'];
 644      }
 645  
 646      return $suffixes['suffix'];
 647  }
 648  
 649  /**
 650   * Registers all WordPress scripts.
 651   *
 652   * Localizes some of them.
 653   * args order: `$scripts->add( 'handle', 'url', 'dependencies', 'query-string', 1 );`
 654   * when last arg === 1 queues the script for the footer
 655   *
 656   * @since 2.6.0
 657   *
 658   * @param WP_Scripts $scripts WP_Scripts object.
 659   */
 660  function wp_default_scripts( $scripts ) {
 661      $suffix     = wp_scripts_get_suffix();
 662      $dev_suffix = wp_scripts_get_suffix( 'dev' );
 663      $guessurl   = site_url();
 664  
 665      if ( ! $guessurl ) {
 666          $guessed_url = true;
 667          $guessurl    = wp_guess_url();
 668      }
 669  
 670      $scripts->base_url        = $guessurl;
 671      $scripts->content_url     = defined( 'WP_CONTENT_URL' ) ? WP_CONTENT_URL : '';
 672      $scripts->default_version = get_bloginfo( 'version' );
 673      $scripts->default_dirs    = array( '/wp-admin/js/', '/wp-includes/js/' );
 674  
 675      $scripts->add( 'utils', "/wp-includes/js/utils$suffix.js" );
 676      did_action( 'init' ) && $scripts->localize(
 677          'utils',
 678          'userSettings',
 679          array(
 680              'url'    => (string) SITECOOKIEPATH,
 681              'uid'    => (string) get_current_user_id(),
 682              'time'   => (string) time(),
 683              'secure' => (string) ( 'https' === parse_url( site_url(), PHP_URL_SCHEME ) ),
 684          )
 685      );
 686  
 687      $scripts->add( 'common', "/wp-admin/js/common$suffix.js", array( 'jquery', 'hoverIntent', 'utils' ), false, 1 );
 688      $scripts->set_translations( 'common' );
 689  
 690      $scripts->add( 'wp-sanitize', "/wp-includes/js/wp-sanitize$suffix.js", array(), false, 1 );
 691  
 692      $scripts->add( 'sack', "/wp-includes/js/tw-sack$suffix.js", array(), '1.6.1', 1 );
 693  
 694      $scripts->add( 'quicktags', "/wp-includes/js/quicktags$suffix.js", array(), false, 1 );
 695      did_action( 'init' ) && $scripts->localize(
 696          'quicktags',
 697          'quicktagsL10n',
 698          array(
 699              'closeAllOpenTags'      => __( 'Close all open tags' ),
 700              'closeTags'             => __( 'close tags' ),
 701              'enterURL'              => __( 'Enter the URL' ),
 702              'enterImageURL'         => __( 'Enter the URL of the image' ),
 703              'enterImageDescription' => __( 'Enter a description of the image' ),
 704              'textdirection'         => __( 'text direction' ),
 705              'toggleTextdirection'   => __( 'Toggle Editor Text Direction' ),
 706              'dfw'                   => __( 'Distraction-free writing mode' ),
 707              'strong'                => __( 'Bold' ),
 708              'strongClose'           => __( 'Close bold tag' ),
 709              'em'                    => __( 'Italic' ),
 710              'emClose'               => __( 'Close italic tag' ),
 711              'link'                  => __( 'Insert link' ),
 712              'blockquote'            => __( 'Blockquote' ),
 713              'blockquoteClose'       => __( 'Close blockquote tag' ),
 714              'del'                   => __( 'Deleted text (strikethrough)' ),
 715              'delClose'              => __( 'Close deleted text tag' ),
 716              'ins'                   => __( 'Inserted text' ),
 717              'insClose'              => __( 'Close inserted text tag' ),
 718              'image'                 => __( 'Insert image' ),
 719              'ul'                    => __( 'Bulleted list' ),
 720              'ulClose'               => __( 'Close bulleted list tag' ),
 721              'ol'                    => __( 'Numbered list' ),
 722              'olClose'               => __( 'Close numbered list tag' ),
 723              'li'                    => __( 'List item' ),
 724              'liClose'               => __( 'Close list item tag' ),
 725              'code'                  => __( 'Code' ),
 726              'codeClose'             => __( 'Close code tag' ),
 727              'more'                  => __( 'Insert Read More tag' ),
 728          )
 729      );
 730  
 731      $scripts->add( 'colorpicker', "/wp-includes/js/colorpicker$suffix.js", array( 'prototype' ), '3517m' );
 732  
 733      $scripts->add( 'editor', "/wp-admin/js/editor$suffix.js", array( 'utils', 'jquery' ), false, 1 );
 734  
 735      $scripts->add( 'clipboard', "/wp-includes/js/clipboard$suffix.js", array(), '2.0.10', 1 );
 736  
 737      $scripts->add( 'wp-ajax-response', "/wp-includes/js/wp-ajax-response$suffix.js", array( 'jquery', 'wp-a11y' ), false, 1 );
 738      did_action( 'init' ) && $scripts->localize(
 739          'wp-ajax-response',
 740          'wpAjax',
 741          array(
 742              'noPerm' => __( 'Sorry, you are not allowed to do that.' ),
 743              'broken' => __( 'Something went wrong.' ),
 744          )
 745      );
 746  
 747      $scripts->add( 'wp-api-request', "/wp-includes/js/api-request$suffix.js", array( 'jquery' ), false, 1 );
 748      // `wpApiSettings` is also used by `wp-api`, which depends on this script.
 749      did_action( 'init' ) && $scripts->localize(
 750          'wp-api-request',
 751          'wpApiSettings',
 752          array(
 753              'root'          => esc_url_raw( get_rest_url() ),
 754              'nonce'         => wp_installing() ? '' : wp_create_nonce( 'wp_rest' ),
 755              'versionString' => 'wp/v2/',
 756          )
 757      );
 758  
 759      $scripts->add( 'wp-pointer', "/wp-includes/js/wp-pointer$suffix.js", array( 'jquery-ui-core' ), false, 1 );
 760      $scripts->set_translations( 'wp-pointer' );
 761  
 762      $scripts->add( 'autosave', "/wp-includes/js/autosave$suffix.js", array( 'heartbeat' ), false, 1 );
 763  
 764      $scripts->add( 'heartbeat', "/wp-includes/js/heartbeat$suffix.js", array( 'jquery', 'wp-hooks' ), false, 1 );
 765      did_action( 'init' ) && $scripts->localize(
 766          'heartbeat',
 767          'heartbeatSettings',
 768          /**
 769           * Filters the Heartbeat settings.
 770           *
 771           * @since 3.6.0
 772           *
 773           * @param array $settings Heartbeat settings array.
 774           */
 775          apply_filters( 'heartbeat_settings', array() )
 776      );
 777  
 778      $scripts->add( 'wp-auth-check', "/wp-includes/js/wp-auth-check$suffix.js", array( 'heartbeat' ), false, 1 );
 779      $scripts->set_translations( 'wp-auth-check' );
 780  
 781      $scripts->add( 'wp-lists', "/wp-includes/js/wp-lists$suffix.js", array( 'wp-ajax-response', 'jquery-color' ), false, 1 );
 782  
 783      // WordPress no longer uses or bundles Prototype or script.aculo.us. These are now pulled from an external source.
 784      $scripts->add( 'prototype', 'https://ajax.googleapis.com/ajax/libs/prototype/1.7.1.0/prototype.js', array(), '1.7.1' );
 785      $scripts->add( 'scriptaculous-root', 'https://ajax.googleapis.com/ajax/libs/scriptaculous/1.9.0/scriptaculous.js', array( 'prototype' ), '1.9.0' );
 786      $scripts->add( 'scriptaculous-builder', 'https://ajax.googleapis.com/ajax/libs/scriptaculous/1.9.0/builder.js', array( 'scriptaculous-root' ), '1.9.0' );
 787      $scripts->add( 'scriptaculous-dragdrop', 'https://ajax.googleapis.com/ajax/libs/scriptaculous/1.9.0/dragdrop.js', array( 'scriptaculous-builder', 'scriptaculous-effects' ), '1.9.0' );
 788      $scripts->add( 'scriptaculous-effects', 'https://ajax.googleapis.com/ajax/libs/scriptaculous/1.9.0/effects.js', array( 'scriptaculous-root' ), '1.9.0' );
 789      $scripts->add( 'scriptaculous-slider', 'https://ajax.googleapis.com/ajax/libs/scriptaculous/1.9.0/slider.js', array( 'scriptaculous-effects' ), '1.9.0' );
 790      $scripts->add( 'scriptaculous-sound', 'https://ajax.googleapis.com/ajax/libs/scriptaculous/1.9.0/sound.js', array( 'scriptaculous-root' ), '1.9.0' );
 791      $scripts->add( 'scriptaculous-controls', 'https://ajax.googleapis.com/ajax/libs/scriptaculous/1.9.0/controls.js', array( 'scriptaculous-root' ), '1.9.0' );
 792      $scripts->add( 'scriptaculous', false, array( 'scriptaculous-dragdrop', 'scriptaculous-slider', 'scriptaculous-controls' ) );
 793  
 794      // Not used in core, replaced by Jcrop.js.
 795      $scripts->add( 'cropper', '/wp-includes/js/crop/cropper.js', array( 'scriptaculous-dragdrop' ) );
 796  
 797      // jQuery.
 798      // The unminified jquery.js and jquery-migrate.js are included to facilitate debugging.
 799      $scripts->add( 'jquery', false, array( 'jquery-core', 'jquery-migrate' ), '3.6.0' );
 800      $scripts->add( 'jquery-core', "/wp-includes/js/jquery/jquery$suffix.js", array(), '3.6.0' );
 801      $scripts->add( 'jquery-migrate', "/wp-includes/js/jquery/jquery-migrate$suffix.js", array(), '3.3.2' );
 802  
 803      // Full jQuery UI.
 804      // The build process in 1.12.1 has changed significantly.
 805      // In order to keep backwards compatibility, and to keep the optimized loading,
 806      // the source files were flattened and included with some modifications for AMD loading.
 807      // A notable change is that 'jquery-ui-core' now contains 'jquery-ui-position' and 'jquery-ui-widget'.
 808      $scripts->add( 'jquery-ui-core', "/wp-includes/js/jquery/ui/core$suffix.js", array( 'jquery' ), '1.13.1', 1 );
 809      $scripts->add( 'jquery-effects-core', "/wp-includes/js/jquery/ui/effect$suffix.js", array( 'jquery' ), '1.13.1', 1 );
 810  
 811      $scripts->add( 'jquery-effects-blind', "/wp-includes/js/jquery/ui/effect-blind$suffix.js", array( 'jquery-effects-core' ), '1.13.1', 1 );
 812      $scripts->add( 'jquery-effects-bounce', "/wp-includes/js/jquery/ui/effect-bounce$suffix.js", array( 'jquery-effects-core' ), '1.13.1', 1 );
 813      $scripts->add( 'jquery-effects-clip', "/wp-includes/js/jquery/ui/effect-clip$suffix.js", array( 'jquery-effects-core' ), '1.13.1', 1 );
 814      $scripts->add( 'jquery-effects-drop', "/wp-includes/js/jquery/ui/effect-drop$suffix.js", array( 'jquery-effects-core' ), '1.13.1', 1 );
 815      $scripts->add( 'jquery-effects-explode', "/wp-includes/js/jquery/ui/effect-explode$suffix.js", array( 'jquery-effects-core' ), '1.13.1', 1 );
 816      $scripts->add( 'jquery-effects-fade', "/wp-includes/js/jquery/ui/effect-fade$suffix.js", array( 'jquery-effects-core' ), '1.13.1', 1 );
 817      $scripts->add( 'jquery-effects-fold', "/wp-includes/js/jquery/ui/effect-fold$suffix.js", array( 'jquery-effects-core' ), '1.13.1', 1 );
 818      $scripts->add( 'jquery-effects-highlight', "/wp-includes/js/jquery/ui/effect-highlight$suffix.js", array( 'jquery-effects-core' ), '1.13.1', 1 );
 819      $scripts->add( 'jquery-effects-puff', "/wp-includes/js/jquery/ui/effect-puff$suffix.js", array( 'jquery-effects-core', 'jquery-effects-scale' ), '1.13.1', 1 );
 820      $scripts->add( 'jquery-effects-pulsate', "/wp-includes/js/jquery/ui/effect-pulsate$suffix.js", array( 'jquery-effects-core' ), '1.13.1', 1 );
 821      $scripts->add( 'jquery-effects-scale', "/wp-includes/js/jquery/ui/effect-scale$suffix.js", array( 'jquery-effects-core', 'jquery-effects-size' ), '1.13.1', 1 );
 822      $scripts->add( 'jquery-effects-shake', "/wp-includes/js/jquery/ui/effect-shake$suffix.js", array( 'jquery-effects-core' ), '1.13.1', 1 );
 823      $scripts->add( 'jquery-effects-size', "/wp-includes/js/jquery/ui/effect-size$suffix.js", array( 'jquery-effects-core' ), '1.13.1', 1 );
 824      $scripts->add( 'jquery-effects-slide', "/wp-includes/js/jquery/ui/effect-slide$suffix.js", array( 'jquery-effects-core' ), '1.13.1', 1 );
 825      $scripts->add( 'jquery-effects-transfer', "/wp-includes/js/jquery/ui/effect-transfer$suffix.js", array( 'jquery-effects-core' ), '1.13.1', 1 );
 826  
 827      // Widgets
 828      $scripts->add( 'jquery-ui-accordion', "/wp-includes/js/jquery/ui/accordion$suffix.js", array( 'jquery-ui-core' ), '1.13.1', 1 );
 829      $scripts->add( 'jquery-ui-autocomplete', "/wp-includes/js/jquery/ui/autocomplete$suffix.js", array( 'jquery-ui-menu', 'wp-a11y' ), '1.13.1', 1 );
 830      $scripts->add( 'jquery-ui-button', "/wp-includes/js/jquery/ui/button$suffix.js", array( 'jquery-ui-core', 'jquery-ui-controlgroup', 'jquery-ui-checkboxradio' ), '1.13.1', 1 );
 831      $scripts->add( 'jquery-ui-datepicker', "/wp-includes/js/jquery/ui/datepicker$suffix.js", array( 'jquery-ui-core' ), '1.13.1', 1 );
 832      $scripts->add( 'jquery-ui-dialog', "/wp-includes/js/jquery/ui/dialog$suffix.js", array( 'jquery-ui-resizable', 'jquery-ui-draggable', 'jquery-ui-button' ), '1.13.1', 1 );
 833      $scripts->add( 'jquery-ui-menu', "/wp-includes/js/jquery/ui/menu$suffix.js", array( 'jquery-ui-core' ), '1.13.1', 1 );
 834      $scripts->add( 'jquery-ui-mouse', "/wp-includes/js/jquery/ui/mouse$suffix.js", array( 'jquery-ui-core' ), '1.13.1', 1 );
 835      $scripts->add( 'jquery-ui-progressbar', "/wp-includes/js/jquery/ui/progressbar$suffix.js", array( 'jquery-ui-core' ), '1.13.1', 1 );
 836      $scripts->add( 'jquery-ui-selectmenu', "/wp-includes/js/jquery/ui/selectmenu$suffix.js", array( 'jquery-ui-menu' ), '1.13.1', 1 );
 837      $scripts->add( 'jquery-ui-slider', "/wp-includes/js/jquery/ui/slider$suffix.js", array( 'jquery-ui-mouse' ), '1.13.1', 1 );
 838      $scripts->add( 'jquery-ui-spinner', "/wp-includes/js/jquery/ui/spinner$suffix.js", array( 'jquery-ui-button' ), '1.13.1', 1 );
 839      $scripts->add( 'jquery-ui-tabs', "/wp-includes/js/jquery/ui/tabs$suffix.js", array( 'jquery-ui-core' ), '1.13.1', 1 );
 840      $scripts->add( 'jquery-ui-tooltip', "/wp-includes/js/jquery/ui/tooltip$suffix.js", array( 'jquery-ui-core' ), '1.13.1', 1 );
 841  
 842      // New in 1.12.1
 843      $scripts->add( 'jquery-ui-checkboxradio', "/wp-includes/js/jquery/ui/checkboxradio$suffix.js", array( 'jquery-ui-core' ), '1.13.1', 1 );
 844      $scripts->add( 'jquery-ui-controlgroup', "/wp-includes/js/jquery/ui/controlgroup$suffix.js", array( 'jquery-ui-core' ), '1.13.1', 1 );
 845  
 846      // Interactions
 847      $scripts->add( 'jquery-ui-draggable', "/wp-includes/js/jquery/ui/draggable$suffix.js", array( 'jquery-ui-mouse' ), '1.13.1', 1 );
 848      $scripts->add( 'jquery-ui-droppable', "/wp-includes/js/jquery/ui/droppable$suffix.js", array( 'jquery-ui-draggable' ), '1.13.1', 1 );
 849      $scripts->add( 'jquery-ui-resizable', "/wp-includes/js/jquery/ui/resizable$suffix.js", array( 'jquery-ui-mouse' ), '1.13.1', 1 );
 850      $scripts->add( 'jquery-ui-selectable', "/wp-includes/js/jquery/ui/selectable$suffix.js", array( 'jquery-ui-mouse' ), '1.13.1', 1 );
 851      $scripts->add( 'jquery-ui-sortable', "/wp-includes/js/jquery/ui/sortable$suffix.js", array( 'jquery-ui-mouse' ), '1.13.1', 1 );
 852  
 853      // As of 1.12.1 `jquery-ui-position` and `jquery-ui-widget` are part of `jquery-ui-core`.
 854      // Listed here for back-compat.
 855      $scripts->add( 'jquery-ui-position', false, array( 'jquery-ui-core' ), '1.13.1', 1 );
 856      $scripts->add( 'jquery-ui-widget', false, array( 'jquery-ui-core' ), '1.13.1', 1 );
 857  
 858      // Strings for 'jquery-ui-autocomplete' live region messages.
 859      did_action( 'init' ) && $scripts->localize(
 860          'jquery-ui-autocomplete',
 861          'uiAutocompleteL10n',
 862          array(
 863              'noResults'    => __( 'No results found.' ),
 864              /* translators: Number of results found when using jQuery UI Autocomplete. */
 865              'oneResult'    => __( '1 result found. Use up and down arrow keys to navigate.' ),
 866              /* translators: %d: Number of results found when using jQuery UI Autocomplete. */
 867              'manyResults'  => __( '%d results found. Use up and down arrow keys to navigate.' ),
 868              'itemSelected' => __( 'Item selected.' ),
 869          )
 870      );
 871  
 872      // Deprecated, not used in core, most functionality is included in jQuery 1.3.
 873      $scripts->add( 'jquery-form', "/wp-includes/js/jquery/jquery.form$suffix.js", array( 'jquery' ), '4.3.0', 1 );
 874  
 875      // jQuery plugins.
 876      $scripts->add( 'jquery-color', '/wp-includes/js/jquery/jquery.color.min.js', array( 'jquery' ), '2.2.0', 1 );
 877      $scripts->add( 'schedule', '/wp-includes/js/jquery/jquery.schedule.js', array( 'jquery' ), '20m', 1 );
 878      $scripts->add( 'jquery-query', '/wp-includes/js/jquery/jquery.query.js', array( 'jquery' ), '2.2.3', 1 );
 879      $scripts->add( 'jquery-serialize-object', '/wp-includes/js/jquery/jquery.serialize-object.js', array( 'jquery' ), '0.2-wp', 1 );
 880      $scripts->add( 'jquery-hotkeys', "/wp-includes/js/jquery/jquery.hotkeys$suffix.js", array( 'jquery' ), '0.0.2m', 1 );
 881      $scripts->add( 'jquery-table-hotkeys', "/wp-includes/js/jquery/jquery.table-hotkeys$suffix.js", array( 'jquery', 'jquery-hotkeys' ), false, 1 );
 882      $scripts->add( 'jquery-touch-punch', '/wp-includes/js/jquery/jquery.ui.touch-punch.js', array( 'jquery-ui-core', 'jquery-ui-mouse' ), '0.2.2', 1 );
 883  
 884      // Not used any more, registered for backward compatibility.
 885      $scripts->add( 'suggest', "/wp-includes/js/jquery/suggest$suffix.js", array( 'jquery' ), '1.1-20110113', 1 );
 886  
 887      // Masonry v2 depended on jQuery. v3 does not. The older jquery-masonry handle is a shiv.
 888      // It sets jQuery as a dependency, as the theme may have been implicitly loading it this way.
 889      $scripts->add( 'imagesloaded', '/wp-includes/js/imagesloaded.min.js', array(), '4.1.4', 1 );
 890      $scripts->add( 'masonry', '/wp-includes/js/masonry.min.js', array( 'imagesloaded' ), '4.2.2', 1 );
 891      $scripts->add( 'jquery-masonry', '/wp-includes/js/jquery/jquery.masonry.min.js', array( 'jquery', 'masonry' ), '3.1.2b', 1 );
 892  
 893      $scripts->add( 'thickbox', '/wp-includes/js/thickbox/thickbox.js', array( 'jquery' ), '3.1-20121105', 1 );
 894      did_action( 'init' ) && $scripts->localize(
 895          'thickbox',
 896          'thickboxL10n',
 897          array(
 898              'next'             => __( 'Next &gt;' ),
 899              'prev'             => __( '&lt; Prev' ),
 900              'image'            => __( 'Image' ),
 901              'of'               => __( 'of' ),
 902              'close'            => __( 'Close' ),
 903              'noiframes'        => __( 'This feature requires inline frames. You have iframes disabled or your browser does not support them.' ),
 904              'loadingAnimation' => includes_url( 'js/thickbox/loadingAnimation.gif' ),
 905          )
 906      );
 907  
 908      // Not used in core, replaced by imgAreaSelect.
 909      $scripts->add( 'jcrop', '/wp-includes/js/jcrop/jquery.Jcrop.min.js', array( 'jquery' ), '0.9.15' );
 910  
 911      $scripts->add( 'swfobject', '/wp-includes/js/swfobject.js', array(), '2.2-20120417' );
 912  
 913      // Error messages for Plupload.
 914      $uploader_l10n = array(
 915          'queue_limit_exceeded'      => __( 'You have attempted to queue too many files.' ),
 916          /* translators: %s: File name. */
 917          'file_exceeds_size_limit'   => __( '%s exceeds the maximum upload size for this site.' ),
 918          'zero_byte_file'            => __( 'This file is empty. Please try another.' ),
 919          'invalid_filetype'          => __( 'Sorry, you are not allowed to upload this file type.' ),
 920          'not_an_image'              => __( 'This file is not an image. Please try another.' ),
 921          'image_memory_exceeded'     => __( 'Memory exceeded. Please try another smaller file.' ),
 922          'image_dimensions_exceeded' => __( 'This is larger than the maximum size. Please try another.' ),
 923          'default_error'             => __( 'An error occurred in the upload. Please try again later.' ),
 924          'missing_upload_url'        => __( 'There was a configuration error. Please contact the server administrator.' ),
 925          'upload_limit_exceeded'     => __( 'You may only upload 1 file.' ),
 926          'http_error'                => __( 'Unexpected response from the server. The file may have been uploaded successfully. Check in the Media Library or reload the page.' ),
 927          'http_error_image'          => __( 'The server cannot process the image. This can happen if the server is busy or does not have enough resources to complete the task. Uploading a smaller image may help. Suggested maximum size is 2560 pixels.' ),
 928          'upload_failed'             => __( 'Upload failed.' ),
 929          /* translators: 1: Opening link tag, 2: Closing link tag. */
 930          'big_upload_failed'         => __( 'Please try uploading this file with the %1$sbrowser uploader%2$s.' ),
 931          /* translators: %s: File name. */
 932          'big_upload_queued'         => __( '%s exceeds the maximum upload size for the multi-file uploader when used in your browser.' ),
 933          'io_error'                  => __( 'IO error.' ),
 934          'security_error'            => __( 'Security error.' ),
 935          'file_cancelled'            => __( 'File canceled.' ),
 936          'upload_stopped'            => __( 'Upload stopped.' ),
 937          'dismiss'                   => __( 'Dismiss' ),
 938          'crunching'                 => __( 'Crunching&hellip;' ),
 939          'deleted'                   => __( 'moved to the Trash.' ),
 940          /* translators: %s: File name. */
 941          'error_uploading'           => __( '&#8220;%s&#8221; has failed to upload.' ),
 942          'unsupported_image'         => __( 'This image cannot be displayed in a web browser. For best results convert it to JPEG before uploading.' ),
 943          'noneditable_image'         => __( 'This image cannot be processed by the web server. Convert it to JPEG or PNG before uploading.' ),
 944          'file_url_copied'           => __( 'The file URL has been copied to your clipboard' ),
 945      );
 946  
 947      $scripts->add( 'moxiejs', "/wp-includes/js/plupload/moxie$suffix.js", array(), '1.3.5' );
 948      $scripts->add( 'plupload', "/wp-includes/js/plupload/plupload$suffix.js", array( 'moxiejs' ), '2.1.9' );
 949      // Back compat handles:
 950      foreach ( array( 'all', 'html5', 'flash', 'silverlight', 'html4' ) as $handle ) {
 951          $scripts->add( "plupload-$handle", false, array( 'plupload' ), '2.1.1' );
 952      }
 953  
 954      $scripts->add( 'plupload-handlers', "/wp-includes/js/plupload/handlers$suffix.js", array( 'clipboard', 'jquery', 'plupload', 'underscore', 'wp-a11y', 'wp-i18n' ) );
 955      did_action( 'init' ) && $scripts->localize( 'plupload-handlers', 'pluploadL10n', $uploader_l10n );
 956  
 957      $scripts->add( 'wp-plupload', "/wp-includes/js/plupload/wp-plupload$suffix.js", array( 'plupload', 'jquery', 'json2', 'media-models' ), false, 1 );
 958      did_action( 'init' ) && $scripts->localize( 'wp-plupload', 'pluploadL10n', $uploader_l10n );
 959  
 960      // Keep 'swfupload' for back-compat.
 961      $scripts->add( 'swfupload', '/wp-includes/js/swfupload/swfupload.js', array(), '2201-20110113' );
 962      $scripts->add( 'swfupload-all', false, array( 'swfupload' ), '2201' );
 963      $scripts->add( 'swfupload-handlers', "/wp-includes/js/swfupload/handlers$suffix.js", array( 'swfupload-all', 'jquery' ), '2201-20110524' );
 964      did_action( 'init' ) && $scripts->localize( 'swfupload-handlers', 'swfuploadL10n', $uploader_l10n );
 965  
 966      $scripts->add( 'comment-reply', "/wp-includes/js/comment-reply$suffix.js", array(), false, 1 );
 967  
 968      $scripts->add( 'json2', "/wp-includes/js/json2$suffix.js", array(), '2015-05-03' );
 969      did_action( 'init' ) && $scripts->add_data( 'json2', 'conditional', 'lt IE 8' );
 970  
 971      $scripts->add( 'underscore', "/wp-includes/js/underscore$dev_suffix.js", array(), '1.13.3', 1 );
 972      $scripts->add( 'backbone', "/wp-includes/js/backbone$dev_suffix.js", array( 'underscore', 'jquery' ), '1.4.1', 1 );
 973  
 974      $scripts->add( 'wp-util', "/wp-includes/js/wp-util$suffix.js", array( 'underscore', 'jquery' ), false, 1 );
 975      did_action( 'init' ) && $scripts->localize(
 976          'wp-util',
 977          '_wpUtilSettings',
 978          array(
 979              'ajax' => array(
 980                  'url' => admin_url( 'admin-ajax.php', 'relative' ),
 981              ),
 982          )
 983      );
 984  
 985      $scripts->add( 'wp-backbone', "/wp-includes/js/wp-backbone$suffix.js", array( 'backbone', 'wp-util' ), false, 1 );
 986  
 987      $scripts->add( 'revisions', "/wp-admin/js/revisions$suffix.js", array( 'wp-backbone', 'jquery-ui-slider', 'hoverIntent' ), false, 1 );
 988  
 989      $scripts->add( 'imgareaselect', "/wp-includes/js/imgareaselect/jquery.imgareaselect$suffix.js", array( 'jquery' ), false, 1 );
 990  
 991      $scripts->add( 'mediaelement', false, array( 'jquery', 'mediaelement-core', 'mediaelement-migrate' ), '4.2.16', 1 );
 992      $scripts->add( 'mediaelement-core', "/wp-includes/js/mediaelement/mediaelement-and-player$suffix.js", array(), '4.2.16', 1 );
 993      $scripts->add( 'mediaelement-migrate', "/wp-includes/js/mediaelement/mediaelement-migrate$suffix.js", array(), false, 1 );
 994  
 995      did_action( 'init' ) && $scripts->add_inline_script(
 996          'mediaelement-core',
 997          sprintf(
 998              'var mejsL10n = %s;',
 999              wp_json_encode(
1000                  array(
1001                      'language' => strtolower( strtok( determine_locale(), '_-' ) ),
1002                      'strings'  => array(
1003                          'mejs.download-file'       => __( 'Download File' ),
1004                          'mejs.install-flash'       => __( 'You are using a browser that does not have Flash player enabled or installed. Please turn on your Flash player plugin or download the latest version from https://get.adobe.com/flashplayer/' ),
1005                          'mejs.fullscreen'          => __( 'Fullscreen' ),
1006                          'mejs.play'                => __( 'Play' ),
1007                          'mejs.pause'               => __( 'Pause' ),
1008                          'mejs.time-slider'         => __( 'Time Slider' ),
1009                          'mejs.time-help-text'      => __( 'Use Left/Right Arrow keys to advance one second, Up/Down arrows to advance ten seconds.' ),
1010                          'mejs.live-broadcast'      => __( 'Live Broadcast' ),
1011                          'mejs.volume-help-text'    => __( 'Use Up/Down Arrow keys to increase or decrease volume.' ),
1012                          'mejs.unmute'              => __( 'Unmute' ),
1013                          'mejs.mute'                => __( 'Mute' ),
1014                          'mejs.volume-slider'       => __( 'Volume Slider' ),
1015                          'mejs.video-player'        => __( 'Video Player' ),
1016                          'mejs.audio-player'        => __( 'Audio Player' ),
1017                          'mejs.captions-subtitles'  => __( 'Captions/Subtitles' ),
1018                          'mejs.captions-chapters'   => __( 'Chapters' ),
1019                          'mejs.none'                => __( 'None' ),
1020                          'mejs.afrikaans'           => __( 'Afrikaans' ),
1021                          'mejs.albanian'            => __( 'Albanian' ),
1022                          'mejs.arabic'              => __( 'Arabic' ),
1023                          'mejs.belarusian'          => __( 'Belarusian' ),
1024                          'mejs.bulgarian'           => __( 'Bulgarian' ),
1025                          'mejs.catalan'             => __( 'Catalan' ),
1026                          'mejs.chinese'             => __( 'Chinese' ),
1027                          'mejs.chinese-simplified'  => __( 'Chinese (Simplified)' ),
1028                          'mejs.chinese-traditional' => __( 'Chinese (Traditional)' ),
1029                          'mejs.croatian'            => __( 'Croatian' ),
1030                          'mejs.czech'               => __( 'Czech' ),
1031                          'mejs.danish'              => __( 'Danish' ),
1032                          'mejs.dutch'               => __( 'Dutch' ),
1033                          'mejs.english'             => __( 'English' ),
1034                          'mejs.estonian'            => __( 'Estonian' ),
1035                          'mejs.filipino'            => __( 'Filipino' ),
1036                          'mejs.finnish'             => __( 'Finnish' ),
1037                          'mejs.french'              => __( 'French' ),
1038                          'mejs.galician'            => __( 'Galician' ),
1039                          'mejs.german'              => __( 'German' ),
1040                          'mejs.greek'               => __( 'Greek' ),
1041                          'mejs.haitian-creole'      => __( 'Haitian Creole' ),
1042                          'mejs.hebrew'              => __( 'Hebrew' ),
1043                          'mejs.hindi'               => __( 'Hindi' ),
1044                          'mejs.hungarian'           => __( 'Hungarian' ),
1045                          'mejs.icelandic'           => __( 'Icelandic' ),
1046                          'mejs.indonesian'          => __( 'Indonesian' ),
1047                          'mejs.irish'               => __( 'Irish' ),
1048                          'mejs.italian'             => __( 'Italian' ),
1049                          'mejs.japanese'            => __( 'Japanese' ),
1050                          'mejs.korean'              => __( 'Korean' ),
1051                          'mejs.latvian'             => __( 'Latvian' ),
1052                          'mejs.lithuanian'          => __( 'Lithuanian' ),
1053                          'mejs.macedonian'          => __( 'Macedonian' ),
1054                          'mejs.malay'               => __( 'Malay' ),
1055                          'mejs.maltese'             => __( 'Maltese' ),
1056                          'mejs.norwegian'           => __( 'Norwegian' ),
1057                          'mejs.persian'             => __( 'Persian' ),
1058                          'mejs.polish'              => __( 'Polish' ),
1059                          'mejs.portuguese'          => __( 'Portuguese' ),
1060                          'mejs.romanian'            => __( 'Romanian' ),
1061                          'mejs.russian'             => __( 'Russian' ),
1062                          'mejs.serbian'             => __( 'Serbian' ),
1063                          'mejs.slovak'              => __( 'Slovak' ),
1064                          'mejs.slovenian'           => __( 'Slovenian' ),
1065                          'mejs.spanish'             => __( 'Spanish' ),
1066                          'mejs.swahili'             => __( 'Swahili' ),
1067                          'mejs.swedish'             => __( 'Swedish' ),
1068                          'mejs.tagalog'             => __( 'Tagalog' ),
1069                          'mejs.thai'                => __( 'Thai' ),
1070                          'mejs.turkish'             => __( 'Turkish' ),
1071                          'mejs.ukrainian'           => __( 'Ukrainian' ),
1072                          'mejs.vietnamese'          => __( 'Vietnamese' ),
1073                          'mejs.welsh'               => __( 'Welsh' ),
1074                          'mejs.yiddish'             => __( 'Yiddish' ),
1075                      ),
1076                  )
1077              )
1078          ),
1079          'before'
1080      );
1081  
1082      $scripts->add( 'mediaelement-vimeo', '/wp-includes/js/mediaelement/renderers/vimeo.min.js', array( 'mediaelement' ), '4.2.16', 1 );
1083      $scripts->add( 'wp-mediaelement', "/wp-includes/js/mediaelement/wp-mediaelement$suffix.js", array( 'mediaelement' ), false, 1 );
1084      $mejs_settings = array(
1085          'pluginPath'  => includes_url( 'js/mediaelement/', 'relative' ),
1086          'classPrefix' => 'mejs-',
1087          'stretching'  => 'responsive',
1088      );
1089      did_action( 'init' ) && $scripts->localize(
1090          'mediaelement',
1091          '_wpmejsSettings',
1092          /**
1093           * Filters the MediaElement configuration settings.
1094           *
1095           * @since 4.4.0
1096           *
1097           * @param array $mejs_settings MediaElement settings array.
1098           */
1099          apply_filters( 'mejs_settings', $mejs_settings )
1100      );
1101  
1102      $scripts->add( 'wp-codemirror', '/wp-includes/js/codemirror/codemirror.min.js', array(), '5.29.1-alpha-ee20357' );
1103      $scripts->add( 'csslint', '/wp-includes/js/codemirror/csslint.js', array(), '1.0.5' );
1104      $scripts->add( 'esprima', '/wp-includes/js/codemirror/esprima.js', array(), '4.0.0' );
1105      $scripts->add( 'jshint', '/wp-includes/js/codemirror/fakejshint.js', array( 'esprima' ), '2.9.5' );
1106      $scripts->add( 'jsonlint', '/wp-includes/js/codemirror/jsonlint.js', array(), '1.6.2' );
1107      $scripts->add( 'htmlhint', '/wp-includes/js/codemirror/htmlhint.js', array(), '0.9.14-xwp' );
1108      $scripts->add( 'htmlhint-kses', '/wp-includes/js/codemirror/htmlhint-kses.js', array( 'htmlhint' ) );
1109      $scripts->add( 'code-editor', "/wp-admin/js/code-editor$suffix.js", array( 'jquery', 'wp-codemirror', 'underscore' ) );
1110      $scripts->add( 'wp-theme-plugin-editor', "/wp-admin/js/theme-plugin-editor$suffix.js", array( 'common', 'wp-util', 'wp-sanitize', 'jquery', 'jquery-ui-core', 'wp-a11y', 'underscore' ) );
1111      $scripts->set_translations( 'wp-theme-plugin-editor' );
1112  
1113      $scripts->add( 'wp-playlist', "/wp-includes/js/mediaelement/wp-playlist$suffix.js", array( 'wp-util', 'backbone', 'mediaelement' ), false, 1 );
1114  
1115      $scripts->add( 'zxcvbn-async', "/wp-includes/js/zxcvbn-async$suffix.js", array(), '1.0' );
1116      did_action( 'init' ) && $scripts->localize(
1117          'zxcvbn-async',
1118          '_zxcvbnSettings',
1119          array(
1120              'src' => empty( $guessed_url ) ? includes_url( '/js/zxcvbn.min.js' ) : $scripts->base_url . '/wp-includes/js/zxcvbn.min.js',
1121          )
1122      );
1123  
1124      $scripts->add( 'password-strength-meter', "/wp-admin/js/password-strength-meter$suffix.js", array( 'jquery', 'zxcvbn-async' ), false, 1 );
1125      did_action( 'init' ) && $scripts->localize(
1126          'password-strength-meter',
1127          'pwsL10n',
1128          array(
1129              'unknown'  => _x( 'Password strength unknown', 'password strength' ),
1130              'short'    => _x( 'Very weak', 'password strength' ),
1131              'bad'      => _x( 'Weak', 'password strength' ),
1132              'good'     => _x( 'Medium', 'password strength' ),
1133              'strong'   => _x( 'Strong', 'password strength' ),
1134              'mismatch' => _x( 'Mismatch', 'password mismatch' ),
1135          )
1136      );
1137      $scripts->set_translations( 'password-strength-meter' );
1138  
1139      $scripts->add( 'application-passwords', "/wp-admin/js/application-passwords$suffix.js", array( 'jquery', 'wp-util', 'wp-api-request', 'wp-date', 'wp-i18n', 'wp-hooks' ), false, 1 );
1140      $scripts->set_translations( 'application-passwords' );
1141  
1142      $scripts->add( 'auth-app', "/wp-admin/js/auth-app$suffix.js", array( 'jquery', 'wp-api-request', 'wp-i18n', 'wp-hooks' ), false, 1 );
1143      $scripts->set_translations( 'auth-app' );
1144  
1145      $scripts->add( 'user-profile', "/wp-admin/js/user-profile$suffix.js", array( 'jquery', 'password-strength-meter', 'wp-util' ), false, 1 );
1146      $scripts->set_translations( 'user-profile' );
1147      $user_id = isset( $_GET['user_id'] ) ? (int) $_GET['user_id'] : 0;
1148      did_action( 'init' ) && $scripts->localize(
1149          'user-profile',
1150          'userProfileL10n',
1151          array(
1152              'user_id' => $user_id,
1153              'nonce'   => wp_installing() ? '' : wp_create_nonce( 'reset-password-for-' . $user_id ),
1154          )
1155      );
1156  
1157      $scripts->add( 'language-chooser', "/wp-admin/js/language-chooser$suffix.js", array( 'jquery' ), false, 1 );
1158  
1159      $scripts->add( 'user-suggest', "/wp-admin/js/user-suggest$suffix.js", array( 'jquery-ui-autocomplete' ), false, 1 );
1160  
1161      $scripts->add( 'admin-bar', "/wp-includes/js/admin-bar$suffix.js", array( 'hoverintent-js' ), false, 1 );
1162  
1163      $scripts->add( 'wplink', "/wp-includes/js/wplink$suffix.js", array( 'jquery', 'wp-a11y' ), false, 1 );
1164      did_action( 'init' ) && $scripts->localize(
1165          'wplink',
1166          'wpLinkL10n',
1167          array(
1168              'title'          => __( 'Insert/edit link' ),
1169              'update'         => __( 'Update' ),
1170              'save'           => __( 'Add Link' ),
1171              'noTitle'        => __( '(no title)' ),
1172              'noMatchesFound' => __( 'No results found.' ),
1173              'linkSelected'   => __( 'Link selected.' ),
1174              'linkInserted'   => __( 'Link inserted.' ),
1175              /* translators: Minimum input length in characters to start searching posts in the "Insert/edit link" modal. */
1176              'minInputLength' => (int) _x( '3', 'minimum input length for searching post links' ),
1177          )
1178      );
1179  
1180      $scripts->add( 'wpdialogs', "/wp-includes/js/wpdialog$suffix.js", array( 'jquery-ui-dialog' ), false, 1 );
1181  
1182      $scripts->add( 'word-count', "/wp-admin/js/word-count$suffix.js", array(), false, 1 );
1183  
1184      $scripts->add( 'media-upload', "/wp-admin/js/media-upload$suffix.js", array( 'thickbox', 'shortcode' ), false, 1 );
1185  
1186      $scripts->add( 'hoverIntent', "/wp-includes/js/hoverIntent$suffix.js", array( 'jquery' ), '1.10.2', 1 );
1187  
1188      // JS-only version of hoverintent (no dependencies).
1189      $scripts->add( 'hoverintent-js', '/wp-includes/js/hoverintent-js.min.js', array(), '2.2.1', 1 );
1190  
1191      $scripts->add( 'customize-base', "/wp-includes/js/customize-base$suffix.js", array( 'jquery', 'json2', 'underscore' ), false, 1 );
1192      $scripts->add( 'customize-loader', "/wp-includes/js/customize-loader$suffix.js", array( 'customize-base' ), false, 1 );
1193      $scripts->add( 'customize-preview', "/wp-includes/js/customize-preview$suffix.js", array( 'wp-a11y', 'customize-base' ), false, 1 );
1194      $scripts->add( 'customize-models', '/wp-includes/js/customize-models.js', array( 'underscore', 'backbone' ), false, 1 );
1195      $scripts->add( 'customize-views', '/wp-includes/js/customize-views.js', array( 'jquery', 'underscore', 'imgareaselect', 'customize-models', 'media-editor', 'media-views' ), false, 1 );
1196      $scripts->add( 'customize-controls', "/wp-admin/js/customize-controls$suffix.js", array( 'customize-base', 'wp-a11y', 'wp-util', 'jquery-ui-core' ), false, 1 );
1197      did_action( 'init' ) && $scripts->localize(
1198          'customize-controls',
1199          '_wpCustomizeControlsL10n',
1200          array(
1201              'activate'                => __( 'Activate &amp; Publish' ),
1202              'save'                    => __( 'Save &amp; Publish' ), // @todo Remove as not required.
1203              'publish'                 => __( 'Publish' ),
1204              'published'               => __( 'Published' ),
1205              'saveDraft'               => __( 'Save Draft' ),
1206              'draftSaved'              => __( 'Draft Saved' ),
1207              'updating'                => __( 'Updating' ),
1208              'schedule'                => _x( 'Schedule', 'customizer changeset action/button label' ),
1209              'scheduled'               => _x( 'Scheduled', 'customizer changeset status' ),
1210              'invalid'                 => __( 'Invalid' ),
1211              'saveBeforeShare'         => __( 'Please save your changes in order to share the preview.' ),
1212              'futureDateError'         => __( 'You must supply a future date to schedule.' ),
1213              'saveAlert'               => __( 'The changes you made will be lost if you navigate away from this page.' ),
1214              'saved'                   => __( 'Saved' ),
1215              'cancel'                  => __( 'Cancel' ),
1216              'close'                   => __( 'Close' ),
1217              'action'                  => __( 'Action' ),
1218              'discardChanges'          => __( 'Discard changes' ),
1219              'cheatin'                 => __( 'Something went wrong.' ),
1220              'notAllowedHeading'       => __( 'You need a higher level of permission.' ),
1221              'notAllowed'              => __( 'Sorry, you are not allowed to customize this site.' ),
1222              'previewIframeTitle'      => __( 'Site Preview' ),
1223              'loginIframeTitle'        => __( 'Session expired' ),
1224              'collapseSidebar'         => _x( 'Hide Controls', 'label for hide controls button without length constraints' ),
1225              'expandSidebar'           => _x( 'Show Controls', 'label for hide controls button without length constraints' ),
1226              'untitledBlogName'        => __( '(Untitled)' ),
1227              'unknownRequestFail'      => __( 'Looks like something&#8217;s gone wrong. Wait a couple seconds, and then try again.' ),
1228              'themeDownloading'        => __( 'Downloading your new theme&hellip;' ),
1229              'themePreviewWait'        => __( 'Setting up your live preview. This may take a bit.' ),
1230              'revertingChanges'        => __( 'Reverting unpublished changes&hellip;' ),
1231              'trashConfirm'            => __( 'Are you sure you want to discard your unpublished changes?' ),
1232              /* translators: %s: Display name of the user who has taken over the changeset in customizer. */
1233              'takenOverMessage'        => __( '%s has taken over and is currently customizing.' ),
1234              /* translators: %s: URL to the Customizer to load the autosaved version. */
1235              'autosaveNotice'          => __( 'There is a more recent autosave of your changes than the one you are previewing. <a href="%s">Restore the autosave</a>' ),
1236              'videoHeaderNotice'       => __( 'This theme does not support video headers on this page. Navigate to the front page or another page that supports video headers.' ),
1237              // Used for overriding the file types allowed in Plupload.
1238              'allowedFiles'            => __( 'Allowed Files' ),
1239              'customCssError'          => array(
1240                  /* translators: %d: Error count. */
1241                  'singular' => _n( 'There is %d error which must be fixed before you can save.', 'There are %d errors which must be fixed before you can save.', 1 ),
1242                  /* translators: %d: Error count. */
1243                  'plural'   => _n( 'There is %d error which must be fixed before you can save.', 'There are %d errors which must be fixed before you can save.', 2 ),
1244                  // @todo This is lacking, as some languages have a dedicated dual form. For proper handling of plurals in JS, see #20491.
1245              ),
1246              'pageOnFrontError'        => __( 'Homepage and posts page must be different.' ),
1247              'saveBlockedError'        => array(
1248                  /* translators: %s: Number of invalid settings. */
1249                  'singular' => _n( 'Unable to save due to %s invalid setting.', 'Unable to save due to %s invalid settings.', 1 ),
1250                  /* translators: %s: Number of invalid settings. */
1251                  'plural'   => _n( 'Unable to save due to %s invalid setting.', 'Unable to save due to %s invalid settings.', 2 ),
1252                  // @todo This is lacking, as some languages have a dedicated dual form. For proper handling of plurals in JS, see #20491.
1253              ),
1254              'scheduleDescription'     => __( 'Schedule your customization changes to publish ("go live") at a future date.' ),
1255              'themePreviewUnavailable' => __( 'Sorry, you cannot preview new themes when you have changes scheduled or saved as a draft. Please publish your changes, or wait until they publish to preview new themes.' ),
1256              'themeInstallUnavailable' => sprintf(
1257                  /* translators: %s: URL to Add Themes admin screen. */
1258                  __( 'You will not be able to install new themes from here yet since your install requires SFTP credentials. For now, please <a href="%s">add themes in the admin</a>.' ),
1259                  esc_url( admin_url( 'theme-install.php' ) )
1260              ),
1261              'publishSettings'         => __( 'Publish Settings' ),
1262              'invalidDate'             => __( 'Invalid date.' ),
1263              'invalidValue'            => __( 'Invalid value.' ),
1264              'blockThemeNotification'  => sprintf(
1265                  /* translators: 1: Link to Site Editor documentation on HelpHub, 2: HTML button. */
1266                  __( 'Hurray! Your theme supports Full Site Editing with blocks. <a href="%1$s">Tell me more</a>. %2$s' ),
1267                  __( 'https://wordpress.org/support/article/site-editor/' ),
1268                  sprintf(
1269                      '<button type="button" data-action="%1$s" class="button switch-to-editor">%2$s</button>',
1270                      esc_url( admin_url( 'site-editor.php' ) ),
1271                      __( 'Use Site Editor' )
1272                  )
1273              ),
1274          )
1275      );
1276      $scripts->add( 'customize-selective-refresh', "/wp-includes/js/customize-selective-refresh$suffix.js", array( 'jquery', 'wp-util', 'customize-preview' ), false, 1 );
1277  
1278      $scripts->add( 'customize-widgets', "/wp-admin/js/customize-widgets$suffix.js", array( 'jquery', 'jquery-ui-sortable', 'jquery-ui-droppable', 'wp-backbone', 'customize-controls' ), false, 1 );
1279      $scripts->add( 'customize-preview-widgets', "/wp-includes/js/customize-preview-widgets$suffix.js", array( 'jquery', 'wp-util', 'customize-preview', 'customize-selective-refresh' ), false, 1 );
1280  
1281      $scripts->add( 'customize-nav-menus', "/wp-admin/js/customize-nav-menus$suffix.js", array( 'jquery', 'wp-backbone', 'customize-controls', 'accordion', 'nav-menu', 'wp-sanitize' ), false, 1 );
1282      $scripts->add( 'customize-preview-nav-menus', "/wp-includes/js/customize-preview-nav-menus$suffix.js", array( 'jquery', 'wp-util', 'customize-preview', 'customize-selective-refresh' ), false, 1 );
1283  
1284      $scripts->add( 'wp-custom-header', "/wp-includes/js/wp-custom-header$suffix.js", array( 'wp-a11y' ), false, 1 );
1285  
1286      $scripts->add( 'accordion', "/wp-admin/js/accordion$suffix.js", array( 'jquery' ), false, 1 );
1287  
1288      $scripts->add( 'shortcode', "/wp-includes/js/shortcode$suffix.js", array( 'underscore' ), false, 1 );
1289      $scripts->add( 'media-models', "/wp-includes/js/media-models$suffix.js", array( 'wp-backbone' ), false, 1 );
1290      did_action( 'init' ) && $scripts->localize(
1291          'media-models',
1292          '_wpMediaModelsL10n',
1293          array(
1294              'settings' => array(
1295                  'ajaxurl' => admin_url( 'admin-ajax.php', 'relative' ),
1296                  'post'    => array( 'id' => 0 ),
1297              ),
1298          )
1299      );
1300  
1301      $scripts->add( 'wp-embed', "/wp-includes/js/wp-embed$suffix.js", array(), false, 1 );
1302  
1303      // To enqueue media-views or media-editor, call wp_enqueue_media().
1304      // Both rely on numerous settings, styles, and templates to operate correctly.
1305      $scripts->add( 'media-views', "/wp-includes/js/media-views$suffix.js", array( 'utils', 'media-models', 'wp-plupload', 'jquery-ui-sortable', 'wp-mediaelement', 'wp-api-request', 'wp-a11y', 'clipboard' ), false, 1 );
1306      $scripts->set_translations( 'media-views' );
1307  
1308      $scripts->add( 'media-editor', "/wp-includes/js/media-editor$suffix.js", array( 'shortcode', 'media-views' ), false, 1 );
1309      $scripts->set_translations( 'media-editor' );
1310      $scripts->add( 'media-audiovideo', "/wp-includes/js/media-audiovideo$suffix.js", array( 'media-editor' ), false, 1 );
1311      $scripts->add( 'mce-view', "/wp-includes/js/mce-view$suffix.js", array( 'shortcode', 'jquery', 'media-views', 'media-audiovideo' ), false, 1 );
1312  
1313      $scripts->add( 'wp-api', "/wp-includes/js/wp-api$suffix.js", array( 'jquery', 'backbone', 'underscore', 'wp-api-request' ), false, 1 );
1314  
1315      if ( is_admin() ) {
1316          $scripts->add( 'admin-tags', "/wp-admin/js/tags$suffix.js", array( 'jquery', 'wp-ajax-response' ), false, 1 );
1317          $scripts->set_translations( 'admin-tags' );
1318  
1319          $scripts->add( 'admin-comments', "/wp-admin/js/edit-comments$suffix.js", array( 'wp-lists', 'quicktags', 'jquery-query' ), false, 1 );
1320          $scripts->set_translations( 'admin-comments' );
1321          did_action( 'init' ) && $scripts->localize(
1322              'admin-comments',
1323              'adminCommentsSettings',
1324              array(
1325                  'hotkeys_highlight_first' => isset( $_GET['hotkeys_highlight_first'] ),
1326                  'hotkeys_highlight_last'  => isset( $_GET['hotkeys_highlight_last'] ),
1327              )
1328          );
1329  
1330          $scripts->add( 'xfn', "/wp-admin/js/xfn$suffix.js", array( 'jquery' ), false, 1 );
1331  
1332          $scripts->add( 'postbox', "/wp-admin/js/postbox$suffix.js", array( 'jquery-ui-sortable', 'wp-a11y' ), false, 1 );
1333          $scripts->set_translations( 'postbox' );
1334  
1335          $scripts->add( 'tags-box', "/wp-admin/js/tags-box$suffix.js", array( 'jquery', 'tags-suggest' ), false, 1 );
1336          $scripts->set_translations( 'tags-box' );
1337  
1338          $scripts->add( 'tags-suggest', "/wp-admin/js/tags-suggest$suffix.js", array( 'jquery-ui-autocomplete', 'wp-a11y' ), false, 1 );
1339          $scripts->set_translations( 'tags-suggest' );
1340  
1341          $scripts->add( 'post', "/wp-admin/js/post$suffix.js", array( 'suggest', 'wp-lists', 'postbox', 'tags-box', 'underscore', 'word-count', 'wp-a11y', 'wp-sanitize', 'clipboard' ), false, 1 );
1342          $scripts->set_translations( 'post' );
1343  
1344          $scripts->add( 'editor-expand', "/wp-admin/js/editor-expand$suffix.js", array( 'jquery', 'underscore' ), false, 1 );
1345  
1346          $scripts->add( 'link', "/wp-admin/js/link$suffix.js", array( 'wp-lists', 'postbox' ), false, 1 );
1347  
1348          $scripts->add( 'comment', "/wp-admin/js/comment$suffix.js", array( 'jquery', 'postbox' ), false, 1 );
1349          $scripts->set_translations( 'comment' );
1350  
1351          $scripts->add( 'admin-gallery', "/wp-admin/js/gallery$suffix.js", array( 'jquery-ui-sortable' ) );
1352  
1353          $scripts->add( 'admin-widgets', "/wp-admin/js/widgets$suffix.js", array( 'jquery-ui-sortable', 'jquery-ui-draggable', 'jquery-ui-droppable', 'wp-a11y' ), false, 1 );
1354          $scripts->set_translations( 'admin-widgets' );
1355  
1356          $scripts->add( 'media-widgets', "/wp-admin/js/widgets/media-widgets$suffix.js", array( 'jquery', 'media-models', 'media-views', 'wp-api-request' ) );
1357          $scripts->add_inline_script( 'media-widgets', 'wp.mediaWidgets.init();', 'after' );
1358  
1359          $scripts->add( 'media-audio-widget', "/wp-admin/js/widgets/media-audio-widget$suffix.js", array( 'media-widgets', 'media-audiovideo' ) );
1360          $scripts->add( 'media-image-widget', "/wp-admin/js/widgets/media-image-widget$suffix.js", array( 'media-widgets' ) );
1361          $scripts->add( 'media-gallery-widget', "/wp-admin/js/widgets/media-gallery-widget$suffix.js", array( 'media-widgets' ) );
1362          $scripts->add( 'media-video-widget', "/wp-admin/js/widgets/media-video-widget$suffix.js", array( 'media-widgets', 'media-audiovideo', 'wp-api-request' ) );
1363          $scripts->add( 'text-widgets', "/wp-admin/js/widgets/text-widgets$suffix.js", array( 'jquery', 'backbone', 'editor', 'wp-util', 'wp-a11y' ) );
1364          $scripts->add( 'custom-html-widgets', "/wp-admin/js/widgets/custom-html-widgets$suffix.js", array( 'jquery', 'backbone', 'wp-util', 'jquery-ui-core', 'wp-a11y' ) );
1365  
1366          $scripts->add( 'theme', "/wp-admin/js/theme$suffix.js", array( 'wp-backbone', 'wp-a11y', 'customize-base' ), false, 1 );
1367  
1368          $scripts->add( 'inline-edit-post', "/wp-admin/js/inline-edit-post$suffix.js", array( 'jquery', 'tags-suggest', 'wp-a11y' ), false, 1 );
1369          $scripts->set_translations( 'inline-edit-post' );
1370  
1371          $scripts->add( 'inline-edit-tax', "/wp-admin/js/inline-edit-tax$suffix.js", array( 'jquery', 'wp-a11y' ), false, 1 );
1372          $scripts->set_translations( 'inline-edit-tax' );
1373  
1374          $scripts->add( 'plugin-install', "/wp-admin/js/plugin-install$suffix.js", array( 'jquery', 'jquery-ui-core', 'thickbox' ), false, 1 );
1375          $scripts->set_translations( 'plugin-install' );
1376  
1377          $scripts->add( 'site-health', "/wp-admin/js/site-health$suffix.js", array( 'clipboard', 'jquery', 'wp-util', 'wp-a11y', 'wp-api-request', 'wp-url', 'wp-i18n', 'wp-hooks' ), false, 1 );
1378          $scripts->set_translations( 'site-health' );
1379  
1380          $scripts->add( 'privacy-tools', "/wp-admin/js/privacy-tools$suffix.js", array( 'jquery', 'wp-a11y' ), false, 1 );
1381          $scripts->set_translations( 'privacy-tools' );
1382  
1383          $scripts->add( 'updates', "/wp-admin/js/updates$suffix.js", array( 'common', 'jquery', 'wp-util', 'wp-a11y', 'wp-sanitize', 'wp-i18n' ), false, 1 );
1384          $scripts->set_translations( 'updates' );
1385          did_action( 'init' ) && $scripts->localize(
1386              'updates',
1387              '_wpUpdatesSettings',
1388              array(
1389                  'ajax_nonce' => wp_installing() ? '' : wp_create_nonce( 'updates' ),
1390              )
1391          );
1392  
1393          $scripts->add( 'farbtastic', '/wp-admin/js/farbtastic.js', array( 'jquery' ), '1.2' );
1394  
1395          $scripts->add( 'iris', '/wp-admin/js/iris.min.js', array( 'jquery-ui-draggable', 'jquery-ui-slider', 'jquery-touch-punch' ), '1.1.1', 1 );
1396          $scripts->add( 'wp-color-picker', "/wp-admin/js/color-picker$suffix.js", array( 'iris' ), false, 1 );
1397          $scripts->set_translations( 'wp-color-picker' );
1398  
1399          $scripts->add( 'dashboard', "/wp-admin/js/dashboard$suffix.js", array( 'jquery', 'admin-comments', 'postbox', 'wp-util', 'wp-a11y', 'wp-date' ), false, 1 );
1400          $scripts->set_translations( 'dashboard' );
1401  
1402          $scripts->add( 'list-revisions', "/wp-includes/js/wp-list-revisions$suffix.js" );
1403  
1404          $scripts->add( 'media-grid', "/wp-includes/js/media-grid$suffix.js", array( 'media-editor' ), false, 1 );
1405          $scripts->add( 'media', "/wp-admin/js/media$suffix.js", array( 'jquery', 'clipboard', 'wp-i18n', 'wp-a11y' ), false, 1 );
1406          $scripts->set_translations( 'media' );
1407  
1408          $scripts->add( 'image-edit', "/wp-admin/js/image-edit$suffix.js", array( 'jquery', 'jquery-ui-core', 'json2', 'imgareaselect', 'wp-a11y' ), false, 1 );
1409          $scripts->set_translations( 'image-edit' );
1410  
1411          $scripts->add( 'set-post-thumbnail', "/wp-admin/js/set-post-thumbnail$suffix.js", array( 'jquery' ), false, 1 );
1412          $scripts->set_translations( 'set-post-thumbnail' );
1413  
1414          /*
1415           * Navigation Menus: Adding underscore as a dependency to utilize _.debounce
1416           * see https://core.trac.wordpress.org/ticket/42321
1417           */
1418          $scripts->add( 'nav-menu', "/wp-admin/js/nav-menu$suffix.js", array( 'jquery-ui-sortable', 'jquery-ui-draggable', 'jquery-ui-droppable', 'wp-lists', 'postbox', 'json2', 'underscore' ) );
1419          $scripts->set_translations( 'nav-menu' );
1420  
1421          $scripts->add( 'custom-header', '/wp-admin/js/custom-header.js', array( 'jquery-masonry' ), false, 1 );
1422          $scripts->add( 'custom-background', "/wp-admin/js/custom-background$suffix.js", array( 'wp-color-picker', 'media-views' ), false, 1 );
1423          $scripts->add( 'media-gallery', "/wp-admin/js/media-gallery$suffix.js", array( 'jquery' ), false, 1 );
1424  
1425          $scripts->add( 'svg-painter', '/wp-admin/js/svg-painter.js', array( 'jquery' ), false, 1 );
1426      }
1427  }
1428  
1429  /**
1430   * Assigns default styles to $styles object.
1431   *
1432   * Nothing is returned, because the $styles parameter is passed by reference.
1433   * Meaning that whatever object is passed will be updated without having to
1434   * reassign the variable that was passed back to the same value. This saves
1435   * memory.
1436   *
1437   * Adding default styles is not the only task, it also assigns the base_url
1438   * property, the default version, and text direction for the object.
1439   *
1440   * @since 2.6.0
1441   *
1442   * @global array $editor_styles
1443   *
1444   * @param WP_Styles $styles
1445   */
1446  function wp_default_styles( $styles ) {
1447      global $editor_styles;
1448  
1449      // Include an unmodified $wp_version.
1450      require  ABSPATH . WPINC . '/version.php';
1451  
1452      if ( ! defined( 'SCRIPT_DEBUG' ) ) {
1453          define( 'SCRIPT_DEBUG', false !== strpos( $wp_version, '-src' ) );
1454      }
1455  
1456      $guessurl = site_url();
1457  
1458      if ( ! $guessurl ) {
1459          $guessurl = wp_guess_url();
1460      }
1461  
1462      $styles->base_url        = $guessurl;
1463      $styles->content_url     = defined( 'WP_CONTENT_URL' ) ? WP_CONTENT_URL : '';
1464      $styles->default_version = get_bloginfo( 'version' );
1465      $styles->text_direction  = function_exists( 'is_rtl' ) && is_rtl() ? 'rtl' : 'ltr';
1466      $styles->default_dirs    = array( '/wp-admin/', '/wp-includes/css/' );
1467  
1468      // Open Sans is no longer used by core, but may be relied upon by themes and plugins.
1469      $open_sans_font_url = '';
1470  
1471      /*
1472       * translators: If there are characters in your language that are not supported
1473       * by Open Sans, translate this to 'off'. Do not translate into your own language.
1474       */
1475      if ( 'off' !== _x( 'on', 'Open Sans font: on or off' ) ) {
1476          $subsets = 'latin,latin-ext';
1477  
1478          /*
1479           * translators: To add an additional Open Sans character subset specific to your language,
1480           * translate this to 'greek', 'cyrillic' or 'vietnamese'. Do not translate into your own language.
1481           */
1482          $subset = _x( 'no-subset', 'Open Sans font: add new subset (greek, cyrillic, vietnamese)' );
1483  
1484          if ( 'cyrillic' === $subset ) {
1485              $subsets .= ',cyrillic,cyrillic-ext';
1486          } elseif ( 'greek' === $subset ) {
1487              $subsets .= ',greek,greek-ext';
1488          } elseif ( 'vietnamese' === $subset ) {
1489              $subsets .= ',vietnamese';
1490          }
1491  
1492          // Hotlink Open Sans, for now.
1493          $open_sans_font_url = "https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,300,400,600&subset=$subsets&display=fallback";
1494      }
1495  
1496      // Register a stylesheet for the selected admin color scheme.
1497      $styles->add( 'colors', true, array( 'wp-admin', 'buttons' ) );
1498  
1499      $suffix = SCRIPT_DEBUG ? '' : '.min';
1500  
1501      // Admin CSS.
1502      $styles->add( 'common', "/wp-admin/css/common$suffix.css" );
1503      $styles->add( 'forms', "/wp-admin/css/forms$suffix.css" );
1504      $styles->add( 'admin-menu', "/wp-admin/css/admin-menu$suffix.css" );
1505      $styles->add( 'dashboard', "/wp-admin/css/dashboard$suffix.css" );
1506      $styles->add( 'list-tables', "/wp-admin/css/list-tables$suffix.css" );
1507      $styles->add( 'edit', "/wp-admin/css/edit$suffix.css" );
1508      $styles->add( 'revisions', "/wp-admin/css/revisions$suffix.css" );
1509      $styles->add( 'media', "/wp-admin/css/media$suffix.css" );
1510      $styles->add( 'themes', "/wp-admin/css/themes$suffix.css" );
1511      $styles->add( 'about', "/wp-admin/css/about$suffix.css" );
1512      $styles->add( 'nav-menus', "/wp-admin/css/nav-menus$suffix.css" );
1513      $styles->add( 'widgets', "/wp-admin/css/widgets$suffix.css", array( 'wp-pointer' ) );
1514      $styles->add( 'site-icon', "/wp-admin/css/site-icon$suffix.css" );
1515      $styles->add( 'l10n', "/wp-admin/css/l10n$suffix.css" );
1516      $styles->add( 'code-editor', "/wp-admin/css/code-editor$suffix.css", array( 'wp-codemirror' ) );
1517      $styles->add( 'site-health', "/wp-admin/css/site-health$suffix.css" );
1518  
1519      $styles->add( 'wp-admin', false, array( 'dashicons', 'common', 'forms', 'admin-menu', 'dashboard', 'list-tables', 'edit', 'revisions', 'media', 'themes', 'about', 'nav-menus', 'widgets', 'site-icon', 'l10n' ) );
1520  
1521      $styles->add( 'login', "/wp-admin/css/login$suffix.css", array( 'dashicons', 'buttons', 'forms', 'l10n' ) );
1522      $styles->add( 'install', "/wp-admin/css/install$suffix.css", array( 'dashicons', 'buttons', 'forms', 'l10n' ) );
1523      $styles->add( 'wp-color-picker', "/wp-admin/css/color-picker$suffix.css" );
1524      $styles->add( 'customize-controls', "/wp-admin/css/customize-controls$suffix.css", array( 'wp-admin', 'colors', 'imgareaselect' ) );
1525      $styles->add( 'customize-widgets', "/wp-admin/css/customize-widgets$suffix.css", array( 'wp-admin', 'colors' ) );
1526      $styles->add( 'customize-nav-menus', "/wp-admin/css/customize-nav-menus$suffix.css", array( 'wp-admin', 'colors' ) );
1527  
1528      // Common dependencies.
1529      $styles->add( 'buttons', "/wp-includes/css/buttons$suffix.css" );
1530      $styles->add( 'dashicons', "/wp-includes/css/dashicons$suffix.css" );
1531  
1532      // Includes CSS.
1533      $styles->add( 'admin-bar', "/wp-includes/css/admin-bar$suffix.css", array( 'dashicons' ) );
1534      $styles->add( 'wp-auth-check', "/wp-includes/css/wp-auth-check$suffix.css", array( 'dashicons' ) );
1535      $styles->add( 'editor-buttons', "/wp-includes/css/editor$suffix.css", array( 'dashicons' ) );
1536      $styles->add( 'media-views', "/wp-includes/css/media-views$suffix.css", array( 'buttons', 'dashicons', 'wp-mediaelement' ) );
1537      $styles->add( 'wp-pointer', "/wp-includes/css/wp-pointer$suffix.css", array( 'dashicons' ) );
1538      $styles->add( 'customize-preview', "/wp-includes/css/customize-preview$suffix.css", array( 'dashicons' ) );
1539      $styles->add( 'wp-embed-template-ie', "/wp-includes/css/wp-embed-template-ie$suffix.css" );
1540      $styles->add_data( 'wp-embed-template-ie', 'conditional', 'lte IE 8' );
1541  
1542      // External libraries and friends.
1543      $styles->add( 'imgareaselect', '/wp-includes/js/imgareaselect/imgareaselect.css', array(), '0.9.8' );
1544      $styles->add( 'wp-jquery-ui-dialog', "/wp-includes/css/jquery-ui-dialog$suffix.css", array( 'dashicons' ) );
1545      $styles->add( 'mediaelement', '/wp-includes/js/mediaelement/mediaelementplayer-legacy.min.css', array(), '4.2.16' );
1546      $styles->add( 'wp-mediaelement', "/wp-includes/js/mediaelement/wp-mediaelement$suffix.css", array( 'mediaelement' ) );
1547      $styles->add( 'thickbox', '/wp-includes/js/thickbox/thickbox.css', array( 'dashicons' ) );
1548      $styles->add( 'wp-codemirror', '/wp-includes/js/codemirror/codemirror.min.css', array(), '5.29.1-alpha-ee20357' );
1549  
1550      // Deprecated CSS.
1551      $styles->add( 'deprecated-media', "/wp-admin/css/deprecated-media$suffix.css" );
1552      $styles->add( 'farbtastic', "/wp-admin/css/farbtastic$suffix.css", array(), '1.3u1' );
1553      $styles->add( 'jcrop', '/wp-includes/js/jcrop/jquery.Jcrop.min.css', array(), '0.9.15' );
1554      $styles->add( 'colors-fresh', false, array( 'wp-admin', 'buttons' ) ); // Old handle.
1555      $styles->add( 'open-sans', $open_sans_font_url ); // No longer used in core as of 4.6.
1556  
1557      // Noto Serif is no longer used by core, but may be relied upon by themes and plugins.
1558      $fonts_url = '';
1559  
1560      /*
1561       * translators: Use this to specify the proper Google Font name and variants
1562       * to load that is supported by your language. Do not translate.
1563       * Set to 'off' to disable loading.
1564       */
1565      $font_family = _x( 'Noto Serif:400,400i,700,700i', 'Google Font Name and Variants' );
1566      if ( 'off' !== $font_family ) {
1567          $fonts_url = 'https://fonts.googleapis.com/css?family=' . urlencode( $font_family );
1568      }
1569      $styles->add( 'wp-editor-font', $fonts_url ); // No longer used in core as of 5.7.
1570      $block_library_theme_path = WPINC . "/css/dist/block-library/theme$suffix.css";
1571      $styles->add( 'wp-block-library-theme', "/$block_library_theme_path" );
1572      $styles->add_data( 'wp-block-library-theme', 'path', ABSPATH . $block_library_theme_path );
1573  
1574      $styles->add(
1575          'wp-reset-editor-styles',
1576          "/wp-includes/css/dist/block-library/reset$suffix.css",
1577          array( 'common', 'forms' ) // Make sure the reset is loaded after the default WP Admin styles.
1578      );
1579  
1580      $styles->add(
1581          'wp-editor-classic-layout-styles',
1582          "/wp-includes/css/dist/edit-post/classic$suffix.css",
1583          array()
1584      );
1585  
1586      $wp_edit_blocks_dependencies = array(
1587          'wp-components',
1588          'wp-editor',
1589          // This need to be added before the block library styles,
1590          // The block library styles override the "reset" styles.
1591          'wp-reset-editor-styles',
1592          'wp-block-library',
1593          'wp-reusable-blocks',
1594      );
1595  
1596      // Only load the default layout and margin styles for themes without theme.json file.
1597      if ( ! WP_Theme_JSON_Resolver::theme_has_support() ) {
1598          $wp_edit_blocks_dependencies[] = 'wp-editor-classic-layout-styles';
1599      }
1600  
1601      if ( ! is_array( $editor_styles ) || count( $editor_styles ) === 0 ) {
1602          // Include opinionated block styles if no $editor_styles are declared, so the editor never appears broken.
1603          $wp_edit_blocks_dependencies[] = 'wp-block-library-theme';
1604      }
1605  
1606      $styles->add(
1607          'wp-edit-blocks',
1608          "/wp-includes/css/dist/block-library/editor$suffix.css",
1609          $wp_edit_blocks_dependencies
1610      );
1611  
1612      $package_styles = array(
1613          'block-editor'         => array( 'wp-components' ),
1614          'block-library'        => array(),
1615          'block-directory'      => array(),
1616          'components'           => array(),
1617          'edit-post'            => array(
1618              'wp-components',
1619              'wp-block-editor',
1620              'wp-editor',
1621              'wp-edit-blocks',
1622              'wp-block-library',
1623              'wp-nux',
1624          ),
1625          'editor'               => array(
1626              'wp-components',
1627              'wp-block-editor',
1628              'wp-nux',
1629              'wp-reusable-blocks',
1630          ),
1631          'format-library'       => array(),
1632          'list-reusable-blocks' => array( 'wp-components' ),
1633          'reusable-blocks'      => array( 'wp-components' ),
1634          'nux'                  => array( 'wp-components' ),
1635          'widgets'              => array(
1636              'wp-components',
1637          ),
1638          'edit-widgets'         => array(
1639              'wp-widgets',
1640              'wp-block-editor',
1641              'wp-edit-blocks',
1642              'wp-block-library',
1643              'wp-reusable-blocks',
1644          ),
1645          'customize-widgets'    => array(
1646              'wp-widgets',
1647              'wp-block-editor',
1648              'wp-edit-blocks',
1649              'wp-block-library',
1650              'wp-reusable-blocks',
1651          ),
1652          'edit-site'            => array(
1653              'wp-components',
1654              'wp-block-editor',
1655              'wp-edit-blocks',
1656          ),
1657      );
1658  
1659      foreach ( $package_styles as $package => $dependencies ) {
1660          $handle = 'wp-' . $package;
1661          $path   = "/wp-includes/css/dist/$package/style$suffix.css";
1662  
1663          if ( 'block-library' === $package && wp_should_load_separate_core_block_assets() ) {
1664              $path = "/wp-includes/css/dist/$package/common$suffix.css";
1665          }
1666          $styles->add( $handle, $path, $dependencies );
1667          $styles->add_data( $handle, 'path', ABSPATH . $path );
1668      }
1669  
1670      // RTL CSS.
1671      $rtl_styles = array(
1672          // Admin CSS.
1673          'common',
1674          'forms',
1675          'admin-menu',
1676          'dashboard',
1677          'list-tables',
1678          'edit',
1679          'revisions',
1680          'media',
1681          'themes',
1682          'about',
1683          'nav-menus',
1684          'widgets',
1685          'site-icon',
1686          'l10n',
1687          'install',
1688          'wp-color-picker',
1689          'customize-controls',
1690          'customize-widgets',
1691          'customize-nav-menus',
1692          'customize-preview',
1693          'login',
1694          'site-health',
1695          // Includes CSS.
1696          'buttons',
1697          'admin-bar',
1698          'wp-auth-check',
1699          'editor-buttons',
1700          'media-views',
1701          'wp-pointer',
1702          'wp-jquery-ui-dialog',
1703          // Package styles.
1704          'wp-reset-editor-styles',
1705          'wp-editor-classic-layout-styles',
1706          'wp-block-library-theme',
1707          'wp-edit-blocks',
1708          'wp-block-editor',
1709          'wp-block-library',
1710          'wp-block-directory',
1711          'wp-components',
1712          'wp-customize-widgets',
1713          'wp-edit-post',
1714          'wp-edit-site',
1715          'wp-edit-widgets',
1716          'wp-editor',
1717          'wp-format-library',
1718          'wp-list-reusable-blocks',
1719          'wp-reusable-blocks',
1720          'wp-nux',
1721          'wp-widgets',
1722          // Deprecated CSS.
1723          'deprecated-media',
1724          'farbtastic',
1725      );
1726  
1727      foreach ( $rtl_styles as $rtl_style ) {
1728          $styles->add_data( $rtl_style, 'rtl', 'replace' );
1729          if ( $suffix ) {
1730              $styles->add_data( $rtl_style, 'suffix', $suffix );
1731          }
1732      }
1733  }
1734  
1735  /**
1736   * Reorders JavaScript scripts array to place prototype before jQuery.
1737   *
1738   * @since 2.3.1
1739   *
1740   * @param array $js_array JavaScript scripts array
1741   * @return array Reordered array, if needed.
1742   */
1743  function wp_prototype_before_jquery( $js_array ) {
1744      $prototype = array_search( 'prototype', $js_array, true );
1745  
1746      if ( false === $prototype ) {
1747          return $js_array;
1748      }
1749  
1750      $jquery = array_search( 'jquery', $js_array, true );
1751  
1752      if ( false === $jquery ) {
1753          return $js_array;
1754      }
1755  
1756      if ( $prototype < $jquery ) {
1757          return $js_array;
1758      }
1759  
1760      unset( $js_array[ $prototype ] );
1761  
1762      array_splice( $js_array, $jquery, 0, 'prototype' );
1763  
1764      return $js_array;
1765  }
1766  
1767  /**
1768   * Loads localized data on print rather than initialization.
1769   *
1770   * These localizations require information that may not be loaded even by init.
1771   *
1772   * @since 2.5.0
1773   */
1774  function wp_just_in_time_script_localization() {
1775  
1776      wp_localize_script(
1777          'autosave',
1778          'autosaveL10n',
1779          array(
1780              'autosaveInterval' => AUTOSAVE_INTERVAL,
1781              'blog_id'          => get_current_blog_id(),
1782          )
1783      );
1784  
1785      wp_localize_script(
1786          'mce-view',
1787          'mceViewL10n',
1788          array(
1789              'shortcodes' => ! empty( $GLOBALS['shortcode_tags'] ) ? array_keys( $GLOBALS['shortcode_tags'] ) : array(),
1790          )
1791      );
1792  
1793      wp_localize_script(
1794          'word-count',
1795          'wordCountL10n',
1796          array(
1797              /*
1798               * translators: If your word count is based on single characters (e.g. East Asian characters),
1799               * enter 'characters_excluding_spaces' or 'characters_including_spaces'. Otherwise, enter 'words'.
1800               * Do not translate into your own language.
1801               */
1802              'type'       => _x( 'words', 'Word count type. Do not translate!' ),
1803              'shortcodes' => ! empty( $GLOBALS['shortcode_tags'] ) ? array_keys( $GLOBALS['shortcode_tags'] ) : array(),
1804          )
1805      );
1806  }
1807  
1808  /**
1809   * Localizes the jQuery UI datepicker.
1810   *
1811   * @since 4.6.0
1812   *
1813   * @link https://api.jqueryui.com/datepicker/#options
1814   *
1815   * @global WP_Locale $wp_locale WordPress date and time locale object.
1816   */
1817  function wp_localize_jquery_ui_datepicker() {
1818      global $wp_locale;
1819  
1820      if ( ! wp_script_is( 'jquery-ui-datepicker', 'enqueued' ) ) {
1821          return;
1822      }
1823  
1824      // Convert the PHP date format into jQuery UI's format.
1825      $datepicker_date_format = str_replace(
1826          array(
1827              'd',
1828              'j',
1829              'l',
1830              'z', // Day.
1831              'F',
1832              'M',
1833              'n',
1834              'm', // Month.
1835              'Y',
1836              'y', // Year.
1837          ),
1838          array(
1839              'dd',
1840              'd',
1841              'DD',
1842              'o',
1843              'MM',
1844              'M',
1845              'm',
1846              'mm',
1847              'yy',
1848              'y',
1849          ),
1850          get_option( 'date_format' )
1851      );
1852  
1853      $datepicker_defaults = wp_json_encode(
1854          array(
1855              'closeText'       => __( 'Close' ),
1856              'currentText'     => __( 'Today' ),
1857              'monthNames'      => array_values( $wp_locale->month ),
1858              'monthNamesShort' => array_values( $wp_locale->month_abbrev ),
1859              'nextText'        => __( 'Next' ),
1860              'prevText'        => __( 'Previous' ),
1861              'dayNames'        => array_values( $wp_locale->weekday ),
1862              'dayNamesShort'   => array_values( $wp_locale->weekday_abbrev ),
1863              'dayNamesMin'     => array_values( $wp_locale->weekday_initial ),
1864              'dateFormat'      => $datepicker_date_format,
1865              'firstDay'        => absint( get_option( 'start_of_week' ) ),
1866              'isRTL'           => $wp_locale->is_rtl(),
1867          )
1868      );
1869  
1870      wp_add_inline_script( 'jquery-ui-datepicker', "jQuery(function(jQuery){jQuery.datepicker.setDefaults({$datepicker_defaults});});" );
1871  }
1872  
1873  /**
1874   * Localizes community events data that needs to be passed to dashboard.js.
1875   *
1876   * @since 4.8.0
1877   */
1878  function wp_localize_community_events() {
1879      if ( ! wp_script_is( 'dashboard' ) ) {
1880          return;
1881      }
1882  
1883      require_once ABSPATH . 'wp-admin/includes/class-wp-community-events.php';
1884  
1885      $user_id            = get_current_user_id();
1886      $saved_location     = get_user_option( 'community-events-location', $user_id );
1887      $saved_ip_address   = isset( $saved_location['ip'] ) ? $saved_location['ip'] : false;
1888      $current_ip_address = WP_Community_Events::get_unsafe_client_ip();
1889  
1890      /*
1891       * If the user's location is based on their IP address, then update their
1892       * location when their IP address changes. This allows them to see events
1893       * in their current city when travelling. Otherwise, they would always be
1894       * shown events in the city where they were when they first loaded the
1895       * Dashboard, which could have been months or years ago.
1896       */
1897      if ( $saved_ip_address && $current_ip_address && $current_ip_address !== $saved_ip_address ) {
1898          $saved_location['ip'] = $current_ip_address;
1899          update_user_meta( $user_id, 'community-events-location', $saved_location );
1900      }
1901  
1902      $events_client = new WP_Community_Events( $user_id, $saved_location );
1903  
1904      wp_localize_script(
1905          'dashboard',
1906          'communityEventsData',
1907          array(
1908              'nonce'       => wp_create_nonce( 'community_events' ),
1909              'cache'       => $events_client->get_cached_events(),
1910              'time_format' => get_option( 'time_format' ),
1911          )
1912      );
1913  }
1914  
1915  /**
1916   * Administration Screen CSS for changing the styles.
1917   *
1918   * If installing the 'wp-admin/' directory will be replaced with './'.
1919   *
1920   * The $_wp_admin_css_colors global manages the Administration Screens CSS
1921   * stylesheet that is loaded. The option that is set is 'admin_color' and is the
1922   * color and key for the array. The value for the color key is an object with
1923   * a 'url' parameter that has the URL path to the CSS file.
1924   *
1925   * The query from $src parameter will be appended to the URL that is given from
1926   * the $_wp_admin_css_colors array value URL.
1927   *
1928   * @since 2.6.0
1929   *
1930   * @global array $_wp_admin_css_colors
1931   *
1932   * @param string $src    Source URL.
1933   * @param string $handle Either 'colors' or 'colors-rtl'.
1934   * @return string|false URL path to CSS stylesheet for Administration Screens.
1935   */
1936  function wp_style_loader_src( $src, $handle ) {
1937      global $_wp_admin_css_colors;
1938  
1939      if ( wp_installing() ) {
1940          return preg_replace( '#^wp-admin/#', './', $src );
1941      }
1942  
1943      if ( 'colors' === $handle ) {
1944          $color = get_user_option( 'admin_color' );
1945  
1946          if ( empty( $color ) || ! isset( $_wp_admin_css_colors[ $color ] ) ) {
1947              $color = 'fresh';
1948          }
1949  
1950          $color = $_wp_admin_css_colors[ $color ];
1951          $url   = $color->url;
1952  
1953          if ( ! $url ) {
1954              return false;
1955          }
1956  
1957          $parsed = parse_url( $src );
1958          if ( isset( $parsed['query'] ) && $parsed['query'] ) {
1959              wp_parse_str( $parsed['query'], $qv );
1960              $url = add_query_arg( $qv, $url );
1961          }
1962  
1963          return $url;
1964      }
1965  
1966      return $src;
1967  }
1968  
1969  /**
1970   * Prints the script queue in the HTML head on admin pages.
1971   *
1972   * Postpones the scripts that were queued for the footer.
1973   * print_footer_scripts() is called in the footer to print these scripts.
1974   *
1975   * @since 2.8.0
1976   *
1977   * @see wp_print_scripts()
1978   *
1979   * @global bool $concatenate_scripts
1980   *
1981   * @return array
1982   */
1983  function print_head_scripts() {
1984      global $concatenate_scripts;
1985  
1986      if ( ! did_action( 'wp_print_scripts' ) ) {
1987          /** This action is documented in wp-includes/functions.wp-scripts.php */
1988          do_action( 'wp_print_scripts' );
1989      }
1990  
1991      $wp_scripts = wp_scripts();
1992  
1993      script_concat_settings();
1994      $wp_scripts->do_concat = $concatenate_scripts;
1995      $wp_scripts->do_head_items();
1996  
1997      /**
1998       * Filters whether to print the head scripts.
1999       *
2000       * @since 2.8.0
2001       *
2002       * @param bool $print Whether to print the head scripts. Default true.
2003       */
2004      if ( apply_filters( 'print_head_scripts', true ) ) {
2005          _print_scripts();
2006      }
2007  
2008      $wp_scripts->reset();
2009      return $wp_scripts->done;
2010  }
2011  
2012  /**
2013   * Prints the scripts that were queued for the footer or too late for the HTML head.
2014   *
2015   * @since 2.8.0
2016   *
2017   * @global WP_Scripts $wp_scripts
2018   * @global bool       $concatenate_scripts
2019   *
2020   * @return array
2021   */
2022  function print_footer_scripts() {
2023      global $wp_scripts, $concatenate_scripts;
2024  
2025      if ( ! ( $wp_scripts instanceof WP_Scripts ) ) {
2026          return array(); // No need to run if not instantiated.
2027      }
2028      script_concat_settings();
2029      $wp_scripts->do_concat = $concatenate_scripts;
2030      $wp_scripts->do_footer_items();
2031  
2032      /**
2033       * Filters whether to print the footer scripts.
2034       *
2035       * @since 2.8.0
2036       *
2037       * @param bool $print Whether to print the footer scripts. Default true.
2038       */
2039      if ( apply_filters( 'print_footer_scripts', true ) ) {
2040          _print_scripts();
2041      }
2042  
2043      $wp_scripts->reset();
2044      return $wp_scripts->done;
2045  }
2046  
2047  /**
2048   * Prints scripts (internal use only)
2049   *
2050   * @ignore
2051   *
2052   * @global WP_Scripts $wp_scripts
2053   * @global bool       $compress_scripts
2054   */
2055  function _print_scripts() {
2056      global $wp_scripts, $compress_scripts;
2057  
2058      $zip = $compress_scripts ? 1 : 0;
2059      if ( $zip && defined( 'ENFORCE_GZIP' ) && ENFORCE_GZIP ) {
2060          $zip = 'gzip';
2061      }
2062  
2063      $concat    = trim( $wp_scripts->concat, ', ' );
2064      $type_attr = current_theme_supports( 'html5', 'script' ) ? '' : " type='text/javascript'";
2065  
2066      if ( $concat ) {
2067          if ( ! empty( $wp_scripts->print_code ) ) {
2068              echo "\n<script{$type_attr}>\n";
2069              echo "/* <![CDATA[ */\n"; // Not needed in HTML 5.
2070              echo $wp_scripts->print_code;
2071              echo "/* ]]> */\n";
2072              echo "</script>\n";
2073          }
2074  
2075          $concat       = str_split( $concat, 128 );
2076          $concatenated = '';
2077  
2078          foreach ( $concat as $key => $chunk ) {
2079              $concatenated .= "&load%5Bchunk_{$key}%5D={$chunk}";
2080          }
2081  
2082          $src = $wp_scripts->base_url . "/wp-admin/load-scripts.php?c={$zip}" . $concatenated . '&ver=' . $wp_scripts->default_version;
2083          echo "<script{$type_attr} src='" . esc_attr( $src ) . "'></script>\n";
2084      }
2085  
2086      if ( ! empty( $wp_scripts->print_html ) ) {
2087          echo $wp_scripts->print_html;
2088      }
2089  }
2090  
2091  /**
2092   * Prints the script queue in the HTML head on the front end.
2093   *
2094   * Postpones the scripts that were queued for the footer.
2095   * wp_print_footer_scripts() is called in the footer to print these scripts.
2096   *
2097   * @since 2.8.0
2098   *
2099   * @global WP_Scripts $wp_scripts
2100   *
2101   * @return array
2102   */
2103  function wp_print_head_scripts() {
2104      global $wp_scripts;
2105  
2106      if ( ! did_action( 'wp_print_scripts' ) ) {
2107          /** This action is documented in wp-includes/functions.wp-scripts.php */
2108          do_action( 'wp_print_scripts' );
2109      }
2110  
2111      if ( ! ( $wp_scripts instanceof WP_Scripts ) ) {
2112          return array(); // No need to run if nothing is queued.
2113      }
2114  
2115      return print_head_scripts();
2116  }
2117  
2118  /**
2119   * Private, for use in *_footer_scripts hooks
2120   *
2121   * @since 3.3.0
2122   */
2123  function _wp_footer_scripts() {
2124      print_late_styles();
2125      print_footer_scripts();
2126  }
2127  
2128  /**
2129   * Hooks to print the scripts and styles in the footer.
2130   *
2131   * @since 2.8.0
2132   */
2133  function wp_print_footer_scripts() {
2134      /**
2135       * Fires when footer scripts are printed.
2136       *
2137       * @since 2.8.0
2138       */
2139      do_action( 'wp_print_footer_scripts' );
2140  }
2141  
2142  /**
2143   * Wrapper for do_action( 'wp_enqueue_scripts' ).
2144   *
2145   * Allows plugins to queue scripts for the front end using wp_enqueue_script().
2146   * Runs first in wp_head() where all is_home(), is_page(), etc. functions are available.
2147   *
2148   * @since 2.8.0
2149   */
2150  function wp_enqueue_scripts() {
2151      /**
2152       * Fires when scripts and styles are enqueued.
2153       *
2154       * @since 2.8.0
2155       */
2156      do_action( 'wp_enqueue_scripts' );
2157  }
2158  
2159  /**
2160   * Prints the styles queue in the HTML head on admin pages.
2161   *
2162   * @since 2.8.0
2163   *
2164   * @global bool $concatenate_scripts
2165   *
2166   * @return array
2167   */
2168  function print_admin_styles() {
2169      global $concatenate_scripts;
2170  
2171      $wp_styles = wp_styles();
2172  
2173      script_concat_settings();
2174      $wp_styles->do_concat = $concatenate_scripts;
2175      $wp_styles->do_items( false );
2176  
2177      /**
2178       * Filters whether to print the admin styles.
2179       *
2180       * @since 2.8.0
2181       *
2182       * @param bool $print Whether to print the admin styles. Default true.
2183       */
2184      if ( apply_filters( 'print_admin_styles', true ) ) {
2185          _print_styles();
2186      }
2187  
2188      $wp_styles->reset();
2189      return $wp_styles->done;
2190  }
2191  
2192  /**
2193   * Prints the styles that were queued too late for the HTML head.
2194   *
2195   * @since 3.3.0
2196   *
2197   * @global WP_Styles $wp_styles
2198   * @global bool      $concatenate_scripts
2199   *
2200   * @return array|void
2201   */
2202  function print_late_styles() {
2203      global $wp_styles, $concatenate_scripts;
2204  
2205      if ( ! ( $wp_styles instanceof WP_Styles ) ) {
2206          return;
2207      }
2208  
2209      script_concat_settings();
2210      $wp_styles->do_concat = $concatenate_scripts;
2211      $wp_styles->do_footer_items();
2212  
2213      /**
2214       * Filters whether to print the styles queued too late for the HTML head.
2215       *
2216       * @since 3.3.0
2217       *
2218       * @param bool $print Whether to print the 'late' styles. Default true.
2219       */
2220      if ( apply_filters( 'print_late_styles', true ) ) {
2221          _print_styles();
2222      }
2223  
2224      $wp_styles->reset();
2225      return $wp_styles->done;
2226  }
2227  
2228  /**
2229   * Prints styles (internal use only).
2230   *
2231   * @ignore
2232   * @since 3.3.0
2233   *
2234   * @global bool $compress_css
2235   */
2236  function _print_styles() {
2237      global $compress_css;
2238  
2239      $wp_styles = wp_styles();
2240  
2241      $zip = $compress_css ? 1 : 0;
2242      if ( $zip && defined( 'ENFORCE_GZIP' ) && ENFORCE_GZIP ) {
2243          $zip = 'gzip';
2244      }
2245  
2246      $concat    = trim( $wp_styles->concat, ', ' );
2247      $type_attr = current_theme_supports( 'html5', 'style' ) ? '' : ' type="text/css"';
2248  
2249      if ( $concat ) {
2250          $dir = $wp_styles->text_direction;
2251          $ver = $wp_styles->default_version;
2252  
2253          $concat       = str_split( $concat, 128 );
2254          $concatenated = '';
2255  
2256          foreach ( $concat as $key => $chunk ) {
2257              $concatenated .= "&load%5Bchunk_{$key}%5D={$chunk}";
2258          }
2259  
2260          $href = $wp_styles->base_url . "/wp-admin/load-styles.php?c={$zip}&dir={$dir}" . $concatenated . '&ver=' . $ver;
2261          echo "<link rel='stylesheet' href='" . esc_attr( $href ) . "'{$type_attr} media='all' />\n";
2262  
2263          if ( ! empty( $wp_styles->print_code ) ) {
2264              echo "<style{$type_attr}>\n";
2265              echo $wp_styles->print_code;
2266              echo "\n</style>\n";
2267          }
2268      }
2269  
2270      if ( ! empty( $wp_styles->print_html ) ) {
2271          echo $wp_styles->print_html;
2272      }
2273  }
2274  
2275  /**
2276   * Determines the concatenation and compression settings for scripts and styles.
2277   *
2278   * @since 2.8.0
2279   *
2280   * @global bool $concatenate_scripts
2281   * @global bool $compress_scripts
2282   * @global bool $compress_css
2283   */
2284  function script_concat_settings() {
2285      global $concatenate_scripts, $compress_scripts, $compress_css;
2286  
2287      $compressed_output = ( ini_get( 'zlib.output_compression' ) || 'ob_gzhandler' === ini_get( 'output_handler' ) );
2288  
2289      $can_compress_scripts = ! wp_installing() && get_site_option( 'can_compress_scripts' );
2290  
2291      if ( ! isset( $concatenate_scripts ) ) {
2292          $concatenate_scripts = defined( 'CONCATENATE_SCRIPTS' ) ? CONCATENATE_SCRIPTS : true;
2293          if ( ( ! is_admin() && ! did_action( 'login_init' ) ) || ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ) {
2294              $concatenate_scripts = false;
2295          }
2296      }
2297  
2298      if ( ! isset( $compress_scripts ) ) {
2299          $compress_scripts = defined( 'COMPRESS_SCRIPTS' ) ? COMPRESS_SCRIPTS : true;
2300          if ( $compress_scripts && ( ! $can_compress_scripts || $compressed_output ) ) {
2301              $compress_scripts = false;
2302          }
2303      }
2304  
2305      if ( ! isset( $compress_css ) ) {
2306          $compress_css = defined( 'COMPRESS_CSS' ) ? COMPRESS_CSS : true;
2307          if ( $compress_css && ( ! $can_compress_scripts || $compressed_output ) ) {
2308              $compress_css = false;
2309          }
2310      }
2311  }
2312  
2313  /**
2314   * Handles the enqueueing of block scripts and styles that are common to both
2315   * the editor and the front-end.
2316   *
2317   * @since 5.0.0
2318   */
2319  function wp_common_block_scripts_and_styles() {
2320      if ( is_admin() && ! wp_should_load_block_editor_scripts_and_styles() ) {
2321          return;
2322      }
2323  
2324      wp_enqueue_style( 'wp-block-library' );
2325  
2326      if ( current_theme_supports( 'wp-block-styles' ) ) {
2327          if ( wp_should_load_separate_core_block_assets() ) {
2328              $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? 'css' : 'min.css';
2329              $files  = glob( __DIR__ . "/blocks/**/theme.$suffix" );
2330              foreach ( $files as $path ) {
2331                  $block_name = basename( dirname( $path ) );
2332                  if ( is_rtl() && file_exists( __DIR__ . "/blocks/$block_name/theme-rtl.$suffix" ) ) {
2333                      $path = __DIR__ . "/blocks/$block_name/theme-rtl.$suffix";
2334                  }
2335                  wp_add_inline_style( "wp-block-{$block_name}", file_get_contents( $path ) );
2336              }
2337          } else {
2338              wp_enqueue_style( 'wp-block-library-theme' );
2339          }
2340      }
2341  
2342      /**
2343       * Fires after enqueuing block assets for both editor and front-end.
2344       *
2345       * Call `add_action` on any hook before 'wp_enqueue_scripts'.
2346       *
2347       * In the function call you supply, simply use `wp_enqueue_script` and
2348       * `wp_enqueue_style` to add your functionality to the Gutenberg editor.
2349       *
2350       * @since 5.0.0
2351       */
2352      do_action( 'enqueue_block_assets' );
2353  }
2354  
2355  /**
2356   * Enqueues the global styles defined via theme.json.
2357   *
2358   * @since 5.8.0
2359   */
2360  function wp_enqueue_global_styles() {
2361      $separate_assets  = wp_should_load_separate_core_block_assets();
2362      $is_block_theme   = wp_is_block_theme();
2363      $is_classic_theme = ! $is_block_theme;
2364  
2365      /*
2366       * Global styles should be printed in the head when loading all styles combined.
2367       * The footer should only be used to print global styles for classic themes with separate core assets enabled.
2368       *
2369       * See https://core.trac.wordpress.org/ticket/53494.
2370       */
2371      if (
2372          ( $is_block_theme && doing_action( 'wp_footer' ) ) ||
2373          ( $is_classic_theme && doing_action( 'wp_footer' ) && ! $separate_assets ) ||
2374          ( $is_classic_theme && doing_action( 'wp_enqueue_scripts' ) && $separate_assets )
2375      ) {
2376          return;
2377      }
2378  
2379      $stylesheet = wp_get_global_stylesheet();
2380  
2381      if ( empty( $stylesheet ) ) {
2382          return;
2383      }
2384  
2385      wp_register_style( 'global-styles', false, array(), true, true );
2386      wp_add_inline_style( 'global-styles', $stylesheet );
2387      wp_enqueue_style( 'global-styles' );
2388  }
2389  
2390  /**
2391   * Renders the SVG filters supplied by theme.json.
2392   *
2393   * Note that this doesn't render the per-block user-defined
2394   * filters which are handled by wp_render_duotone_support,
2395   * but it should be rendered before the filtered content
2396   * in the body to satisfy Safari's rendering quirks.
2397   *
2398   * @since 5.9.1
2399   */
2400  function wp_global_styles_render_svg_filters() {
2401      /*
2402       * When calling via the in_admin_header action, we only want to render the
2403       * SVGs on block editor pages.
2404       */
2405      if (
2406          is_admin() &&
2407          ! get_current_screen()->is_block_editor()
2408      ) {
2409          return;
2410      }
2411  
2412      $filters = wp_get_global_styles_svg_filters();
2413      if ( ! empty( $filters ) ) {
2414          echo $filters;
2415      }
2416  }
2417  
2418  /**
2419   * Checks if the editor scripts and styles for all registered block types
2420   * should be enqueued on the current screen.
2421   *
2422   * @since 5.6.0
2423   *
2424   * @global WP_Screen $current_screen WordPress current screen object.
2425   *
2426   * @return bool Whether scripts and styles should be enqueued.
2427   */
2428  function wp_should_load_block_editor_scripts_and_styles() {
2429      global $current_screen;
2430  
2431      $is_block_editor_screen = ( $current_screen instanceof WP_Screen ) && $current_screen->is_block_editor();
2432  
2433      /**
2434       * Filters the flag that decides whether or not block editor scripts and styles
2435       * are going to be enqueued on the current screen.
2436       *
2437       * @since 5.6.0
2438       *
2439       * @param bool $is_block_editor_screen Current value of the flag.
2440       */
2441      return apply_filters( 'should_load_block_editor_scripts_and_styles', $is_block_editor_screen );
2442  }
2443  
2444  /**
2445   * Checks whether separate styles should be loaded for core blocks on-render.
2446   *
2447   * When this function returns true, other functions ensure that core blocks
2448   * only load their assets on-render, and each block loads its own, individual
2449   * assets. Third-party blocks only load their assets when rendered.
2450   *
2451   * When this function returns false, all core block assets are loaded regardless
2452   * of whether they are rendered in a page or not, because they are all part of
2453   * the `block-library/style.css` file. Assets for third-party blocks are always
2454   * enqueued regardless of whether they are rendered or not.
2455   *
2456   * This only affects front end and not the block editor screens.
2457   *
2458   * @see wp_enqueue_registered_block_scripts_and_styles()
2459   * @see register_block_style_handle()
2460   *
2461   * @since 5.8.0
2462   *
2463   * @return bool Whether separate assets will be loaded.
2464   */
2465  function wp_should_load_separate_core_block_assets() {
2466      if ( is_admin() || is_feed() || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ) {
2467          return false;
2468      }
2469  
2470      /**
2471       * Filters whether block styles should be loaded separately.
2472       *
2473       * Returning false loads all core block assets, regardless of whether they are rendered
2474       * in a page or not. Returning true loads core block assets only when they are rendered.
2475       *
2476       * @since 5.8.0
2477       *
2478       * @param bool $load_separate_assets Whether separate assets will be loaded.
2479       *                                   Default false (all block assets are loaded, even when not used).
2480       */
2481      return apply_filters( 'should_load_separate_core_block_assets', false );
2482  }
2483  
2484  /**
2485   * Enqueues registered block scripts and styles, depending on current rendered
2486   * context (only enqueuing editor scripts while in context of the editor).
2487   *
2488   * @since 5.0.0
2489   *
2490   * @global WP_Screen $current_screen WordPress current screen object.
2491   */
2492  function wp_enqueue_registered_block_scripts_and_styles() {
2493      global $current_screen;
2494  
2495      if ( wp_should_load_separate_core_block_assets() ) {
2496          return;
2497      }
2498  
2499      $load_editor_scripts = is_admin() && wp_should_load_block_editor_scripts_and_styles();
2500  
2501      $block_registry = WP_Block_Type_Registry::get_instance();
2502      foreach ( $block_registry->get_all_registered() as $block_name => $block_type ) {
2503          // Front-end styles.
2504          if ( ! empty( $block_type->style ) ) {
2505              wp_enqueue_style( $block_type->style );
2506          }
2507  
2508          // Front-end script.
2509          if ( ! empty( $block_type->script ) ) {
2510              wp_enqueue_script( $block_type->script );
2511          }
2512  
2513          // Editor styles.
2514          if ( $load_editor_scripts && ! empty( $block_type->editor_style ) ) {
2515              wp_enqueue_style( $block_type->editor_style );
2516          }
2517  
2518          // Editor script.
2519          if ( $load_editor_scripts && ! empty( $block_type->editor_script ) ) {
2520              wp_enqueue_script( $block_type->editor_script );
2521          }
2522      }
2523  }
2524  
2525  /**
2526   * Function responsible for enqueuing the styles required for block styles functionality on the editor and on the frontend.
2527   *
2528   * @since 5.3.0
2529   *
2530   * @global WP_Styles $wp_styles
2531   */
2532  function enqueue_block_styles_assets() {
2533      global $wp_styles;
2534  
2535      $block_styles = WP_Block_Styles_Registry::get_instance()->get_all_registered();
2536  
2537      foreach ( $block_styles as $block_name => $styles ) {
2538          foreach ( $styles as $style_properties ) {
2539              if ( isset( $style_properties['style_handle'] ) ) {
2540  
2541                  // If the site loads separate styles per-block, enqueue the stylesheet on render.
2542                  if ( wp_should_load_separate_core_block_assets() ) {
2543                      add_filter(
2544                          'render_block',
2545                          function( $html, $block ) use ( $block_name, $style_properties ) {
2546                              if ( $block['blockName'] === $block_name ) {
2547                                  wp_enqueue_style( $style_properties['style_handle'] );
2548                              }
2549                              return $html;
2550                          },
2551                          10,
2552                          2
2553                      );
2554                  } else {
2555                      wp_enqueue_style( $style_properties['style_handle'] );
2556                  }
2557              }
2558              if ( isset( $style_properties['inline_style'] ) ) {
2559  
2560                  // Default to "wp-block-library".
2561                  $handle = 'wp-block-library';
2562  
2563                  // If the site loads separate styles per-block, check if the block has a stylesheet registered.
2564                  if ( wp_should_load_separate_core_block_assets() ) {
2565                      $block_stylesheet_handle = generate_block_asset_handle( $block_name, 'style' );
2566  
2567                      if ( isset( $wp_styles->registered[ $block_stylesheet_handle ] ) ) {
2568                          $handle = $block_stylesheet_handle;
2569                      }
2570                  }
2571  
2572                  // Add inline styles to the calculated handle.
2573                  wp_add_inline_style( $handle, $style_properties['inline_style'] );
2574              }
2575          }
2576      }
2577  }
2578  
2579  /**
2580   * Function responsible for enqueuing the assets required for block styles functionality on the editor.
2581   *
2582   * @since 5.3.0
2583   */
2584  function enqueue_editor_block_styles_assets() {
2585      $block_styles = WP_Block_Styles_Registry::get_instance()->get_all_registered();
2586  
2587      $register_script_lines = array( '( function() {' );
2588      foreach ( $block_styles as $block_name => $styles ) {
2589          foreach ( $styles as $style_properties ) {
2590              $block_style = array(
2591                  'name'  => $style_properties['name'],
2592                  'label' => $style_properties['label'],
2593              );
2594              if ( isset( $style_properties['is_default'] ) ) {
2595                  $block_style['isDefault'] = $style_properties['is_default'];
2596              }
2597              $register_script_lines[] = sprintf(
2598                  '    wp.blocks.registerBlockStyle( \'%s\', %s );',
2599                  $block_name,
2600                  wp_json_encode( $block_style )
2601              );
2602          }
2603      }
2604      $register_script_lines[] = '} )();';
2605      $inline_script           = implode( "\n", $register_script_lines );
2606  
2607      wp_register_script( 'wp-block-styles', false, array( 'wp-blocks' ), true, true );
2608      wp_add_inline_script( 'wp-block-styles', $inline_script );
2609      wp_enqueue_script( 'wp-block-styles' );
2610  }
2611  
2612  /**
2613   * Enqueues the assets required for the block directory within the block editor.
2614   *
2615   * @since 5.5.0
2616   */
2617  function wp_enqueue_editor_block_directory_assets() {
2618      wp_enqueue_script( 'wp-block-directory' );
2619      wp_enqueue_style( 'wp-block-directory' );
2620  }
2621  
2622  /**
2623   * Enqueues the assets required for the format library within the block editor.
2624   *
2625   * @since 5.8.0
2626   */
2627  function wp_enqueue_editor_format_library_assets() {
2628      wp_enqueue_script( 'wp-format-library' );
2629      wp_enqueue_style( 'wp-format-library' );
2630  }
2631  
2632  /**
2633   * Sanitizes an attributes array into an attributes string to be placed inside a `<script>` tag.
2634   *
2635   * Automatically injects type attribute if needed.
2636   * Used by {@see wp_get_script_tag()} and {@see wp_get_inline_script_tag()}.
2637   *
2638   * @since 5.7.0
2639   *
2640   * @param array $attributes Key-value pairs representing `<script>` tag attributes.
2641   * @return string String made of sanitized `<script>` tag attributes.
2642   */
2643  function wp_sanitize_script_attributes( $attributes ) {
2644      $html5_script_support = ! is_admin() && ! current_theme_supports( 'html5', 'script' );
2645      $attributes_string    = '';
2646  
2647      // If HTML5 script tag is supported, only the attribute name is added
2648      // to $attributes_string for entries with a boolean value, and that are true.
2649      foreach ( $attributes as $attribute_name => $attribute_value ) {
2650          if ( is_bool( $attribute_value ) ) {
2651              if ( $attribute_value ) {
2652                  $attributes_string .= $html5_script_support ? sprintf( ' %1$s="%2$s"', esc_attr( $attribute_name ), esc_attr( $attribute_name ) ) : ' ' . esc_attr( $attribute_name );
2653              }
2654          } else {
2655              $attributes_string .= sprintf( ' %1$s="%2$s"', esc_attr( $attribute_name ), esc_attr( $attribute_value ) );
2656          }
2657      }
2658  
2659      return $attributes_string;
2660  }
2661  
2662  /**
2663   * Formats `<script>` loader tags.
2664   *
2665   * It is possible to inject attributes in the `<script>` tag via the {@see 'wp_script_attributes'} filter.
2666   * Automatically injects type attribute if needed.
2667   *
2668   * @since 5.7.0
2669   *
2670   * @param array $attributes Key-value pairs representing `<script>` tag attributes.
2671   * @return string String containing `<script>` opening and closing tags.
2672   */
2673  function wp_get_script_tag( $attributes ) {
2674      if ( ! isset( $attributes['type'] ) && ! is_admin() && ! current_theme_supports( 'html5', 'script' ) ) {
2675          $attributes['type'] = 'text/javascript';
2676      }
2677      /**
2678       * Filters attributes to be added to a script tag.
2679       *
2680       * @since 5.7.0
2681       *
2682       * @param array $attributes Key-value pairs representing `<script>` tag attributes.
2683       *                          Only the attribute name is added to the `<script>` tag for
2684       *                          entries with a boolean value, and that are true.
2685       */
2686      $attributes = apply_filters( 'wp_script_attributes', $attributes );
2687  
2688      return sprintf( "<script%s></script>\n", wp_sanitize_script_attributes( $attributes ) );
2689  }
2690  
2691  /**
2692   * Prints formatted `<script>` loader tag.
2693   *
2694   * It is possible to inject attributes in the `<script>` tag via the  {@see 'wp_script_attributes'}  filter.
2695   * Automatically injects type attribute if needed.
2696   *
2697   * @since 5.7.0
2698   *
2699   * @param array $attributes Key-value pairs representing `<script>` tag attributes.
2700   */
2701  function wp_print_script_tag( $attributes ) {
2702      echo wp_get_script_tag( $attributes );
2703  }
2704  
2705  /**
2706   * Wraps inline JavaScript in `<script>` tag.
2707   *
2708   * It is possible to inject attributes in the `<script>` tag via the  {@see 'wp_script_attributes'}  filter.
2709   * Automatically injects type attribute if needed.
2710   *
2711   * @since 5.7.0
2712   *
2713   * @param string $javascript Inline JavaScript code.
2714   * @param array  $attributes Optional. Key-value pairs representing `<script>` tag attributes.
2715   * @return string String containing inline JavaScript code wrapped around `<script>` tag.
2716   */
2717  function wp_get_inline_script_tag( $javascript, $attributes = array() ) {
2718      if ( ! isset( $attributes['type'] ) && ! is_admin() && ! current_theme_supports( 'html5', 'script' ) ) {
2719          $attributes['type'] = 'text/javascript';
2720      }
2721      /**
2722       * Filters attributes to be added to a script tag.
2723       *
2724       * @since 5.7.0
2725       *
2726       * @param array  $attributes Key-value pairs representing `<script>` tag attributes.
2727       *                           Only the attribute name is added to the `<script>` tag for
2728       *                           entries with a boolean value, and that are true.
2729       * @param string $javascript Inline JavaScript code.
2730       */
2731      $attributes = apply_filters( 'wp_inline_script_attributes', $attributes, $javascript );
2732  
2733      $javascript = "\n" . trim( $javascript, "\n\r " ) . "\n";
2734  
2735      return sprintf( "<script%s>%s</script>\n", wp_sanitize_script_attributes( $attributes ), $javascript );
2736  }
2737  
2738  /**
2739   * Prints inline JavaScript wrapped in `<script>` tag.
2740   *
2741   * It is possible to inject attributes in the `<script>` tag via the  {@see 'wp_script_attributes'}  filter.
2742   * Automatically injects type attribute if needed.
2743   *
2744   * @since 5.7.0
2745   *
2746   * @param string $javascript Inline JavaScript code.
2747   * @param array  $attributes Optional. Key-value pairs representing `<script>` tag attributes.
2748   */
2749  function wp_print_inline_script_tag( $javascript, $attributes = array() ) {
2750      echo wp_get_inline_script_tag( $javascript, $attributes );
2751  }
2752  
2753  /**
2754   * Allows small styles to be inlined.
2755   *
2756   * This improves performance and sustainability, and is opt-in. Stylesheets can opt in
2757   * by adding `path` data using `wp_style_add_data`, and defining the file's absolute path:
2758   *
2759   *     wp_style_add_data( $style_handle, 'path', $file_path );
2760   *
2761   * @since 5.8.0
2762   *
2763   * @global WP_Styles $wp_styles
2764   */
2765  function wp_maybe_inline_styles() {
2766      global $wp_styles;
2767  
2768      $total_inline_limit = 20000;
2769      /**
2770       * The maximum size of inlined styles in bytes.
2771       *
2772       * @since 5.8.0
2773       *
2774       * @param int $total_inline_limit The file-size threshold, in bytes. Default 20000.
2775       */
2776      $total_inline_limit = apply_filters( 'styles_inline_size_limit', $total_inline_limit );
2777  
2778      $styles = array();
2779  
2780      // Build an array of styles that have a path defined.
2781      foreach ( $wp_styles->queue as $handle ) {
2782          if ( wp_styles()->get_data( $handle, 'path' ) && file_exists( $wp_styles->registered[ $handle ]->extra['path'] ) ) {
2783              $styles[] = array(
2784                  'handle' => $handle,
2785                  'src'    => $wp_styles->registered[ $handle ]->src,
2786                  'path'   => $wp_styles->registered[ $handle ]->extra['path'],
2787                  'size'   => filesize( $wp_styles->registered[ $handle ]->extra['path'] ),
2788              );
2789          }
2790      }
2791  
2792      if ( ! empty( $styles ) ) {
2793          // Reorder styles array based on size.
2794          usort(
2795              $styles,
2796              static function( $a, $b ) {
2797                  return ( $a['size'] <= $b['size'] ) ? -1 : 1;
2798              }
2799          );
2800  
2801          /*
2802           * The total inlined size.
2803           *
2804           * On each iteration of the loop, if a style gets added inline the value of this var increases
2805           * to reflect the total size of inlined styles.
2806           */
2807          $total_inline_size = 0;
2808  
2809          // Loop styles.
2810          foreach ( $styles as $style ) {
2811  
2812              // Size check. Since styles are ordered by size, we can break the loop.
2813              if ( $total_inline_size + $style['size'] > $total_inline_limit ) {
2814                  break;
2815              }
2816  
2817              // Get the styles if we don't already have them.
2818              $style['css'] = file_get_contents( $style['path'] );
2819  
2820              // Check if the style contains relative URLs that need to be modified.
2821              // URLs relative to the stylesheet's path should be converted to relative to the site's root.
2822              $style['css'] = _wp_normalize_relative_css_links( $style['css'], $style['src'] );
2823  
2824              // Set `src` to `false` and add styles inline.
2825              $wp_styles->registered[ $style['handle'] ]->src = false;
2826              if ( empty( $wp_styles->registered[ $style['handle'] ]->extra['after'] ) ) {
2827                  $wp_styles->registered[ $style['handle'] ]->extra['after'] = array();
2828              }
2829              array_unshift( $wp_styles->registered[ $style['handle'] ]->extra['after'], $style['css'] );
2830  
2831              // Add the styles size to the $total_inline_size var.
2832              $total_inline_size += (int) $style['size'];
2833          }
2834      }
2835  }
2836  
2837  /**
2838   * Makes URLs relative to the WordPress installation.
2839   *
2840   * @since 5.9.0
2841   * @access private
2842   *
2843   * @param string $css            The CSS to make URLs relative to the WordPress installation.
2844   * @param string $stylesheet_url The URL to the stylesheet.
2845   *
2846   * @return string The CSS with URLs made relative to the WordPress installation.
2847   */
2848  function _wp_normalize_relative_css_links( $css, $stylesheet_url ) {
2849      $has_src_results = preg_match_all( '#url\s*\(\s*[\'"]?\s*([^\'"\)]+)#', $css, $src_results );
2850      if ( $has_src_results ) {
2851          // Loop through the URLs to find relative ones.
2852          foreach ( $src_results[1] as $src_index => $src_result ) {
2853              // Skip if this is an absolute URL.
2854              if ( 0 === strpos( $src_result, 'http' ) || 0 === strpos( $src_result, '//' ) ) {
2855                  continue;
2856              }
2857  
2858              // Skip if the URL is an HTML ID.
2859              if ( str_starts_with( $src_result, '#' ) ) {
2860                  continue;
2861              }
2862  
2863              // Skip if the URL is a data URI.
2864              if ( str_starts_with( $src_result, 'data:' ) ) {
2865                  continue;
2866              }
2867  
2868              // Build the absolute URL.
2869              $absolute_url = dirname( $stylesheet_url ) . '/' . $src_result;
2870              $absolute_url = str_replace( '/./', '/', $absolute_url );
2871              // Convert to URL related to the site root.
2872              $relative_url = wp_make_link_relative( $absolute_url );
2873  
2874              // Replace the URL in the CSS.
2875              $css = str_replace(
2876                  $src_results[0][ $src_index ],
2877                  str_replace( $src_result, $relative_url, $src_results[0][ $src_index ] ),
2878                  $css
2879              );
2880          }
2881      }
2882  
2883      return $css;
2884  }
2885  
2886  /**
2887   * Function that enqueues the CSS Custom Properties coming from theme.json.
2888   *
2889   * @since 5.9.0
2890   */
2891  function wp_enqueue_global_styles_css_custom_properties() {
2892      wp_register_style( 'global-styles-css-custom-properties', false, array(), true, true );
2893      wp_add_inline_style( 'global-styles-css-custom-properties', wp_get_global_stylesheet( array( 'variables' ) ) );
2894      wp_enqueue_style( 'global-styles-css-custom-properties' );
2895  }
2896  
2897  /**
2898   * This function takes care of adding inline styles
2899   * in the proper place, depending on the theme in use.
2900   *
2901   * @since 5.9.1
2902   *
2903   * For block themes, it's loaded in the head.
2904   * For classic ones, it's loaded in the body
2905   * because the wp_head action happens before
2906   * the render_block.
2907   *
2908   * @link https://core.trac.wordpress.org/ticket/53494.
2909   *
2910   * @param string $style String containing the CSS styles to be added.
2911   */
2912  function wp_enqueue_block_support_styles( $style ) {
2913      $action_hook_name = 'wp_footer';
2914      if ( wp_is_block_theme() ) {
2915          $action_hook_name = 'wp_head';
2916      }
2917      add_action(
2918          $action_hook_name,
2919          static function () use ( $style ) {
2920              echo "<style>$style</style>\n";
2921          }
2922      );
2923  }
2924  
2925  /**
2926   * Enqueues a stylesheet for a specific block.
2927   *
2928   * If the theme has opted-in to separate-styles loading,
2929   * then the stylesheet will be enqueued on-render,
2930   * otherwise when the block inits.
2931   *
2932   * @since 5.9.0
2933   *
2934   * @param string $block_name The block-name, including namespace.
2935   * @param array  $args       An array of arguments [handle,src,deps,ver,media].
2936   */
2937  function wp_enqueue_block_style( $block_name, $args ) {
2938      $args = wp_parse_args(
2939          $args,
2940          array(
2941              'handle' => '',
2942              'src'    => '',
2943              'deps'   => array(),
2944              'ver'    => false,
2945              'media'  => 'all',
2946          )
2947      );
2948  
2949      /**
2950       * Callback function to register and enqueue styles.
2951       *
2952       * @param string $content When the callback is used for the render_block filter,
2953       *                        the content needs to be returned so the function parameter
2954       *                        is to ensure the content exists.
2955       * @return string Block content.
2956       */
2957      $callback = static function( $content ) use ( $args ) {
2958          // Register the stylesheet.
2959          if ( ! empty( $args['src'] ) ) {
2960              wp_register_style( $args['handle'], $args['src'], $args['deps'], $args['ver'], $args['media'] );
2961          }
2962  
2963          // Add `path` data if provided.
2964          if ( isset( $args['path'] ) ) {
2965              wp_style_add_data( $args['handle'], 'path', $args['path'] );
2966  
2967              // Get the RTL file path.
2968              $rtl_file_path = str_replace( '.css', '-rtl.css', $args['path'] );
2969  
2970              // Add RTL stylesheet.
2971              if ( file_exists( $rtl_file_path ) ) {
2972                  wp_style_add_data( $args['handle'], 'rtl', 'replace' );
2973  
2974                  if ( is_rtl() ) {
2975                      wp_style_add_data( $args['handle'], 'path', $rtl_file_path );
2976                  }
2977              }
2978          }
2979  
2980          // Enqueue the stylesheet.
2981          wp_enqueue_style( $args['handle'] );
2982  
2983          return $content;
2984      };
2985  
2986      $hook = did_action( 'wp_enqueue_scripts' ) ? 'wp_footer' : 'wp_enqueue_scripts';
2987      if ( wp_should_load_separate_core_block_assets() ) {
2988          /**
2989           * Callback function to register and enqueue styles.
2990           *
2991           * @param string $content The block content.
2992           * @param array  $block   The full block, including name and attributes.
2993           * @return string Block content.
2994           */
2995          $callback_separate = static function( $content, $block ) use ( $block_name, $callback ) {
2996              if ( ! empty( $block['blockName'] ) && $block_name === $block['blockName'] ) {
2997                  return $callback( $content );
2998              }
2999              return $content;
3000          };
3001  
3002          /*
3003           * The filter's callback here is an anonymous function because
3004           * using a named function in this case is not possible.
3005           *
3006           * The function cannot be unhooked, however, users are still able
3007           * to dequeue the stylesheets registered/enqueued by the callback
3008           * which is why in this case, using an anonymous function
3009           * was deemed acceptable.
3010           */
3011          add_filter( 'render_block', $callback_separate, 10, 2 );
3012          return;
3013      }
3014  
3015      /*
3016       * The filter's callback here is an anonymous function because
3017       * using a named function in this case is not possible.
3018       *
3019       * The function cannot be unhooked, however, users are still able
3020       * to dequeue the stylesheets registered/enqueued by the callback
3021       * which is why in this case, using an anonymous function
3022       * was deemed acceptable.
3023       */
3024      add_filter( $hook, $callback );
3025  
3026      // Enqueue assets in the editor.
3027      add_action( 'enqueue_block_assets', $callback );
3028  }
3029  
3030  /**
3031   * Runs the theme.json webfonts handler.
3032   *
3033   * Using `WP_Theme_JSON_Resolver`, it gets the fonts defined
3034   * in the `theme.json` for the current selection and style
3035   * variations, validates the font-face properties, generates
3036   * the '@font-face' style declarations, and then enqueues the
3037   * styles for both the editor and front-end.
3038   *
3039   * Design Notes:
3040   * This is not a public API, but rather an internal handler.
3041   * A future public Webfonts API will replace this stopgap code.
3042   *
3043   * This code design is intentional.
3044   *    a. It hides the inner-workings.
3045   *    b. It does not expose API ins or outs for consumption.
3046   *    c. It only works with a theme's `theme.json`.
3047   *
3048   * Why?
3049   *    a. To avoid backwards-compatibility issues when
3050   *       the Webfonts API is introduced in Core.
3051   *    b. To make `fontFace` declarations in `theme.json` work.
3052   *
3053   * @link  https://github.com/WordPress/gutenberg/issues/40472
3054   *
3055   * @since 6.0.0
3056   * @access private
3057   */
3058  function _wp_theme_json_webfonts_handler() {
3059      // Block themes are unavailable during installation.
3060      if ( wp_installing() ) {
3061          return;
3062      }
3063  
3064      // Webfonts to be processed.
3065      $registered_webfonts = array();
3066  
3067      /**
3068       * Gets the webfonts from theme.json.
3069       *
3070       * @since 6.0.0
3071       *
3072       * @return array Array of defined webfonts.
3073       */
3074      $fn_get_webfonts_from_theme_json = static function() {
3075          // Get settings from theme.json.
3076          $settings = WP_Theme_JSON_Resolver::get_merged_data()->get_settings();
3077  
3078          // If in the editor, add webfonts defined in variations.
3079          if ( is_admin() || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ) {
3080              $variations = WP_Theme_JSON_Resolver::get_style_variations();
3081              foreach ( $variations as $variation ) {
3082                  // Skip if fontFamilies are not defined in the variation.
3083                  if ( empty( $variation['settings']['typography']['fontFamilies'] ) ) {
3084                      continue;
3085                  }
3086  
3087                  // Initialize the array structure.
3088                  if ( empty( $settings['typography'] ) ) {
3089                      $settings['typography'] = array();
3090                  }
3091                  if ( empty( $settings['typography']['fontFamilies'] ) ) {
3092                      $settings['typography']['fontFamilies'] = array();
3093                  }
3094                  if ( empty( $settings['typography']['fontFamilies']['theme'] ) ) {
3095                      $settings['typography']['fontFamilies']['theme'] = array();
3096                  }
3097  
3098                  // Combine variations with settings. Remove duplicates.
3099                  $settings['typography']['fontFamilies']['theme'] = array_merge( $settings['typography']['fontFamilies']['theme'], $variation['settings']['typography']['fontFamilies']['theme'] );
3100                  $settings['typography']['fontFamilies']          = array_unique( $settings['typography']['fontFamilies'] );
3101              }
3102          }
3103  
3104          // Bail out early if there are no settings for webfonts.
3105          if ( empty( $settings['typography']['fontFamilies'] ) ) {
3106              return array();
3107          }
3108  
3109          $webfonts = array();
3110  
3111          // Look for fontFamilies.
3112          foreach ( $settings['typography']['fontFamilies'] as $font_families ) {
3113              foreach ( $font_families as $font_family ) {
3114  
3115                  // Skip if fontFace is not defined.
3116                  if ( empty( $font_family['fontFace'] ) ) {
3117                      continue;
3118                  }
3119  
3120                  // Skip if fontFace is not an array of webfonts.
3121                  if ( ! is_array( $font_family['fontFace'] ) ) {
3122                      continue;
3123                  }
3124  
3125                  $webfonts = array_merge( $webfonts, $font_family['fontFace'] );
3126              }
3127          }
3128  
3129          return $webfonts;
3130      };
3131  
3132      /**
3133       * Transforms each 'src' into an URI by replacing 'file:./'
3134       * placeholder from theme.json.
3135       *
3136       * The absolute path to the webfont file(s) cannot be defined in
3137       * theme.json. `file:./` is the placeholder which is replaced by
3138       * the theme's URL path to the theme's root.
3139       *
3140       * @since 6.0.0
3141       *
3142       * @param array $src Webfont file(s) `src`.
3143       * @return array Webfont's `src` in URI.
3144       */
3145      $fn_transform_src_into_uri = static function( array $src ) {
3146          foreach ( $src as $key => $url ) {
3147              // Tweak the URL to be relative to the theme root.
3148              if ( ! str_starts_with( $url, 'file:./' ) ) {
3149                  continue;
3150              }
3151  
3152              $src[ $key ] = get_theme_file_uri( str_replace( 'file:./', '', $url ) );
3153          }
3154  
3155          return $src;
3156      };
3157  
3158      /**
3159       * Converts the font-face properties (i.e. keys) into kebab-case.
3160       *
3161       * @since 6.0.0
3162       *
3163       * @param array $font_face Font face to convert.
3164       * @return array Font faces with each property in kebab-case format.
3165       */
3166      $fn_convert_keys_to_kebab_case = static function( array $font_face ) {
3167          foreach ( $font_face as $property => $value ) {
3168              $kebab_case               = _wp_to_kebab_case( $property );
3169              $font_face[ $kebab_case ] = $value;
3170              if ( $kebab_case !== $property ) {
3171                  unset( $font_face[ $property ] );
3172              }
3173          }
3174  
3175          return $font_face;
3176      };
3177  
3178      /**
3179       * Validates a webfont.
3180       *
3181       * @since 6.0.0
3182       *
3183       * @param array $webfont The webfont arguments.
3184       * @return array|false The validated webfont arguments, or false if the webfont is invalid.
3185       */
3186      $fn_validate_webfont = static function( $webfont ) {
3187          $webfont = wp_parse_args(
3188              $webfont,
3189              array(
3190                  'font-family'  => '',
3191                  'font-style'   => 'normal',
3192                  'font-weight'  => '400',
3193                  'font-display' => 'fallback',
3194                  'src'          => array(),
3195              )
3196          );
3197  
3198          // Check the font-family.
3199          if ( empty( $webfont['font-family'] ) || ! is_string( $webfont['font-family'] ) ) {
3200              trigger_error( __( 'Webfont font family must be a non-empty string.' ) );
3201  
3202              return false;
3203          }
3204  
3205          // Check that the `src` property is defined and a valid type.
3206          if ( empty( $webfont['src'] ) || ( ! is_string( $webfont['src'] ) && ! is_array( $webfont['src'] ) ) ) {
3207              trigger_error( __( 'Webfont src must be a non-empty string or an array of strings.' ) );
3208  
3209              return false;
3210          }
3211  
3212          // Validate the `src` property.
3213          foreach ( (array) $webfont['src'] as $src ) {
3214              if ( ! is_string( $src ) || '' === trim( $src ) ) {
3215                  trigger_error( __( 'Each webfont src must be a non-empty string.' ) );
3216  
3217                  return false;
3218              }
3219          }
3220  
3221          // Check the font-weight.
3222          if ( ! is_string( $webfont['font-weight'] ) && ! is_int( $webfont['font-weight'] ) ) {
3223              trigger_error( __( 'Webfont font weight must be a properly formatted string or integer.' ) );
3224  
3225              return false;
3226          }
3227  
3228          // Check the font-display.
3229          if ( ! in_array( $webfont['font-display'], array( 'auto', 'block', 'fallback', 'swap' ), true ) ) {
3230              $webfont['font-display'] = 'fallback';
3231          }
3232  
3233          $valid_props = array(
3234              'ascend-override',
3235              'descend-override',
3236              'font-display',
3237              'font-family',
3238              'font-stretch',
3239              'font-style',
3240              'font-weight',
3241              'font-variant',
3242              'font-feature-settings',
3243              'font-variation-settings',
3244              'line-gap-override',
3245              'size-adjust',
3246              'src',
3247              'unicode-range',
3248          );
3249  
3250          foreach ( $webfont as $prop => $value ) {
3251              if ( ! in_array( $prop, $valid_props, true ) ) {
3252                  unset( $webfont[ $prop ] );
3253              }
3254          }
3255  
3256          return $webfont;
3257      };
3258  
3259      /**
3260       * Registers webfonts declared in theme.json.
3261       *
3262       * @since 6.0.0
3263       *
3264       * @uses $registered_webfonts To access and update the registered webfonts registry (passed by reference).
3265       * @uses $fn_get_webfonts_from_theme_json To run the function that gets the webfonts from theme.json.
3266       * @uses $fn_convert_keys_to_kebab_case To run the function that converts keys into kebab-case.
3267       * @uses $fn_validate_webfont To run the function that validates each font-face (webfont) from theme.json.
3268       */
3269      $fn_register_webfonts = static function() use ( &$registered_webfonts, $fn_get_webfonts_from_theme_json, $fn_convert_keys_to_kebab_case, $fn_validate_webfont, $fn_transform_src_into_uri ) {
3270          $registered_webfonts = array();
3271  
3272          foreach ( $fn_get_webfonts_from_theme_json() as $webfont ) {
3273              if ( ! is_array( $webfont ) ) {
3274                  continue;
3275              }
3276  
3277              $webfont = $fn_convert_keys_to_kebab_case( $webfont );
3278  
3279              $webfont = $fn_validate_webfont( $webfont );
3280  
3281              $webfont['src'] = $fn_transform_src_into_uri( (array) $webfont['src'] );
3282  
3283              // Skip if not valid.
3284              if ( empty( $webfont ) ) {
3285                  continue;
3286              }
3287  
3288              $registered_webfonts[] = $webfont;
3289          }
3290      };
3291  
3292      /**
3293       * Orders 'src' items to optimize for browser support.
3294       *
3295       * @since 6.0.0
3296       *
3297       * @param array $webfont Webfont to process.
3298       * @return array Ordered `src` items.
3299       */
3300      $fn_order_src = static function( array $webfont ) {
3301          $src         = array();
3302          $src_ordered = array();
3303  
3304          foreach ( $webfont['src'] as $url ) {
3305              // Add data URIs first.
3306              if ( str_starts_with( trim( $url ), 'data:' ) ) {
3307                  $src_ordered[] = array(
3308                      'url'    => $url,
3309                      'format' => 'data',
3310                  );
3311                  continue;
3312              }
3313              $format         = pathinfo( $url, PATHINFO_EXTENSION );
3314              $src[ $format ] = $url;
3315          }
3316  
3317          // Add woff2.
3318          if ( ! empty( $src['woff2'] ) ) {
3319              $src_ordered[] = array(
3320                  'url'    => sanitize_url( $src['woff2'] ),
3321                  'format' => 'woff2',
3322              );
3323          }
3324  
3325          // Add woff.
3326          if ( ! empty( $src['woff'] ) ) {
3327              $src_ordered[] = array(
3328                  'url'    => sanitize_url( $src['woff'] ),
3329                  'format' => 'woff',
3330              );
3331          }
3332  
3333          // Add ttf.
3334          if ( ! empty( $src['ttf'] ) ) {
3335              $src_ordered[] = array(
3336                  'url'    => sanitize_url( $src['ttf'] ),
3337                  'format' => 'truetype',
3338              );
3339          }
3340  
3341          // Add eot.
3342          if ( ! empty( $src['eot'] ) ) {
3343              $src_ordered[] = array(
3344                  'url'    => sanitize_url( $src['eot'] ),
3345                  'format' => 'embedded-opentype',
3346              );
3347          }
3348  
3349          // Add otf.
3350          if ( ! empty( $src['otf'] ) ) {
3351              $src_ordered[] = array(
3352                  'url'    => sanitize_url( $src['otf'] ),
3353                  'format' => 'opentype',
3354              );
3355          }
3356          $webfont['src'] = $src_ordered;
3357  
3358          return $webfont;
3359      };
3360  
3361      /**
3362       * Compiles the 'src' into valid CSS.
3363       *
3364       * @since 6.0.0
3365       *
3366       * @param string $font_family Font family.
3367       * @param array  $value       Value to process.
3368       * @return string The CSS.
3369       */
3370      $fn_compile_src = static function( $font_family, array $value ) {
3371          $src = "local($font_family)";
3372  
3373          foreach ( $value as $item ) {
3374  
3375              if (
3376                  str_starts_with( $item['url'], site_url() ) ||
3377                  str_starts_with( $item['url'], home_url() )
3378              ) {
3379                  $item['url'] = wp_make_link_relative( $item['url'] );
3380              }
3381  
3382              $src .= ( 'data' === $item['format'] )
3383                  ? ", url({$item['url']})"
3384                  : ", url('{$item['url']}') format('{$item['format']}')";
3385          }
3386  
3387          return $src;
3388      };
3389  
3390      /**
3391       * Compiles the font variation settings.
3392       *
3393       * @since 6.0.0
3394       *
3395       * @param array $font_variation_settings Array of font variation settings.
3396       * @return string The CSS.
3397       */
3398      $fn_compile_variations = static function( array $font_variation_settings ) {
3399          $variations = '';
3400  
3401          foreach ( $font_variation_settings as $key => $value ) {
3402              $variations .= "$key $value";
3403          }
3404  
3405          return $variations;
3406      };
3407  
3408      /**
3409       * Builds the font-family's CSS.
3410       *
3411       * @since 6.0.0
3412       *
3413       * @uses $fn_compile_src To run the function that compiles the src.
3414       * @uses $fn_compile_variations To run the function that compiles the variations.
3415       *
3416       * @param array $webfont Webfont to process.
3417       * @return string This font-family's CSS.
3418       */
3419      $fn_build_font_face_css = static function( array $webfont ) use ( $fn_compile_src, $fn_compile_variations ) {
3420          $css = '';
3421  
3422          // Wrap font-family in quotes if it contains spaces.
3423          if (
3424              str_contains( $webfont['font-family'], ' ' ) &&
3425              ! str_contains( $webfont['font-family'], '"' ) &&
3426              ! str_contains( $webfont['font-family'], "'" )
3427          ) {
3428              $webfont['font-family'] = '"' . $webfont['font-family'] . '"';
3429          }
3430  
3431          foreach ( $webfont as $key => $value ) {
3432              /*
3433               * Skip "provider", since it's for internal API use,
3434               * and not a valid CSS property.
3435               */
3436              if ( 'provider' === $key ) {
3437                  continue;
3438              }
3439  
3440              // Compile the "src" parameter.
3441              if ( 'src' === $key ) {
3442                  $value = $fn_compile_src( $webfont['font-family'], $value );
3443              }
3444  
3445              // If font-variation-settings is an array, convert it to a string.
3446              if ( 'font-variation-settings' === $key && is_array( $value ) ) {
3447                  $value = $fn_compile_variations( $value );
3448              }
3449  
3450              if ( ! empty( $value ) ) {
3451                  $css .= "$key:$value;";
3452              }
3453          }
3454  
3455          return $css;
3456      };
3457  
3458      /**
3459       * Gets the '@font-face' CSS styles for locally-hosted font files.
3460       *
3461       * @since 6.0.0
3462       *
3463       * @uses $registered_webfonts To access and update the registered webfonts registry (passed by reference).
3464       * @uses $fn_order_src To run the function that orders the src.
3465       * @uses $fn_build_font_face_css To run the function that builds the font-face CSS.
3466       *
3467       * @return string The `@font-face` CSS.
3468       */
3469      $fn_get_css = static function() use ( &$registered_webfonts, $fn_order_src, $fn_build_font_face_css ) {
3470          $css = '';
3471  
3472          foreach ( $registered_webfonts as $webfont ) {
3473              // Order the webfont's `src` items to optimize for browser support.
3474              $webfont = $fn_order_src( $webfont );
3475  
3476              // Build the @font-face CSS for this webfont.
3477              $css .= '@font-face{' . $fn_build_font_face_css( $webfont ) . '}';
3478          }
3479  
3480          return $css;
3481      };
3482  
3483      /**
3484       * Generates and enqueues webfonts styles.
3485       *
3486       * @since 6.0.0
3487       *
3488       * @uses $fn_get_css To run the function that gets the CSS.
3489       */
3490      $fn_generate_and_enqueue_styles = static function() use ( $fn_get_css ) {
3491          // Generate the styles.
3492          $styles = $fn_get_css();
3493  
3494          // Bail out if there are no styles to enqueue.
3495          if ( '' === $styles ) {
3496              return;
3497          }
3498  
3499          // Enqueue the stylesheet.
3500          wp_register_style( 'wp-webfonts', '' );
3501          wp_enqueue_style( 'wp-webfonts' );
3502  
3503          // Add the styles to the stylesheet.
3504          wp_add_inline_style( 'wp-webfonts', $styles );
3505      };
3506  
3507      /**
3508       * Generates and enqueues editor styles.
3509       *
3510       * @since 6.0.0
3511       *
3512       * @uses $fn_get_css To run the function that gets the CSS.
3513       */
3514      $fn_generate_and_enqueue_editor_styles = static function() use ( $fn_get_css ) {
3515          // Generate the styles.
3516          $styles = $fn_get_css();
3517  
3518          // Bail out if there are no styles to enqueue.
3519          if ( '' === $styles ) {
3520              return;
3521          }
3522  
3523          wp_add_inline_style( 'wp-block-library', $styles );
3524      };
3525  
3526      add_action( 'wp_loaded', $fn_register_webfonts );
3527      add_action( 'wp_enqueue_scripts', $fn_generate_and_enqueue_styles );
3528      add_action( 'admin_init', $fn_generate_and_enqueue_editor_styles );
3529  }


Generated: Sat Apr 27 01:00:02 2024 Cross-referenced by PHPXref 0.7.1