PluginProbe
Gutenberg / 8.3.0
Gutenberg v8.3.0
24.0.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 All 403 releases
← All changes | lib/client-assets.php +551 -256 23.2.28.3.0 View file →
@@ -1,8 +1,8 @@
1 1 <?php
2 2 /**
3 - * Functions to register client-side assets (scripts and stylesheets) specific
4 - * for the Gutenberg editor plugin.
3 + * Functions to register client-side assets (scripts and stylesheets) for the
4 + * Gutenberg editor plugin.
5 5 *
6 6 * @package gutenberg
7 7 */
8 8
@@ -12,30 +12,93 @@
12 12
13 13 /**
14 14 * Retrieves the root plugin path.
15 15 *
16 + * @return string Root path to the gutenberg plugin.
17 + *
16 18 * @since 0.1.0
17 - *
18 - * @return string Root path to the gutenberg plugin.
19 19 */
20 20 function gutenberg_dir_path() {
21 - return plugin_dir_path( __DIR__ );
21 + return plugin_dir_path( dirname( __FILE__ ) );
22 22 }
23 23
24 24 /**
25 25 * Retrieves a URL to a file in the gutenberg plugin.
26 26 *
27 - * @since 0.1.0
28 - *
29 27 * @param string $path Relative path of the desired file.
30 28 *
31 29 * @return string Fully qualified URL pointing to the desired file.
30 + *
31 + * @since 0.1.0
32 32 */
33 33 function gutenberg_url( $path ) {
34 - return plugins_url( $path, __DIR__ );
34 + return plugins_url( $path, dirname( __FILE__ ) );
35 35 }
36 36
37 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 + $script = $scripts->query( $handle, 'registered' );
58 + if ( $script ) {
59 + /*
60 + * In many ways, this is a reimplementation of `wp_register_script` but
61 + * bypassing consideration of whether a script by the given handle had
62 + * already been registered.
63 + */
64 +
65 + // See: `_WP_Dependency::__construct` .
66 + $script->src = $src;
67 + $script->deps = $deps;
68 + $script->ver = $ver;
69 + $script->args = $in_footer;
70 +
71 + /*
72 + * The script's `group` designation is an indication of whether it is
73 + * to be printed in the header or footer. The behavior here defers to
74 + * the arguments as passed. Specifically, group data is not assigned
75 + * for a script unless it is designated to be printed in the footer.
76 + */
77 +
78 + // See: `wp_register_script` .
79 + unset( $script->extra['group'] );
80 + if ( $in_footer ) {
81 + $script->add_data( 'group', 1 );
82 + }
83 + } else {
84 + $scripts->add( $handle, $src, $deps, $ver, $in_footer );
85 + }
86 +
87 + /*
88 + * `WP_Dependencies::set_translations` will fall over on itself if setting
89 + * translations on the `wp-i18n` handle, since it internally adds `wp-i18n`
90 + * as a dependency of itself, exhausting memory. The same applies for the
91 + * polyfill script, which is a dependency _of_ `wp-i18n`.
92 + *
93 + * See: https://core.trac.wordpress.org/ticket/46089
94 + */
95 + if ( 'wp-i18n' !== $handle && 'wp-polyfill' !== $handle ) {
96 + $scripts->set_translations( $handle, 'default' );
97 + }
98 +}
99 +
100 +/**
38 101 * Filters the default translation file load behavior to load the Gutenberg
39 102 * plugin translation file, if available.
40 103 *
41 104 * @param string|false $file Path to the translation file to load. False if
@@ -51,14 +114,14 @@
51 114 return $file;
52 115 }
53 116
54 117 // Ignore scripts whose handle does not have the "wp-" prefix.
55 - if ( ! str_starts_with( $handle, 'wp-' ) ) {
118 + if ( 'wp-' !== substr( $handle, 0, 3 ) ) {
56 119 return $file;
57 120 }
58 121
59 - // Ignore scripts that are not found in the expected `build/scripts/` location.
60 - $script_path = gutenberg_dir_path() . 'build/scripts/' . substr( $handle, 3 ) . '/index.min.js';
122 + // Ignore scripts that are not found in the expected `build/` location.
123 + $script_path = gutenberg_dir_path() . 'build/' . substr( $handle, 3 ) . '/index.js';
61 124 if ( ! file_exists( $script_path ) ) {
62 125 return $file;
63 126 }
64 127
@@ -86,369 +149,601 @@
86 149 }
87 150 add_filter( 'load_script_translation_file', 'gutenberg_override_translation_file', 10, 2 );
88 151
89 152 /**
90 - * Adds the 'editor' dependency to wp-block-library, required by the Classic block.
153 + * Filters the default labels for common post types to change the case style
154 + * from capitalized (e.g. "Featured Image") to sentence-style (e.g. "Featured
155 + * image").
91 156 *
92 - * @param WP_Scripts $scripts WP_Scripts instance.
157 + * See: https://github.com/WordPress/gutenberg/pull/18758
158 + *
159 + * @param object $labels Object with all the labels as member variables.
160 + *
161 + * @return object Object with all the labels, including overridden ones.
93 162 */
94 -function gutenberg_register_block_library_script_special_case( $scripts ) {
95 - $handle = 'wp-block-library';
96 - $script = $scripts->query( $handle, 'registered' );
97 - if ( ! in_array( 'editor', $script->deps, true ) ) {
98 - $script->deps[] = 'editor';
163 +function gutenberg_override_posttype_labels( $labels ) {
164 + $labels->featured_image = __( 'Featured image', 'gutenberg' );
165 + return $labels;
166 +}
167 +foreach ( array( 'post', 'page' ) as $post_type ) {
168 + add_filter( "post_type_labels_{$post_type}", 'gutenberg_override_posttype_labels' );
169 +}
170 +
171 +/**
172 + * Registers a style according to `wp_register_style`. Honors this request by
173 + * deregistering any style by the same handler before registration.
174 + *
175 + * @since 4.1.0
176 + *
177 + * @param WP_Styles $styles WP_Styles instance.
178 + * @param string $handle Name of the stylesheet. Should be unique.
179 + * @param string $src Full URL of the stylesheet, or path of the stylesheet relative to the WordPress root directory.
180 + * @param array $deps Optional. An array of registered stylesheet handles this stylesheet depends on. Default empty array.
181 + * @param string|bool|null $ver Optional. String specifying stylesheet version number, if it has one, which is added to the URL
182 + * as a query string for cache busting purposes. If version is set to false, a version
183 + * number is automatically added equal to current installed WordPress version.
184 + * If set to null, no version is added.
185 + * @param string $media Optional. The media for which this stylesheet has been defined.
186 + * Default 'all'. Accepts media types like 'all', 'print' and 'screen', or media queries like
187 + * '(orientation: portrait)' and '(max-width: 640px)'.
188 + */
189 +function gutenberg_override_style( $styles, $handle, $src, $deps = array(), $ver = false, $media = 'all' ) {
190 + $style = $styles->query( $handle, 'registered' );
191 + if ( $style ) {
192 + $styles->remove( $handle );
99 193 }
194 + $styles->add( $handle, $src, $deps, $ver, $media );
100 195 }
101 -add_action( 'wp_default_scripts', 'gutenberg_register_block_library_script_special_case', 11 );
102 196
103 197 /**
104 - * Registers WordPress package styles with complex requirements.
198 + * Registers vendor JavaScript files to be used as dependencies of the editor
199 + * and plugins.
105 200 *
106 - * Simple styles (main style.css with inferred dependencies) are auto-registered
107 - * via build/styles.php at default priority (10). This function runs at priority 15 to handle:
108 - * - Multiple style files per package (content.css, classic.css, etc.)
109 - * - Non-WordPress dependencies (dashicons, common, forms)
110 - * - Custom handles that don't match wp-{package} pattern
111 - * - Conditional dependencies based on theme/settings
112 - * - Dynamic filename logic
201 + * This function is called from a script during the plugin build process, so it
202 + * should not call any WordPress PHP functions.
113 203 *
114 - * These override calls will replace the auto-registered versions as needed.
204 + * @since 0.1.0
115 205 *
116 - * @since 6.7.0
206 + * @param WP_Scripts $scripts WP_Scripts instance.
207 + */
208 +function gutenberg_register_vendor_scripts( $scripts ) {
209 + $suffix = SCRIPT_DEBUG ? '' : '.min';
210 +
211 + /*
212 + * This script registration and the corresponding function should be removed
213 + * once the plugin is updated to support WordPress 5.4.0 and newer.
214 + *
215 + * See: `gutenberg_add_url_polyfill`
216 + */
217 + gutenberg_register_vendor_script(
218 + $scripts,
219 + 'wp-polyfill-url',
220 + 'https://unpkg.com/core-js-url-browser@3.6.4/url' . $suffix . '.js',
221 + array(),
222 + '3.6.4'
223 + );
224 +
225 + /*
226 + * This script registration and the corresponding function should be removed
227 + * removed once the plugin is updated to support WordPress 5.4.0 and newer.
228 + *
229 + * See: `gutenberg_add_dom_rect_polyfill`
230 + */
231 + gutenberg_register_vendor_script(
232 + $scripts,
233 + 'wp-polyfill-dom-rect',
234 + 'https://unpkg.com/polyfill-library@3.42.0/polyfills/DOMRect/polyfill.js',
235 + array(),
236 + '3.42.0'
237 + );
238 +}
239 +add_action( 'wp_default_scripts', 'gutenberg_register_vendor_scripts' );
240 +
241 +/**
242 + * Registers all the WordPress packages scripts that are in the standardized
243 + * `build/` location.
117 244 *
118 - * @global array $editor_styles
245 + * @since 4.5.0
119 246 *
120 - * @param WP_Styles $styles WP_Styles instance.
247 + * @param WP_Scripts $scripts WP_Scripts instance.
121 248 */
122 -function gutenberg_register_packages_styles( $styles ) {
123 - // When in production, use the plugin's version as the asset version;
124 - // else (for development or test) default to use the current time.
125 - $version = defined( 'GUTENBERG_VERSION' ) && ! SCRIPT_DEBUG ? GUTENBERG_VERSION : time();
126 - $suffix = SCRIPT_DEBUG ? '' : '.min';
249 +function gutenberg_register_packages_scripts( $scripts ) {
250 + foreach ( glob( gutenberg_dir_path() . 'build/*/index.js' ) as $path ) {
251 + // Prefix `wp-` to package directory to get script handle.
252 + // For example, `…/build/a11y/index.js` becomes `wp-a11y`.
253 + $handle = 'wp-' . basename( dirname( $path ) );
127 254
128 - // wp-components: add dashicons (icon font dependency)
129 - $styles->query( 'wp-components', 'registered' )->deps[] = 'dashicons';
255 + // Replace `.js` extension with `.asset.php` to find the generated dependencies file.
256 + $asset_file = substr( $path, 0, -3 ) . '.asset.php';
257 + $asset = file_exists( $asset_file )
258 + ? require( $asset_file )
259 + : null;
260 + $dependencies = isset( $asset['dependencies'] ) ? $asset['dependencies'] : array();
261 + $version = isset( $asset['version'] ) ? $asset['version'] : filemtime( $path );
130 262
131 - // wp-edit-post: add wp-edit-blocks (custom handle not auto-inferred)
132 - $styles->query( 'wp-edit-post', 'registered' )->deps[] = 'wp-edit-blocks';
263 + // Add dependencies that cannot be detected and generated by build tools.
264 + switch ( $handle ) {
265 + case 'wp-block-library':
266 + array_push( $dependencies, 'editor' );
267 + break;
133 268
134 - // wp-edit-site: add core WP styles and custom handles
135 - $edit_site_style = $styles->query( 'wp-edit-site', 'registered' );
136 - $edit_site_style->deps[] = 'common';
137 - $edit_site_style->deps[] = 'forms';
138 - $edit_site_style->deps[] = 'wp-block-library-editor';
269 + case 'wp-edit-post':
270 + array_push( $dependencies, 'media-models', 'media-views', 'postbox' );
271 + break;
139 272
140 - // wp-edit-widgets: add wp-edit-blocks (custom handle not auto-inferred)
141 - $styles->query( 'wp-edit-widgets', 'registered' )->deps[] = 'wp-edit-blocks';
273 + case 'wp-edit-site':
274 + array_push( $dependencies, 'wp-dom-ready' );
275 + break;
276 + }
142 277
143 - // wp-customize-widgets: add wp-edit-blocks (custom handle not auto-inferred)
144 - $styles->query( 'wp-customize-widgets', 'registered' )->deps[] = 'wp-edit-blocks';
278 + // Get the path from Gutenberg directory as expected by `gutenberg_url`.
279 + $gutenberg_path = substr( $path, strlen( gutenberg_dir_path() ) );
145 280
146 - // Register wp-base-styles and add it to the already registered wp-admin stylesheet
281 + gutenberg_override_script(
282 + $scripts,
283 + $handle,
284 + gutenberg_url( $gutenberg_path ),
285 + $dependencies,
286 + $version,
287 + true
288 + );
289 + }
290 +}
291 +add_action( 'wp_default_scripts', 'gutenberg_register_packages_scripts' );
292 +
293 +/**
294 + * Registers all the WordPress packages styles that are in the standardized
295 + * `build/` location.
296 + *
297 + * @since 6.7.0
298 +
299 + * @param WP_Styles $styles WP_Styles instance.
300 + */
301 +function gutenberg_register_packages_styles( $styles ) {
302 + // Editor Styles.
147 303 gutenberg_override_style(
148 304 $styles,
149 - 'wp-base-styles',
150 - gutenberg_url( 'build/styles/base-styles/admin-schemes' . $suffix . '.css' ),
151 - array(),
152 - $version
305 + 'wp-block-editor',
306 + gutenberg_url( 'build/block-editor/style.css' ),
307 + array( 'wp-components', 'wp-editor-font' ),
308 + filemtime( gutenberg_dir_path() . 'build/editor/style.css' )
153 309 );
154 - $styles->add_data( 'wp-base-styles', 'rtl', 'replace' );
155 - $styles->add_data( 'wp-base-styles', 'suffix', $suffix );
156 - $styles->add_data( 'wp-base-styles', 'path', gutenberg_dir_path() . 'build/styles/base-styles/admin-schemes' . $suffix . '.css' );
157 - $styles->query( 'wp-admin', 'registered' )->deps[] = 'wp-base-styles';
310 + $styles->add_data( 'wp-block-editor', 'rtl', 'replace' );
158 311
159 312 gutenberg_override_style(
160 313 $styles,
161 - 'wp-block-editor-content',
162 - gutenberg_url( 'build/styles/block-editor/content' . $suffix . '.css' ),
163 - array( 'wp-components' ),
164 - $version
314 + 'wp-editor',
315 + gutenberg_url( 'build/editor/style.css' ),
316 + array( 'wp-components', 'wp-block-editor', 'wp-nux' ),
317 + filemtime( gutenberg_dir_path() . 'build/editor/style.css' )
165 318 );
166 - $styles->add_data( 'wp-block-editor-content', 'rtl', 'replace' );
167 - $styles->add_data( 'wp-block-editor-content', 'suffix', $suffix );
319 + $styles->add_data( 'wp-editor', 'rtl', 'replace' );
168 320
169 - $block_library_filename = wp_should_load_separate_core_block_assets() ? 'common' : 'style';
170 321 gutenberg_override_style(
171 322 $styles,
323 + 'wp-edit-post',
324 + gutenberg_url( 'build/edit-post/style.css' ),
325 + array( 'wp-components', 'wp-block-editor', 'wp-editor', 'wp-edit-blocks', 'wp-block-library', 'wp-nux' ),
326 + filemtime( gutenberg_dir_path() . 'build/edit-post/style.css' )
327 + );
328 + $styles->add_data( 'wp-edit-post', 'rtl', 'replace' );
329 +
330 + gutenberg_override_style(
331 + $styles,
332 + 'wp-components',
333 + gutenberg_url( 'build/components/style.css' ),
334 + array(),
335 + filemtime( gutenberg_dir_path() . 'build/components/style.css' )
336 + );
337 + $styles->add_data( 'wp-components', 'rtl', 'replace' );
338 +
339 + gutenberg_override_style(
340 + $styles,
172 341 'wp-block-library',
173 - gutenberg_url( 'build/styles/block-library/' . $block_library_filename . $suffix . '.css' ),
342 + gutenberg_url( 'build/block-library/style.css' ),
174 343 array(),
175 - $version
344 + filemtime( gutenberg_dir_path() . 'build/block-library/style.css' )
176 345 );
177 346 $styles->add_data( 'wp-block-library', 'rtl', 'replace' );
178 - $styles->add_data( 'wp-block-library', 'suffix', $suffix );
179 - $styles->add_data( 'wp-block-library', 'path', gutenberg_dir_path() . 'build/styles/block-library/' . $block_library_filename . $suffix . '.css' );
180 347
181 - // Only add CONTENT styles here that should be enqueued in the iframe!
182 - $wp_edit_blocks_dependencies = array(
183 - 'wp-components',
184 - // This need to be added before the block library styles,
185 - // The block library styles override the "reset" styles.
186 - 'wp-reset-editor-styles',
187 - 'wp-block-library',
188 - // Until #37466, we can't specifically add them as editor styles yet,
189 - // so we must hard-code it here as a dependency.
190 - 'wp-block-editor-content',
191 - 'wp-base-styles',
348 + gutenberg_override_style(
349 + $styles,
350 + 'wp-format-library',
351 + gutenberg_url( 'build/format-library/style.css' ),
352 + array( 'wp-block-editor', 'wp-components' ),
353 + filemtime( gutenberg_dir_path() . 'build/format-library/style.css' )
192 354 );
355 + $styles->add_data( 'wp-format-library', 'rtl', 'replace' );
193 356
194 - // Only load the default layout and margin styles for themes without theme.json file.
195 - if ( ! wp_theme_has_theme_json() ) {
196 - $wp_edit_blocks_dependencies[] = 'wp-editor-classic-layout-styles';
197 - }
357 + gutenberg_override_style(
358 + $styles,
359 + 'wp-edit-blocks',
360 + gutenberg_url( 'build/block-library/editor.css' ),
361 + array(
362 + 'wp-components',
363 + 'wp-editor',
364 + 'wp-block-library',
365 + // Always include visual styles so the editor never appears broken.
366 + 'wp-block-library-theme',
367 + ),
368 + filemtime( gutenberg_dir_path() . 'build/block-library/editor.css' )
369 + );
370 + $styles->add_data( 'wp-edit-blocks', 'rtl', 'replace' );
198 371
199 - global $editor_styles;
200 - if ( current_theme_supports( 'wp-block-styles' ) && ( ! is_array( $editor_styles ) || count( $editor_styles ) === 0 ) ) {
201 - // Include opinionated block styles if the theme supports block styles and no $editor_styles are declared, so the editor never appears broken.
202 - $wp_edit_blocks_dependencies[] = 'wp-block-library-theme';
203 - }
372 + gutenberg_override_style(
373 + $styles,
374 + 'wp-nux',
375 + gutenberg_url( 'build/nux/style.css' ),
376 + array( 'wp-components' ),
377 + filemtime( gutenberg_dir_path() . 'build/nux/style.css' )
378 + );
379 + $styles->add_data( 'wp-nux', 'rtl', 'replace' );
204 380
205 381 gutenberg_override_style(
206 382 $styles,
207 - 'wp-reset-editor-styles',
208 - gutenberg_url( 'build/styles/block-library/reset' . $suffix . '.css' ),
209 - array( 'common', 'forms' ), // Make sure the reset is loaded after the default WP Admin styles.
210 - $version
383 + 'wp-block-library-theme',
384 + gutenberg_url( 'build/block-library/theme.css' ),
385 + array(),
386 + filemtime( gutenberg_dir_path() . 'build/block-library/theme.css' )
211 387 );
212 - $styles->add_data( 'wp-reset-editor-styles', 'rtl', 'replace' );
213 - $styles->add_data( 'wp-reset-editor-styles', 'suffix', $suffix );
388 + $styles->add_data( 'wp-block-library-theme', 'rtl', 'replace' );
214 389
215 390 gutenberg_override_style(
216 391 $styles,
217 - 'wp-editor-classic-layout-styles',
218 - gutenberg_url( 'build/styles/edit-post/classic' . $suffix . '.css' ),
219 - array(),
220 - $version
392 + 'wp-list-reusable-blocks',
393 + gutenberg_url( 'build/list-reusable-blocks/style.css' ),
394 + array( 'wp-components' ),
395 + filemtime( gutenberg_dir_path() . 'build/list-reusable-blocks/style.css' )
221 396 );
222 - $styles->add_data( 'wp-editor-classic-layout-styles', 'rtl', 'replace' );
223 - $styles->add_data( 'wp-editor-classic-layout-styles', 'suffix', $suffix );
397 + $styles->add_data( 'wp-list-reusable-block', 'rtl', 'replace' );
224 398
225 399 gutenberg_override_style(
226 400 $styles,
227 - 'wp-block-library-editor',
228 - gutenberg_url( 'build/styles/block-library/editor' . $suffix . '.css' ),
229 - array(),
230 - $version
401 + 'wp-edit-navigation',
402 + gutenberg_url( 'build/edit-navigation/style.css' ),
403 + array( 'wp-components', 'wp-block-editor', 'wp-edit-blocks' ),
404 + filemtime( gutenberg_dir_path() . 'build/edit-navigation/style.css' )
231 405 );
232 - $styles->add_data( 'wp-block-library-editor', 'rtl', 'replace' );
233 - $styles->add_data( 'wp-block-library-editor', 'suffix', $suffix );
406 + $styles->add_data( 'wp-edit-navigation', 'rtl', 'replace' );
234 407
235 408 gutenberg_override_style(
236 409 $styles,
237 - 'wp-edit-blocks',
238 - gutenberg_url( 'build/styles/block-library/editor' . $suffix . '.css' ),
239 - $wp_edit_blocks_dependencies,
240 - $version
410 + 'wp-edit-site',
411 + gutenberg_url( 'build/edit-site/style.css' ),
412 + array( 'wp-components', 'wp-block-editor', 'wp-edit-blocks' ),
413 + filemtime( gutenberg_dir_path() . 'build/edit-site/style.css' )
241 414 );
242 - $styles->add_data( 'wp-edit-blocks', 'rtl', 'replace' );
243 - $styles->add_data( 'wp-edit-blocks', 'suffix', $suffix );
415 + $styles->add_data( 'wp-edit-site', 'rtl', 'replace' );
244 416
245 417 gutenberg_override_style(
246 418 $styles,
247 - 'wp-block-library-theme',
248 - gutenberg_url( 'build/styles/block-library/theme' . $suffix . '.css' ),
249 - array(),
250 - $version
419 + 'wp-edit-widgets',
420 + gutenberg_url( 'build/edit-widgets/style.css' ),
421 + array( 'wp-components', 'wp-block-editor', 'wp-edit-blocks' ),
422 + filemtime( gutenberg_dir_path() . 'build/edit-widgets/style.css' )
251 423 );
252 - $styles->add_data( 'wp-block-library-theme', 'rtl', 'replace' );
253 - $styles->add_data( 'wp-block-library-theme', 'suffix', $suffix );
424 + $styles->add_data( 'wp-edit-widgets', 'rtl', 'replace' );
254 425
255 426 gutenberg_override_style(
256 427 $styles,
257 - 'classic-theme-styles',
258 - gutenberg_url( 'build/styles/block-library/classic' . $suffix . '.css' ),
259 - array(),
260 - $version
428 + 'wp-block-directory',
429 + gutenberg_url( 'build/block-directory/style.css' ),
430 + array( 'wp-block-editor', 'wp-components' ),
431 + filemtime( gutenberg_dir_path() . 'build/block-directory/style.css' )
261 432 );
262 - $styles->add_data( 'classic-theme-styles', 'rtl', 'replace' );
263 - $styles->add_data( 'classic-theme-styles', 'suffix', $suffix );
264 - $styles->add_data( 'classic-theme-styles', 'path', gutenberg_dir_path() . 'build/styles/block-library/classic' . $suffix . '.css' );
433 + $styles->add_data( 'wp-block-directory', 'rtl', 'replace' );
265 434 }
266 -add_action( 'wp_default_styles', 'gutenberg_register_packages_styles', 15 );
435 +add_action( 'wp_default_styles', 'gutenberg_register_packages_styles' );
267 436
268 437 /**
269 - * Fetches, processes and compiles stored core styles, then combines and renders them to the page.
270 - * Styles are stored via the Style Engine API.
438 + * Registers common scripts and styles to be used as dependencies of the editor
439 + * and plugins.
271 440 *
272 - * This hook also exists, and should be backported to Core in future versions.
273 - * However, it is envisaged that Gutenberg will continue to use the Style Engine's `gutenberg_*` functions and `_Gutenberg` classes to aid continuous development.
441 + * @since 0.1.0
442 + */
443 +function gutenberg_enqueue_block_editor_assets() {
444 + if ( defined( 'GUTENBERG_LIVE_RELOAD' ) && GUTENBERG_LIVE_RELOAD ) {
445 + $live_reload_url = ( GUTENBERG_LIVE_RELOAD === true ) ? 'http://localhost:35729/livereload.js' : GUTENBERG_LIVE_RELOAD;
446 +
447 + wp_enqueue_script(
448 + 'gutenberg-live-reload',
449 + $live_reload_url
450 + );
451 + }
452 +}
453 +add_action( 'enqueue_block_editor_assets', 'gutenberg_enqueue_block_editor_assets' );
454 +
455 +/**
456 + * Retrieves a unique and reasonably short and human-friendly filename for a
457 + * vendor script based on a URL and the script handle.
274 458 *
275 - * @since 6.1
459 + * @param string $handle The name of the script.
460 + * @param string $src Full URL of the external script.
276 461 *
277 - * @link https://developer.wordpress.org/block-editor/reference-guides/packages/packages-style-engine/
462 + * @return string Script filename suitable for local caching.
278 463 *
279 - * @param array $options {
280 - * Optional. An array of options to pass to gutenberg_style_engine_get_stylesheet_from_context(). Default empty array.
464 + * @since 0.1.0
465 + */
466 +function gutenberg_vendor_script_filename( $handle, $src ) {
467 + $filename = basename( $src );
468 + $match = preg_match(
469 + '/^'
470 + . '(?P<ignore>.*?)'
471 + . '(?P<suffix>\.min)?'
472 + . '(?P<extension>\.js)'
473 + . '(?P<extra>.*)'
474 + . '$/',
475 + $filename,
476 + $filename_pieces
477 + );
478 +
479 + $prefix = $handle;
480 + $suffix = $match ? $filename_pieces['suffix'] : '';
481 + $hash = substr( md5( $src ), 0, 8 );
482 +
483 + return "${prefix}${suffix}.${hash}.js";
484 +}
485 +
486 +/**
487 + * Registers a vendor script from a URL, preferring a locally cached version if
488 + * possible, or downloading it if the cached version is unavailable or
489 + * outdated.
281 490 *
282 - * @type bool $optimize Whether to optimize the CSS output, e.g., combine rules. Default is `false`.
283 - * @type bool $prettify Whether to add new lines and indents to output. Default is the test of whether the global constant `SCRIPT_DEBUG` is defined.
284 - * }
491 + * @param WP_Scripts $scripts WP_Scripts instance.
492 + * @param string $handle Name of the script.
493 + * @param string $src Full URL of the external script.
494 + * @param array $deps Optional. An array of registered script handles this
495 + * script depends on.
496 + * @param string|bool|null $ver Optional. String specifying script version number, if it has one, which is added to the URL
497 + * as a query string for cache busting purposes. If version is set to false, a version
498 + * number is automatically added equal to current installed WordPress version.
499 + * If set to null, no version is added.
500 + * @param bool $in_footer Optional. Whether to enqueue the script before </body> instead of in the <head>.
501 + * Default 'false'.
285 502 *
286 - * @return void
503 + * @since 0.1.0
287 504 */
288 -function gutenberg_enqueue_stored_styles( $options = array() ) {
289 - $is_block_theme = wp_is_block_theme();
290 - $is_classic_theme = ! $is_block_theme;
291 -
292 - /*
293 - * For block themes, print stored styles in the header.
294 - * For classic themes, in the footer.
295 - */
296 - if (
297 - ( $is_block_theme && doing_action( 'wp_footer' ) ) ||
298 - ( $is_classic_theme && doing_action( 'wp_enqueue_scripts' ) )
299 - ) {
505 +function gutenberg_register_vendor_script( $scripts, $handle, $src, $deps = array(), $ver = null, $in_footer = false ) {
506 + if ( defined( 'GUTENBERG_LOAD_VENDOR_SCRIPTS' ) && ! GUTENBERG_LOAD_VENDOR_SCRIPTS ) {
300 507 return;
301 508 }
302 509
303 - $core_styles_keys = array( 'block-supports' );
304 - $compiled_core_stylesheet = '';
305 - $style_tag_id = 'core';
306 - foreach ( $core_styles_keys as $style_key ) {
307 - // Adds comment if code is prettified to identify core styles sections in debugging.
308 - $should_prettify = isset( $options['prettify'] ) ? true === $options['prettify'] : SCRIPT_DEBUG;
309 - if ( $should_prettify ) {
310 - $compiled_core_stylesheet .= "/**\n * Core styles: $style_key\n */\n";
311 - }
312 - // Chains core store ids to signify what the styles contain.
313 - $style_tag_id .= '-' . $style_key;
314 - $compiled_core_stylesheet .= gutenberg_style_engine_get_stylesheet_from_context( $style_key, $options );
315 - }
510 + $filename = gutenberg_vendor_script_filename( $handle, $src );
316 511
317 - // Combines Core styles.
318 - if ( ! empty( $compiled_core_stylesheet ) ) {
319 - wp_register_style( $style_tag_id, false, array(), true );
320 - wp_add_inline_style( $style_tag_id, $compiled_core_stylesheet );
321 - wp_enqueue_style( $style_tag_id );
512 + if ( defined( 'GUTENBERG_LIST_VENDOR_ASSETS' ) && GUTENBERG_LIST_VENDOR_ASSETS ) {
513 + echo "$src|$filename\n";
514 + return;
322 515 }
323 516
324 - // If there are any other stores registered by themes etc., print them out.
325 - $additional_stores = WP_Style_Engine_CSS_Rules_Store_Gutenberg::get_stores();
517 + $full_path = gutenberg_dir_path() . 'vendor/' . $filename;
326 518
327 - /*
328 - * Since the corresponding action hook in Core is removed below,
329 - * this function should still honour any styles stored using the Core Style Engine store.
330 - */
331 - if ( class_exists( 'WP_Style_Engine_CSS_Rules_Store' ) ) {
332 - $additional_stores = array_merge( $additional_stores, WP_Style_Engine_CSS_Rules_Store::get_stores() );
333 - }
519 + $needs_fetch = (
520 + defined( 'GUTENBERG_DEVELOPMENT_MODE' ) && GUTENBERG_DEVELOPMENT_MODE && (
521 + ! file_exists( $full_path ) ||
522 + time() - filemtime( $full_path ) >= DAY_IN_SECONDS
523 + )
524 + );
334 525
335 - foreach ( array_keys( $additional_stores ) as $store_name ) {
336 - if ( in_array( $store_name, $core_styles_keys, true ) ) {
337 - continue;
526 + if ( $needs_fetch ) {
527 + // Determine whether we can write to this file. If not, don't waste
528 + // time doing a network request.
529 + // @codingStandardsIgnoreStart
530 + $f = @fopen( $full_path, 'a' );
531 + // @codingStandardsIgnoreEnd
532 + if ( ! $f ) {
533 + // Failed to open the file for writing, probably due to server
534 + // permissions. Enqueue the script directly from the URL instead.
535 + gutenberg_override_script( $scripts, $handle, $src, $deps, $ver, $in_footer );
536 + return;
338 537 }
339 - $styles = gutenberg_style_engine_get_stylesheet_from_context( $store_name, $options );
340 - if ( ! empty( $styles ) ) {
341 - $key = "wp-style-engine-$store_name";
342 - wp_register_style( $key, false, array(), true );
343 - wp_add_inline_style( $key, $styles );
344 - wp_enqueue_style( $key );
538 + fclose( $f );
539 + $response = wp_remote_get( $src );
540 + if ( wp_remote_retrieve_response_code( $response ) === 200 ) {
541 + $f = fopen( $full_path, 'w' );
542 + fwrite( $f, wp_remote_retrieve_body( $response ) );
543 + fclose( $f );
544 + } elseif ( ! filesize( $full_path ) ) {
545 + // The request failed. If the file is already cached, continue to
546 + // use this file. If not, then unlink the 0 byte file, and enqueue
547 + // the script directly from the URL.
548 + gutenberg_override_script( $scripts, $handle, $src, $deps, $ver, $in_footer );
549 + unlink( $full_path );
550 + return;
345 551 }
346 552 }
553 + gutenberg_override_script(
554 + $scripts,
555 + $handle,
556 + gutenberg_url( 'vendor/' . $filename ),
557 + $deps,
558 + $ver,
559 + $in_footer
560 + );
347 561 }
348 562
349 563 /**
350 - * Registers vendor JavaScript files to be used as dependencies of the editor
351 - * and plugins.
564 + * Extends block editor settings to include Gutenberg's `editor-styles.css` as
565 + * taking precedent those styles shipped with core.
352 566 *
353 - * This function is called from a script during the plugin build process, so it
354 - * should not call any WordPress PHP functions.
567 + * @param array $settings Default editor settings.
355 568 *
356 - * @since 13.0
357 - *
358 - * @param WP_Scripts $scripts WP_Scripts instance.
569 + * @return array Filtered editor settings.
359 570 */
360 -function gutenberg_register_vendor_scripts( $scripts ) {
361 - $extension = SCRIPT_DEBUG ? '.js' : '.min.js';
362 - $vendors_dir = gutenberg_dir_path() . 'build/scripts/vendors/';
571 +function gutenberg_extend_block_editor_styles( $settings ) {
572 + $editor_styles_file = gutenberg_dir_path() . 'build/editor/editor-styles.css';
363 573
364 - $vendor_handles = array( 'react', 'react-dom', 'react-jsx-runtime' );
574 + /*
575 + * If, for whatever reason, the built editor styles do not exist, avoid
576 + * override and fall back to the default.
577 + */
578 + if ( ! file_exists( $editor_styles_file ) ) {
579 + return $settings;
580 + }
365 581
366 - foreach ( $vendor_handles as $handle ) {
367 - $asset_file = $vendors_dir . $handle . '.min.asset.php';
368 - $asset = file_exists( $asset_file ) ? require $asset_file : array();
369 - $dependencies = $asset['dependencies'] ?? array();
370 - $version = $asset['version'] ?? '0';
582 + if ( empty( $settings['styles'] ) ) {
583 + $settings['styles'] = array();
584 + } else {
585 + /*
586 + * The styles setting is an array of CSS strings, so there is no direct
587 + * way to find the default styles. To maximize stability, load (again)
588 + * the default styles from disk and find its place in the array.
589 + *
590 + * See: https://github.com/WordPress/wordpress-develop/blob/5.0.3/src/wp-admin/edit-form-blocks.php#L168-L175
591 + */
371 592
372 - gutenberg_override_script(
373 - $scripts,
374 - $handle,
375 - gutenberg_url( 'build/scripts/vendors/' . $handle . $extension ),
376 - $dependencies,
377 - $version
593 + $default_styles = file_get_contents(
594 + ABSPATH . WPINC . '/css/dist/editor/editor-styles.css'
378 595 );
596 +
597 + /*
598 + * Iterate backwards from the end of the array since the preferred
599 + * insertion point in case not found is prepended as first entry.
600 + */
601 + for ( $i = count( $settings['styles'] ) - 1; $i >= 0; $i-- ) {
602 + if ( isset( $settings['styles'][ $i ]['css'] ) &&
603 + $default_styles === $settings['styles'][ $i ]['css'] ) {
604 + break;
605 + }
606 + }
379 607 }
380 608
381 - // WordPress Core in `wp_register_development_scripts` sets `wp-react-refresh-entry`
382 - // as a dependency to `react` when `SCRIPT_DEBUG` is true. Preserve that here.
383 - if ( SCRIPT_DEBUG ) {
384 - $react = $scripts->query( 'react', 'registered' );
385 - if ( $react && ! in_array( 'wp-react-refresh-entry', $react->deps, true ) ) {
386 - $react->deps[] = 'wp-react-refresh-entry';
387 - }
609 + $editor_styles = array(
610 + 'css' => file_get_contents( $editor_styles_file ),
611 + );
612 +
613 + // Substitute default styles if found. Otherwise, prepend to setting array.
614 + if ( isset( $i ) && $i >= 0 ) {
615 + $settings['styles'][ $i ] = $editor_styles;
616 + } else {
617 + array_unshift( $settings['styles'], $editor_styles );
388 618 }
619 +
620 + return $settings;
389 621 }
390 -add_action( 'wp_default_scripts', 'gutenberg_register_vendor_scripts' );
622 +add_filter( 'block_editor_settings', 'gutenberg_extend_block_editor_styles' );
391 623
392 624 /**
393 - * Registers or re-registers Gutenberg Script Modules.
625 + * Load a block pattern by name.
394 626 *
395 - * Script modules that are registered by Core will be re-registered by Gutenberg.
627 + * @param string $name Block Pattern File name.
396 628 *
397 - * @since 19.3.0
629 + * @return array Block Pattern Array.
398 630 */
399 -function gutenberg_define_interactivity_modules_support() {
400 - // Load the auto-generated module registry.
401 - $modules_registry_file = gutenberg_dir_path() . 'build/modules/index.php';
402 - if ( ! file_exists( $modules_registry_file ) ) {
403 - return;
631 +function gutenberg_load_block_pattern( $name ) {
632 + return require( __DIR__ . '/patterns/' . $name . '.php' );
633 +}
634 +
635 +/**
636 + * Extends block editor settings to include a list of default patterns.
637 + *
638 + * @param array $settings Default editor settings.
639 + *
640 + * @return array Filtered editor settings.
641 + */
642 +function gutenberg_extend_settings_block_patterns( $settings ) {
643 + if ( empty( $settings['__experimentalBlockPatterns'] ) ) {
644 + $settings['__experimentalBlockPatterns'] = array();
404 645 }
405 646
406 - $modules = require $modules_registry_file;
647 + $settings['__experimentalBlockPatterns'] = array_merge(
648 + WP_Block_Patterns_Registry::get_instance()->get_all_registered(),
649 + $settings['__experimentalBlockPatterns']
650 + );
407 651
408 - // Add client navigation support to block library modules.
409 - foreach ( $modules as $module ) {
410 - if ( str_starts_with( $module['id'], '@wordpress/block-library' ) && method_exists( 'WP_Interactivity_API', 'add_client_navigation_support_to_script_module' ) ) {
411 - wp_interactivity()->add_client_navigation_support_to_script_module( $module['id'] );
412 - }
652 + if ( empty( $settings['__experimentalBlockPatternCategories'] ) ) {
653 + $settings['__experimentalBlockPatternCategories'] = array();
413 654 }
655 +
656 + $settings['__experimentalBlockPatternCategories'] = array_merge(
657 + WP_Block_Pattern_Categories_Registry::get_instance()->get_all_registered(),
658 + $settings['__experimentalBlockPatternCategories']
659 + );
660 +
661 + return $settings;
414 662 }
415 -remove_action( 'wp_default_scripts', 'wp_define_interactivity_modules_support' );
416 -add_action( 'wp_default_scripts', 'gutenberg_define_interactivity_modules_support' );
663 +add_filter( 'block_editor_settings', 'gutenberg_extend_settings_block_patterns', 0 );
417 664
418 665 /**
419 - * Always remove the Core action hook while gutenberg_enqueue_stored_styles() exists to avoid styles being printed twice.
420 - * This is also because gutenberg_enqueue_stored_styles uses the Style Engine's `gutenberg_*` functions and `_Gutenberg` classes,
421 - * which are in continuous development and generally ahead of Core.
666 + * Extends block editor settings to determine whether to use custom line height controls.
667 + *
668 + * @param array $settings Default editor settings.
669 + *
670 + * @return array Filtered editor settings.
422 671 */
423 -remove_action( 'wp_enqueue_scripts', 'wp_enqueue_stored_styles' );
424 -remove_action( 'wp_footer', 'wp_enqueue_stored_styles', 1 );
672 +function gutenberg_extend_settings_custom_line_height( $settings ) {
673 + $settings['__experimentalDisableCustomLineHeight'] = get_theme_support( 'disable-custom-line-height' );
674 + return $settings;
675 +}
676 +add_filter( 'block_editor_settings', 'gutenberg_extend_settings_custom_line_height' );
425 677
426 -// Enqueue stored styles.
427 -add_action( 'wp_enqueue_scripts', 'gutenberg_enqueue_stored_styles' );
428 -add_action( 'wp_footer', 'gutenberg_enqueue_stored_styles', 1 );
678 +/**
679 + * Extends block editor settings to determine whether to use custom unit controls.
680 + * Currently experimental.
681 + *
682 + * @param array $settings Default editor settings.
683 + *
684 + * @return array Filtered editor settings.
685 + */
686 +function gutenberg_extend_settings_custom_units( $settings ) {
687 + $settings['__experimentalDisableCustomUnits'] = get_theme_support( 'experimental-custom-units' );
688 + return $settings;
689 +}
690 +add_filter( 'block_editor_settings', 'gutenberg_extend_settings_custom_units' );
429 691
430 -add_action( 'enqueue_block_editor_assets', 'gutenberg_enqueue_latex_to_mathml_loader' );
431 -function gutenberg_enqueue_latex_to_mathml_loader() {
432 - wp_enqueue_script_module( '@wordpress/latex-to-mathml/loader' );
692 +/**
693 + * Extends block editor settings to determine whether to use custom spacing controls.
694 + * Currently experimental.
695 + *
696 + * @param array $settings Default editor settings.
697 + *
698 + * @return array Filtered editor settings.
699 + */
700 +function gutenberg_extend_settings_custom_spacing( $settings ) {
701 + $settings['__experimentalEnableCustomSpacing'] = get_theme_support( 'experimental-custom-spacing' );
702 + return $settings;
433 703 }
704 +add_filter( 'block_editor_settings', 'gutenberg_extend_settings_custom_spacing' );
434 705
706 +
435 707 /**
436 - * Enqueue the vips loader script module in the block editor.
708 + * Extends block editor settings to determine whether to use custom spacing controls.
709 + * Currently experimental.
437 710 *
438 - * This registers @wordpress/vips/worker as a dynamic dependency in the import map,
439 - * enabling on-demand loading of the ~3.8MB WASM-based image processing module
440 - * when client-side media processing is triggered via @wordpress/upload-media.
711 + * @param array $settings Default editor settings.
441 712 *
442 - * @see packages/vips/src/loader.ts
713 + * @return array Filtered editor settings.
443 714 */
444 -if ( defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN ) {
445 - add_action( 'enqueue_block_editor_assets', 'gutenberg_enqueue_vips_loader' );
715 +function gutenberg_extend_settings_link_color( $settings ) {
716 + $settings['__experimentalEnableLinkColor'] = get_theme_support( 'experimental-link-color' );
717 + return $settings;
446 718 }
447 -function gutenberg_enqueue_vips_loader() {
448 - wp_enqueue_script_module( '@wordpress/vips/loader' );
719 +add_filter( 'block_editor_settings', 'gutenberg_extend_settings_link_color' );
720 +
721 +/*
722 + * Register default patterns if not registered in Core already.
723 + */
724 +
725 +if ( class_exists( 'WP_Block_Patterns_Registry' ) && ! WP_Block_Patterns_Registry::get_instance()->is_registered( 'text-two-columns' ) ) {
726 + register_block_pattern( 'core/text-two-columns', gutenberg_load_block_pattern( 'text-two-columns' ) );
727 + register_block_pattern( 'core/two-buttons', gutenberg_load_block_pattern( 'two-buttons' ) );
728 + register_block_pattern( 'core/cover-abc', gutenberg_load_block_pattern( 'cover-abc' ) );
729 + register_block_pattern( 'core/two-images', gutenberg_load_block_pattern( 'two-images' ) );
730 + register_block_pattern( 'core/hero-two-columns', gutenberg_load_block_pattern( 'hero-two-columns' ) );
731 + register_block_pattern( 'core/numbered-features', gutenberg_load_block_pattern( 'numbered-features' ) );
732 + register_block_pattern( 'core/its-time', gutenberg_load_block_pattern( 'its-time' ) );
733 + register_block_pattern( 'core/hero-right-column', gutenberg_load_block_pattern( 'hero-right-column' ) );
734 + register_block_pattern( 'core/testimonials', gutenberg_load_block_pattern( 'testimonials' ) );
735 + register_block_pattern( 'core/features-services', gutenberg_load_block_pattern( 'features-services' ) );
449 736 }
450 737
451 -add_action( 'admin_enqueue_scripts', 'gutenberg_enqueue_core_abilities' );
452 -function gutenberg_enqueue_core_abilities() {
453 - wp_enqueue_script_module( '@wordpress/core-abilities' );
738 +/*
739 + * Register default pattern categories if not registered in Core already.
740 + */
741 +if ( class_exists( 'WP_Block_Pattern_Categories_Registry' ) ) {
742 + register_block_pattern_category( 'text', array( 'label' => _x( 'Text', 'Block pattern category', 'gutenberg' ) ) );
743 + register_block_pattern_category( 'hero', array( 'label' => _x( 'Hero', 'Block pattern category', 'gutenberg' ) ) );
744 + register_block_pattern_category( 'columns', array( 'label' => _x( 'Columns', 'Block pattern category', 'gutenberg' ) ) );
745 + register_block_pattern_category( 'buttons', array( 'label' => _x( 'Buttons', 'Block pattern category', 'gutenberg' ) ) );
746 + register_block_pattern_category( 'gallery', array( 'label' => _x( 'Gallery', 'Block pattern category', 'gutenberg' ) ) );
747 + register_block_pattern_category( 'features', array( 'label' => _x( 'Features', 'Block pattern category', 'gutenberg' ) ) );
748 + register_block_pattern_category( 'testimonials', array( 'label' => _x( 'Testimonials', 'Block pattern category', 'gutenberg' ) ) );
454 749 }