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