Make WordPress Core

source: trunk/src/wp-includes/script-loader.php

Last change on this file was 59896, checked in by johnbillion, 8 days ago

Docs: Various improvements to inline documentation.

See #62281

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