PluginProbe
Gutenberg / 12.9.0
Gutenberg v12.9.0
23.9.1 23.9.0 23.8.0 23.7.2 23.7.1 23.7.0 23.6.1 23.6.2 23.6.0 23.5.3 23.5.2 23.5.1 23.5.0 23.4.0 23.3.2 23.3.1 23.3.0 23.2.0 23.2.1 23.2.2 23.1.1 23.1.0 23.0.1 12.6.0 7.4.0 All 402 releases
gutenberg / lib / client-assets.php

client-assets.php in Gutenberg 12.9.0, at lib/client-assets.php

552 lines 17.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Functions to register client-side assets (scripts and stylesheets) for the
4 * Gutenberg editor plugin.
5 *
6 * @package gutenberg
7 */
8
9 if ( ! defined( 'ABSPATH' ) ) {
10 die( 'Silence is golden.' );
11 }
12
13 /**
14 * Retrieves the root plugin path.
15 *
16 * @return string Root path to the gutenberg plugin.
17 *
18 * @since 0.1.0
19 */
20 function gutenberg_dir_path() {
21 return plugin_dir_path( __DIR__ );
22 }
23
24 /**
25 * Retrieves a URL to a file in the gutenberg plugin.
26 *
27 * @param string $path Relative path of the desired file.
28 *
29 * @return string Fully qualified URL pointing to the desired file.
30 *
31 * @since 0.1.0
32 */
33 function gutenberg_url( $path ) {
34 return plugins_url( $path, __DIR__ );
35 }
36
37 /**
38 * Registers a script according to `wp_register_script`. Honors this request by
39 * reassigning internal dependency properties of any script handle already
40 * registered by that name. It does not deregister the original script, to
41 * avoid losing inline scripts which may have been attached.
42 *
43 * @since 4.1.0
44 *
45 * @param WP_Scripts $scripts WP_Scripts instance.
46 * @param string $handle Name of the script. Should be unique.
47 * @param string $src Full URL of the script, or path of the script relative to the WordPress root directory.
48 * @param array $deps Optional. An array of registered script handles this script depends on. Default empty array.
49 * @param string|bool|null $ver Optional. String specifying script version number, if it has one, which is added to the URL
50 * as a query string for cache busting purposes. If version is set to false, a version
51 * number is automatically added equal to current installed WordPress version.
52 * If set to null, no version is added.
53 * @param bool $in_footer Optional. Whether to enqueue the script before </body> instead of in the <head>.
54 * Default 'false'.
55 */
56 function gutenberg_override_script( $scripts, $handle, $src, $deps = array(), $ver = false, $in_footer = false ) {
57 /*
58 * Force `wp-i18n` script to be registered in the <head> as a
59 * temporary workaround for https://meta.trac.wordpress.org/ticket/6195.
60 */
61 $in_footer = 'wp-i18n' === $handle ? false : $in_footer;
62
63 $script = $scripts->query( $handle, 'registered' );
64 if ( $script ) {
65 /*
66 * In many ways, this is a reimplementation of `wp_register_script` but
67 * bypassing consideration of whether a script by the given handle had
68 * already been registered.
69 */
70
71 // See: `_WP_Dependency::__construct` .
72 $script->src = $src;
73 $script->deps = $deps;
74 $script->ver = $ver;
75 $script->args = $in_footer ? 1 : null;
76 } else {
77 $scripts->add( $handle, $src, $deps, $ver, ( $in_footer ? 1 : null ) );
78 }
79
80 /*
81 * `WP_Dependencies::set_translations` will fall over on itself if setting
82 * translations on the `wp-i18n` handle, since it internally adds `wp-i18n`
83 * as a dependency of itself, exhausting memory. The same applies for the
84 * polyfill and hooks scripts, which are dependencies _of_ `wp-i18n`.
85 *
86 * See: https://core.trac.wordpress.org/ticket/46089
87 */
88 if ( ! in_array( $handle, array( 'wp-i18n', 'wp-polyfill', 'wp-hooks' ), true ) ) {
89 $scripts->set_translations( $handle, 'default' );
90 }
91
92 /*
93 * Wp-editor module is exposed as window.wp.editor.
94 * Problem: there is quite some code expecting window.wp.oldEditor object available under window.wp.editor.
95 * Solution: fuse the two objects together to maintain backward compatibility.
96 * For more context, see https://github.com/WordPress/gutenberg/issues/33203
97 */
98 if ( 'wp-editor' === $handle ) {
99 $scripts->add_inline_script(
100 'wp-editor',
101 'Object.assign( window.wp.editor, window.wp.oldEditor );',
102 'after'
103 );
104 }
105 }
106
107 /**
108 * Filters the default translation file load behavior to load the Gutenberg
109 * plugin translation file, if available.
110 *
111 * @param string|false $file Path to the translation file to load. False if
112 * there isn't one.
113 * @param string $handle Name of the script to register a translation
114 * domain to.
115 *
116 * @return string|false Filtered path to the Gutenberg translation file, if
117 * available.
118 */
119 function gutenberg_override_translation_file( $file, $handle ) {
120 if ( ! $file ) {
121 return $file;
122 }
123
124 // Ignore scripts whose handle does not have the "wp-" prefix.
125 if ( 'wp-' !== substr( $handle, 0, 3 ) ) {
126 return $file;
127 }
128
129 // Ignore scripts that are not found in the expected `build/` location.
130 $script_path = gutenberg_dir_path() . 'build/' . substr( $handle, 3 ) . '/index.min.js';
131 if ( ! file_exists( $script_path ) ) {
132 return $file;
133 }
134
135 /*
136 * The default file will be in the plugins language directory, omitting the
137 * domain since Gutenberg assigns the script translations as the default.
138 *
139 * Example: /www/wp-content/languages/plugins/de_DE-07d88e6a803e01276b9bfcc1203e862e.json
140 *
141 * The logic of `load_script_textdomain` is such that it will assume to
142 * search in the plugins language directory, since the assigned source of
143 * the overridden Gutenberg script originates in the plugins directory.
144 *
145 * The plugin translation files each begin with the slug of the plugin, so
146 * it's a simple matter of prepending the Gutenberg plugin slug.
147 */
148 $path_parts = pathinfo( $file );
149 $plugin_translation_file = (
150 $path_parts['dirname'] .
151 '/gutenberg-' .
152 $path_parts['basename']
153 );
154
155 return $plugin_translation_file;
156 }
157 add_filter( 'load_script_translation_file', 'gutenberg_override_translation_file', 10, 2 );
158
159 /**
160 * Registers a style according to `wp_register_style`. Honors this request by
161 * deregistering any style by the same handler before registration.
162 *
163 * @since 4.1.0
164 *
165 * @param WP_Styles $styles WP_Styles instance.
166 * @param string $handle Name of the stylesheet. Should be unique.
167 * @param string $src Full URL of the stylesheet, or path of the stylesheet relative to the WordPress root directory.
168 * @param array $deps Optional. An array of registered stylesheet handles this stylesheet depends on. Default empty array.
169 * @param string|bool|null $ver Optional. String specifying stylesheet version number, if it has one, which is added to the URL
170 * as a query string for cache busting purposes. If version is set to false, a version
171 * number is automatically added equal to current installed WordPress version.
172 * If set to null, no version is added.
173 * @param string $media Optional. The media for which this stylesheet has been defined.
174 * Default 'all'. Accepts media types like 'all', 'print' and 'screen', or media queries like
175 * '(orientation: portrait)' and '(max-width: 640px)'.
176 */
177 function gutenberg_override_style( $styles, $handle, $src, $deps = array(), $ver = false, $media = 'all' ) {
178 $style = $styles->query( $handle, 'registered' );
179 if ( $style ) {
180 $styles->remove( $handle );
181 }
182 $styles->add( $handle, $src, $deps, $ver, $media );
183 }
184
185 /**
186 * Registers vendor JavaScript files to be used as dependencies of the editor
187 * and plugins.
188 *
189 * This function is called from a script during the plugin build process, so it
190 * should not call any WordPress PHP functions.
191 *
192 * @since 0.1.0
193 *
194 * @param WP_Scripts $scripts WP_Scripts instance.
195 */
196 function gutenberg_register_vendor_scripts( $scripts ) {
197 $extension = SCRIPT_DEBUG ? '.js' : '.min.js';
198
199 gutenberg_override_script(
200 $scripts,
201 'react',
202 gutenberg_url( 'build/vendors/react' . $extension ),
203 // See https://github.com/pmmmwh/react-refresh-webpack-plugin/blob/main/docs/TROUBLESHOOTING.md#externalising-react.
204 SCRIPT_DEBUG ? array( 'wp-react-refresh-entry', 'wp-polyfill' ) : array( 'wp-polyfill' )
205 );
206 gutenberg_override_script(
207 $scripts,
208 'react-dom',
209 gutenberg_url( 'build/vendors/react-dom' . $extension ),
210 array( 'react' )
211 );
212 }
213 add_action( 'wp_default_scripts', 'gutenberg_register_vendor_scripts' );
214
215 /**
216 * Registers all the WordPress packages scripts that are in the standardized
217 * `build/` location.
218 *
219 * @since 4.5.0
220 *
221 * @param WP_Scripts $scripts WP_Scripts instance.
222 */
223 function gutenberg_register_packages_scripts( $scripts ) {
224 // When in production, use the plugin's version as the default asset version;
225 // else (for development or test) default to use the current time.
226 $default_version = defined( 'GUTENBERG_VERSION' ) && ! ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? GUTENBERG_VERSION : time();
227
228 foreach ( glob( gutenberg_dir_path() . 'build/*/index.min.js' ) as $path ) {
229 // Prefix `wp-` to package directory to get script handle.
230 // For example, `…/build/a11y/index.min.js` becomes `wp-a11y`.
231 $handle = 'wp-' . basename( dirname( $path ) );
232
233 // Replace extension with `.asset.php` to find the generated dependencies file.
234 $asset_file = substr( $path, 0, -( strlen( '.js' ) ) ) . '.asset.php';
235 $asset = file_exists( $asset_file )
236 ? require( $asset_file )
237 : null;
238 $dependencies = isset( $asset['dependencies'] ) ? $asset['dependencies'] : array();
239 $version = isset( $asset['version'] ) ? $asset['version'] : $default_version;
240
241 // Add dependencies that cannot be detected and generated by build tools.
242 switch ( $handle ) {
243 case 'wp-block-library':
244 array_push( $dependencies, 'editor' );
245 break;
246
247 case 'wp-edit-post':
248 array_push( $dependencies, 'media-models', 'media-views', 'postbox' );
249 break;
250
251 case 'wp-edit-site':
252 array_push( $dependencies, 'wp-dom-ready' );
253 break;
254 }
255
256 // Get the path from Gutenberg directory as expected by `gutenberg_url`.
257 $gutenberg_path = substr( $path, strlen( gutenberg_dir_path() ) );
258
259 gutenberg_override_script(
260 $scripts,
261 $handle,
262 gutenberg_url( $gutenberg_path ),
263 $dependencies,
264 $version,
265 true
266 );
267 }
268 }
269 add_action( 'wp_default_scripts', 'gutenberg_register_packages_scripts' );
270
271 /**
272 * Registers all the WordPress packages styles that are in the standardized
273 * `build/` location.
274 *
275 * @since 6.7.0
276
277 * @param WP_Styles $styles WP_Styles instance.
278 */
279 function gutenberg_register_packages_styles( $styles ) {
280 // When in production, use the plugin's version as the asset version;
281 // else (for development or test) default to use the current time.
282 $version = defined( 'GUTENBERG_VERSION' ) && ! ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? GUTENBERG_VERSION : time();
283
284 // Editor Styles.
285 gutenberg_override_style(
286 $styles,
287 'wp-block-editor',
288 gutenberg_url( 'build/block-editor/style.css' ),
289 array( 'wp-components' ),
290 $version
291 );
292 $styles->add_data( 'wp-block-editor', 'rtl', 'replace' );
293
294 gutenberg_override_style(
295 $styles,
296 'wp-editor',
297 gutenberg_url( 'build/editor/style.css' ),
298 array( 'wp-components', 'wp-block-editor', 'wp-nux', 'wp-reusable-blocks' ),
299 $version
300 );
301 $styles->add_data( 'wp-editor', 'rtl', 'replace' );
302
303 gutenberg_override_style(
304 $styles,
305 'wp-edit-post',
306 gutenberg_url( 'build/edit-post/style.css' ),
307 array( 'wp-components', 'wp-block-editor', 'wp-editor', 'wp-edit-blocks', 'wp-block-library', 'wp-nux' ),
308 $version
309 );
310 $styles->add_data( 'wp-edit-post', 'rtl', 'replace' );
311
312 gutenberg_override_style(
313 $styles,
314 'wp-components',
315 gutenberg_url( 'build/components/style.css' ),
316 array( 'dashicons' ),
317 $version
318 );
319 $styles->add_data( 'wp-components', 'rtl', 'replace' );
320
321 $block_library_filename = wp_should_load_separate_core_block_assets() ? 'common' : 'style';
322 gutenberg_override_style(
323 $styles,
324 'wp-block-library',
325 gutenberg_url( 'build/block-library/' . $block_library_filename . '.css' ),
326 array(),
327 $version
328 );
329 $styles->add_data( 'wp-block-library', 'rtl', 'replace' );
330 $styles->add_data( 'wp-block-library', 'path', gutenberg_dir_path() . 'build/block-library/' . $block_library_filename . '.css' );
331
332 gutenberg_override_style(
333 $styles,
334 'wp-format-library',
335 gutenberg_url( 'build/format-library/style.css' ),
336 array( 'wp-block-editor', 'wp-components' ),
337 $version
338 );
339 $styles->add_data( 'wp-format-library', 'rtl', 'replace' );
340
341 $wp_edit_blocks_dependencies = array(
342 'wp-components',
343 'wp-editor',
344 // This need to be added before the block library styles,
345 // The block library styles override the "reset" styles.
346 'wp-reset-editor-styles',
347 'wp-block-library',
348 'wp-reusable-blocks',
349 );
350
351 // Only load the default layout and margin styles for themes without theme.json file.
352 if ( ! WP_Theme_JSON_Resolver_Gutenberg::theme_has_support() ) {
353 $wp_edit_blocks_dependencies[] = 'wp-editor-classic-layout-styles';
354 }
355
356 global $editor_styles;
357 if ( ! is_array( $editor_styles ) || count( $editor_styles ) === 0 ) {
358 // Include opinionated block styles if no $editor_styles are declared, so the editor never appears broken.
359 $wp_edit_blocks_dependencies[] = 'wp-block-library-theme';
360 }
361
362 gutenberg_override_style(
363 $styles,
364 'wp-reset-editor-styles',
365 gutenberg_url( 'build/block-library/reset.css' ),
366 array( 'common', 'forms' ), // Make sure the reset is loaded after the default WP Admin styles.
367 $version
368 );
369 $styles->add_data( 'wp-reset-editor-styles', 'rtl', 'replace' );
370
371 gutenberg_override_style(
372 $styles,
373 'wp-editor-classic-layout-styles',
374 gutenberg_url( 'build/edit-post/classic.css' ),
375 array(),
376 $version
377 );
378 $styles->add_data( 'wp-editor-classic-layout-styles', 'rtl', 'replace' );
379
380 gutenberg_override_style(
381 $styles,
382 'wp-edit-blocks',
383 gutenberg_url( 'build/block-library/editor.css' ),
384 $wp_edit_blocks_dependencies,
385 $version
386 );
387 $styles->add_data( 'wp-edit-blocks', 'rtl', 'replace' );
388
389 gutenberg_override_style(
390 $styles,
391 'wp-nux',
392 gutenberg_url( 'build/nux/style.css' ),
393 array( 'wp-components' ),
394 $version
395 );
396 $styles->add_data( 'wp-nux', 'rtl', 'replace' );
397
398 gutenberg_override_style(
399 $styles,
400 'wp-block-library-theme',
401 gutenberg_url( 'build/block-library/theme.css' ),
402 array(),
403 $version
404 );
405 $styles->add_data( 'wp-block-library-theme', 'rtl', 'replace' );
406
407 gutenberg_override_style(
408 $styles,
409 'wp-list-reusable-blocks',
410 gutenberg_url( 'build/list-reusable-blocks/style.css' ),
411 array( 'wp-components' ),
412 $version
413 );
414 $styles->add_data( 'wp-list-reusable-block', 'rtl', 'replace' );
415
416 gutenberg_override_style(
417 $styles,
418 'wp-edit-navigation',
419 gutenberg_url( 'build/edit-navigation/style.css' ),
420 array( 'wp-components', 'wp-block-editor', 'wp-edit-blocks' ),
421 $version
422 );
423 $styles->add_data( 'wp-edit-navigation', 'rtl', 'replace' );
424
425 gutenberg_override_style(
426 $styles,
427 'wp-edit-site',
428 gutenberg_url( 'build/edit-site/style.css' ),
429 array( 'wp-components', 'wp-block-editor', 'wp-edit-blocks' ),
430 $version
431 );
432 $styles->add_data( 'wp-edit-site', 'rtl', 'replace' );
433
434 gutenberg_override_style(
435 $styles,
436 'wp-edit-widgets',
437 gutenberg_url( 'build/edit-widgets/style.css' ),
438 array( 'wp-components', 'wp-block-editor', 'wp-edit-blocks', 'wp-reusable-blocks', 'wp-widgets' ),
439 $version
440 );
441 $styles->add_data( 'wp-edit-widgets', 'rtl', 'replace' );
442
443 gutenberg_override_style(
444 $styles,
445 'wp-block-directory',
446 gutenberg_url( 'build/block-directory/style.css' ),
447 array( 'wp-block-editor', 'wp-components' ),
448 $version
449 );
450 $styles->add_data( 'wp-block-directory', 'rtl', 'replace' );
451
452 gutenberg_override_style(
453 $styles,
454 'wp-customize-widgets',
455 gutenberg_url( 'build/customize-widgets/style.css' ),
456 array( 'wp-components', 'wp-block-editor', 'wp-edit-blocks', 'wp-widgets' ),
457 $version
458 );
459 $styles->add_data( 'wp-customize-widgets', 'rtl', 'replace' );
460
461 gutenberg_override_style(
462 $styles,
463 'wp-reusable-blocks',
464 gutenberg_url( 'build/reusable-blocks/style.css' ),
465 array( 'wp-components' ),
466 $version
467 );
468 $styles->add_data( 'wp-reusable-block', 'rtl', 'replace' );
469
470 gutenberg_override_style(
471 $styles,
472 'wp-widgets',
473 gutenberg_url( 'build/widgets/style.css' ),
474 array( 'wp-components' )
475 );
476 $styles->add_data( 'wp-widgets', 'rtl', 'replace' );
477 }
478 add_action( 'wp_default_styles', 'gutenberg_register_packages_styles' );
479
480 /**
481 * Sets the editor styles to be consumed by JS.
482 */
483 function gutenberg_resolve_assets() {
484 global $pagenow;
485
486 $script_handles = array();
487 $style_handles = array(
488 'wp-block-editor',
489 'wp-block-library',
490 'wp-block-library-theme',
491 'wp-edit-blocks',
492 );
493
494 if ( 'widgets.php' === $pagenow || 'customize.php' === $pagenow ) {
495 $style_handles[] = 'wp-widgets';
496 $style_handles[] = 'wp-edit-widgets';
497 }
498
499 $block_registry = WP_Block_Type_Registry::get_instance();
500
501 foreach ( $block_registry->get_all_registered() as $block_type ) {
502 if ( ! empty( $block_type->style ) ) {
503 $style_handles[] = $block_type->style;
504 }
505
506 if ( ! empty( $block_type->editor_style ) ) {
507 $style_handles[] = $block_type->editor_style;
508 }
509
510 if ( ! empty( $block_type->script ) ) {
511 $script_handles[] = $block_type->script;
512 }
513 }
514
515 $style_handles = array_unique( $style_handles );
516 $done = wp_styles()->done;
517
518 ob_start();
519
520 // We do not need reset styles for the iframed editor.
521 wp_styles()->done = array( 'wp-reset-editor-styles' );
522 wp_styles()->do_items( $style_handles );
523 wp_styles()->done = $done;
524
525 $styles = ob_get_clean();
526
527 $script_handles = array_unique( $script_handles );
528 $done = wp_scripts()->done;
529
530 ob_start();
531
532 wp_scripts()->done = array();
533 wp_scripts()->do_items( $script_handles );
534 wp_scripts()->done = $done;
535
536 $scripts = ob_get_clean();
537
538 return array(
539 'styles' => $styles,
540 'scripts' => $scripts,
541 );
542 }
543
544 add_filter(
545 'block_editor_settings_all',
546 function( $settings ) {
547 // In the future we can allow WP Dependency handles to be passed.
548 $settings['__unstableResolvedAssets'] = gutenberg_resolve_assets();
549 return $settings;
550 }
551 );
552