[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

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


Generated : Thu Sep 18 08:20:05 2025 Cross-referenced by PHPXref