PluginProbe
Gutenberg / 12.5.4
Gutenberg v12.5.4
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 / blocks.php

blocks.php in Gutenberg 12.5.4, at lib/blocks.php

715 lines 23.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Block and style registration functions.
4 *
5 * @package gutenberg
6 */
7
8 /**
9 * Substitutes the implementation of a core-registered block type, if exists,
10 * with the built result from the plugin.
11 */
12 function gutenberg_reregister_core_block_types() {
13 // Blocks directory may not exist if working from a fresh clone.
14 $blocks_dirs = array(
15 __DIR__ . '/../build/block-library/blocks/' => array(
16 'block_folders' => array(
17 'audio',
18 'button',
19 'buttons',
20 'freeform',
21 'code',
22 'column',
23 'columns',
24 'comments-query-loop',
25 'cover',
26 'gallery',
27 'group',
28 'heading',
29 'html',
30 'home-link',
31 'image',
32 'list',
33 'media-text',
34 'missing',
35 'more',
36 'navigation-area',
37 'navigation-link',
38 'navigation-submenu',
39 'nextpage',
40 'pattern',
41 'paragraph',
42 'preformatted',
43 'pullquote',
44 'quote',
45 'separator',
46 'social-links',
47 'spacer',
48 'table',
49 // 'table-of-contents',
50 'text-columns',
51 'verse',
52 'video',
53 'embed',
54 ),
55 'block_names' => array(
56 'archives.php' => 'core/archives',
57 'block.php' => 'core/block',
58 'calendar.php' => 'core/calendar',
59 'categories.php' => 'core/categories',
60 'comment-author-avatar.php' => 'core/comment-author-avatar',
61 'comment-author-name.php' => 'core/comment-author-name',
62 'comment-content.php' => 'core/comment-content',
63 'comment-date.php' => 'core/comment-date',
64 'comment-edit-link.php' => 'core/comment-edit-link',
65 'comment-reply-link.php' => 'core/comment-reply-link',
66 'comment-template.php' => 'core/comment-template',
67 'comments-pagination.php' => 'core/comments-pagination',
68 'comments-pagination-next.php' => 'core/comments-pagination-next',
69 'comments-pagination-numbers.php' => 'core/comments-pagination-numbers',
70 'comments-pagination-previous.php' => 'core/comments-pagination-previous',
71 'file.php' => 'core/file',
72 'home-link.php' => 'core/home-link',
73 'image.php' => 'core/image',
74 'gallery.php' => 'core/gallery',
75 'latest-comments.php' => 'core/latest-comments',
76 'latest-posts.php' => 'core/latest-posts',
77 'loginout.php' => 'core/loginout',
78 'navigation.php' => 'core/navigation',
79 'navigation-area.php' => 'core/navigation-area',
80 'navigation-link.php' => 'core/navigation-link',
81 'navigation-submenu.php' => 'core/navigation-submenu',
82 'page-list.php' => 'core/page-list',
83 'pattern.php' => 'core/pattern',
84 'post-author.php' => 'core/post-author',
85 'post-author-name.php' => 'core/post-author-name',
86 'post-comment.php' => 'core/post-comment',
87 'post-comments.php' => 'core/post-comments',
88 'post-comments-count.php' => 'core/post-comments-count',
89 'post-comments-form.php' => 'core/post-comments-form',
90 'post-comments-link.php' => 'core/post-comments-link',
91 'post-content.php' => 'core/post-content',
92 'post-date.php' => 'core/post-date',
93 'post-excerpt.php' => 'core/post-excerpt',
94 'post-featured-image.php' => 'core/post-featured-image',
95 'post-navigation-link.php' => 'core/post-navigation-link',
96 'post-terms.php' => 'core/post-terms',
97 'post-title.php' => 'core/post-title',
98 'query.php' => 'core/query',
99 'post-template.php' => 'core/post-template',
100 'query-pagination.php' => 'core/query-pagination',
101 'query-pagination-next.php' => 'core/query-pagination-next',
102 'query-pagination-numbers.php' => 'core/query-pagination-numbers',
103 'query-pagination-previous.php' => 'core/query-pagination-previous',
104 'query-title.php' => 'core/query-title',
105 'rss.php' => 'core/rss',
106 'search.php' => 'core/search',
107 'shortcode.php' => 'core/shortcode',
108 'social-link.php' => 'core/social-link',
109 'site-logo.php' => 'core/site-logo',
110 'site-tagline.php' => 'core/site-tagline',
111 'site-title.php' => 'core/site-title',
112 // 'table-of-contents.php' => 'core/table-of-contents',
113 'tag-cloud.php' => 'core/tag-cloud',
114 'template-part.php' => 'core/template-part',
115 'term-description.php' => 'core/term-description',
116 ),
117 ),
118 __DIR__ . '/../build/edit-widgets/blocks/' => array(
119 'block_folders' => array(
120 'widget-area',
121 ),
122 'block_names' => array(),
123 ),
124 __DIR__ . '/../build/widgets/blocks/' => array(
125 'block_folders' => array(
126 'legacy-widget',
127 'widget-group',
128 ),
129 'block_names' => array(
130 'legacy-widget.php' => 'core/legacy-widget',
131 'widget-group.php' => 'core/widget-group',
132 ),
133 ),
134 );
135 foreach ( $blocks_dirs as $blocks_dir => $details ) {
136 $block_folders = $details['block_folders'];
137 $block_names = $details['block_names'];
138
139 $registry = WP_Block_Type_Registry::get_instance();
140
141 foreach ( $block_folders as $folder_name ) {
142 $block_json_file = $blocks_dir . $folder_name . '/block.json';
143
144 // Ideally, all paths to block metadata files should be listed in
145 // WordPress core. In this place we should rather use filter
146 // to replace paths with overrides defined by the plugin.
147 $metadata = json_decode( file_get_contents( $block_json_file ), true );
148 if ( ! is_array( $metadata ) || ! $metadata['name'] ) {
149 return false;
150 }
151
152 if ( $registry->is_registered( $metadata['name'] ) ) {
153 $registry->unregister( $metadata['name'] );
154 }
155
156 gutenberg_register_core_block_assets( $folder_name );
157 register_block_type_from_metadata( $block_json_file );
158 }
159
160 foreach ( $block_names as $file => $sub_block_names ) {
161 if ( ! file_exists( $blocks_dir . $file ) ) {
162 return;
163 }
164
165 $sub_block_names_normalized = is_string( $sub_block_names ) ? array( $sub_block_names ) : $sub_block_names;
166 foreach ( $sub_block_names_normalized as $block_name ) {
167 if ( $registry->is_registered( $block_name ) ) {
168 $registry->unregister( $block_name );
169 }
170 gutenberg_register_core_block_assets( $block_name );
171 }
172
173 require_once $blocks_dir . $file;
174 }
175 }
176 }
177
178 add_action( 'init', 'gutenberg_reregister_core_block_types' );
179
180 /**
181 * Registers block styles for a core block.
182 *
183 * @param string $block_name The block-name.
184 *
185 * @return void
186 */
187 function gutenberg_register_core_block_assets( $block_name ) {
188 if ( ! wp_should_load_separate_core_block_assets() ) {
189 return;
190 }
191
192 $block_name = str_replace( 'core/', '', $block_name );
193
194 // When in production, use the plugin's version as the default asset version;
195 // else (for development or test) default to use the current time.
196 $default_version = defined( 'GUTENBERG_VERSION' ) && ! ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? GUTENBERG_VERSION : time();
197
198 $style_path = "build/block-library/blocks/$block_name/style.css";
199 $editor_style_path = "build/block-library/blocks/$block_name/style-editor.css";
200
201 if ( file_exists( gutenberg_dir_path() . $style_path ) ) {
202 wp_deregister_style( "wp-block-{$block_name}" );
203 wp_register_style(
204 "wp-block-{$block_name}",
205 gutenberg_url( $style_path ),
206 array(),
207 $default_version
208 );
209 wp_style_add_data( "wp-block-{$block_name}", 'rtl', 'replace' );
210
211 // Add a reference to the stylesheet's path to allow calculations for inlining styles in `wp_head`.
212 wp_style_add_data( "wp-block-{$block_name}", 'path', gutenberg_dir_path() . $style_path );
213 } else {
214 wp_register_style( "wp-block-{$block_name}", false );
215 }
216
217 // If the current theme supports wp-block-styles, dequeue the full stylesheet
218 // and instead attach each block's theme-styles to their block styles stylesheet.
219 if ( current_theme_supports( 'wp-block-styles' ) ) {
220
221 // Dequeue the full stylesheet.
222 // Make sure this only runs once, it doesn't need to run for every block.
223 static $stylesheet_removed;
224 if ( ! $stylesheet_removed ) {
225 add_action(
226 'wp_enqueue_scripts',
227 function() {
228 wp_dequeue_style( 'wp-block-library-theme' );
229 }
230 );
231 $stylesheet_removed = true;
232 }
233
234 // Get the path to the block's stylesheet.
235 $theme_style_path = is_rtl()
236 ? "build/block-library/blocks/$block_name/theme-rtl.css"
237 : "build/block-library/blocks/$block_name/theme.css";
238
239 // If the file exists, enqueue it.
240 if ( file_exists( gutenberg_dir_path() . $theme_style_path ) ) {
241
242 if ( file_exists( gutenberg_dir_path() . $style_path ) ) {
243 // If there is a main stylesheet for this block, append the theme styles to main styles.
244 wp_add_inline_style(
245 "wp-block-{$block_name}",
246 file_get_contents( gutenberg_dir_path() . $theme_style_path )
247 );
248 } else {
249 // If there is no main stylesheet for this block, register theme style.
250 wp_register_style(
251 "wp-block-{$block_name}",
252 gutenberg_url( $theme_style_path ),
253 array(),
254 $default_version
255 );
256 wp_style_add_data( "wp-block-{$block_name}", 'path', gutenberg_dir_path() . $theme_style_path );
257 }
258 }
259 }
260
261 if ( file_exists( gutenberg_dir_path() . $editor_style_path ) ) {
262 wp_deregister_style( "wp-block-{$block_name}-editor" );
263 wp_register_style(
264 "wp-block-{$block_name}-editor",
265 gutenberg_url( $editor_style_path ),
266 array(),
267 $default_version
268 );
269 wp_style_add_data( "wp-block-{$block_name}-editor", 'rtl', 'replace' );
270 } else {
271 wp_register_style( "wp-block-{$block_name}-editor", false );
272 }
273 }
274
275 /**
276 * Change the way styles get loaded depending on their size.
277 *
278 * Optimizes performance and sustainability of styles by inlining smaller stylesheets.
279 *
280 * @todo Remove this function when the minimum supported version is WordPress 5.8.
281 *
282 * @return void
283 */
284 function gutenberg_maybe_inline_styles() {
285
286 // Early exit if the "wp_maybe_inline_styles" function exists.
287 if ( function_exists( 'wp_maybe_inline_styles' ) ) {
288 return;
289 }
290
291 $total_inline_limit = 20000;
292 /**
293 * The maximum size of inlined styles in bytes.
294 *
295 * @param int $total_inline_limit The file-size threshold, in bytes. Defaults to 20000.
296 * @return int The file-size threshold, in bytes.
297 */
298 $total_inline_limit = apply_filters( 'styles_inline_size_limit', $total_inline_limit );
299
300 global $wp_styles;
301 $styles = array();
302
303 // Build an array of styles that have a path defined.
304 foreach ( $wp_styles->queue as $handle ) {
305 if ( wp_styles()->get_data( $handle, 'path' ) && file_exists( $wp_styles->registered[ $handle ]->extra['path'] ) ) {
306 $styles[] = array(
307 'handle' => $handle,
308 'src' => $wp_styles->registered[ $handle ]->src,
309 'path' => $wp_styles->registered[ $handle ]->extra['path'],
310 'size' => filesize( $wp_styles->registered[ $handle ]->extra['path'] ),
311 );
312 }
313 }
314
315 if ( ! empty( $styles ) ) {
316 // Reorder styles array based on size.
317 usort(
318 $styles,
319 function( $a, $b ) {
320 return ( $a['size'] <= $b['size'] ) ? -1 : 1;
321 }
322 );
323
324 /**
325 * The total inlined size.
326 *
327 * On each iteration of the loop, if a style gets added inline the value of this var increases
328 * to reflect the total size of inlined styles.
329 */
330 $total_inline_size = 0;
331
332 // Loop styles.
333 foreach ( $styles as $style ) {
334
335 // Size check. Since styles are ordered by size, we can break the loop.
336 if ( $total_inline_size + $style['size'] > $total_inline_limit ) {
337 break;
338 }
339
340 // Get the styles if we don't already have them.
341 $style['css'] = file_get_contents( $style['path'] );
342
343 // Check if the style contains relative URLs that need to be modified.
344 // URLs relative to the stylesheet's path should be converted to relative to the site's root.
345 $style['css'] = _wp_normalize_relative_css_links( $style['css'], $style['src'] );
346
347 // Set `src` to `false` and add styles inline.
348 $wp_styles->registered[ $style['handle'] ]->src = false;
349 if ( empty( $wp_styles->registered[ $style['handle'] ]->extra['after'] ) ) {
350 $wp_styles->registered[ $style['handle'] ]->extra['after'] = array();
351 }
352 array_unshift( $wp_styles->registered[ $style['handle'] ]->extra['after'], $style['css'] );
353
354 // Add the styles size to the $total_inline_size var.
355 $total_inline_size += (int) $style['size'];
356 }
357 }
358 }
359 // Run for styles enqueued in <head>.
360 add_action( 'wp_head', 'gutenberg_maybe_inline_styles', 1 );
361 // Run for late-loaded styles in the footer.
362 add_action( 'wp_footer', 'gutenberg_maybe_inline_styles', 1 );
363
364 if ( ! function_exists( '_wp_normalize_relative_css_links' ) ) {
365 /**
366 * Make URLs relative to the WordPress installation.
367 *
368 * @since 5.8.2
369 *
370 * @param string $css The CSS to make URLs relative to the WordPress installation.
371 * @param string $stylesheet_url The URL to the stylesheet.
372 *
373 * @return string The CSS with URLs made relative to the WordPress installation.
374 */
375 function _wp_normalize_relative_css_links( $css, $stylesheet_url ) {
376 $has_src_results = preg_match_all( '#url\s*\(\s*[\'"]?\s*([^\'"\)]+)#', $css, $src_results );
377 if ( $has_src_results ) {
378 // Loop through the URLs to find relative ones.
379 foreach ( $src_results[1] as $src_index => $src_result ) {
380 // Skip if this is an absolute URL.
381 if ( 0 === strpos( $src_result, 'http' ) || 0 === strpos( $src_result, '//' ) ) {
382 continue;
383 }
384
385 // Build the absolute URL.
386 $absolute_url = dirname( $stylesheet_url ) . '/' . $src_result;
387 $absolute_url = str_replace( '/./', '/', $absolute_url );
388 // Convert to URL related to the site root.
389 $relative_url = wp_make_link_relative( $absolute_url );
390
391 // Replace the URL in the CSS.
392 $css = str_replace(
393 $src_results[0][ $src_index ],
394 str_replace( $src_result, $relative_url, $src_results[0][ $src_index ] ),
395 $css
396 );
397 }
398 }
399
400 return $css;
401 }
402 }
403
404 /**
405 * Complements the implementation of block type `core/social-icon`, whether it
406 * be provided by core or the plugin, with derived block types for each
407 * "service" (WordPress, Twitter, etc.) supported by Social Links.
408 *
409 * This ensures backwards compatibility for any users running the Gutenberg
410 * plugin who have used Social Links prior to their conversion to block
411 * variations.
412 *
413 * This shim is INTENTIONALLY left out of core, as Social Links haven't yet
414 * landed there.
415 *
416 * @see https://github.com/WordPress/gutenberg/pull/19887
417 */
418 function gutenberg_register_legacy_social_link_blocks() {
419 $services = array(
420 'amazon',
421 'bandcamp',
422 'behance',
423 'chain',
424 'codepen',
425 'deviantart',
426 'dribbble',
427 'dropbox',
428 'etsy',
429 'facebook',
430 'feed',
431 'fivehundredpx',
432 'flickr',
433 'foursquare',
434 'goodreads',
435 'google',
436 'github',
437 'instagram',
438 'lastfm',
439 'linkedin',
440 'mail',
441 'mastodon',
442 'meetup',
443 'medium',
444 'pinterest',
445 'pocket',
446 'reddit',
447 'skype',
448 'snapchat',
449 'soundcloud',
450 'spotify',
451 'tumblr',
452 'twitch',
453 'twitter',
454 'vimeo',
455 'vk',
456 'wordpress',
457 'yelp',
458 'youtube',
459 );
460
461 foreach ( $services as $service ) {
462 register_block_type(
463 'core/social-link-' . $service,
464 array(
465 'category' => 'widgets',
466 'attributes' => array(
467 'url' => array(
468 'type' => 'string',
469 ),
470 'service' => array(
471 'type' => 'string',
472 'default' => $service,
473 ),
474 'label' => array(
475 'type' => 'string',
476 ),
477 ),
478 'render_callback' => 'gutenberg_render_block_core_social_link',
479 )
480 );
481 }
482 }
483
484 add_action( 'init', 'gutenberg_register_legacy_social_link_blocks' );
485
486 /**
487 * Filters the default block categories array to add a new one for themes.
488 *
489 * This can be removed when plugin support requires WordPress 5.8.0+.
490 *
491 * @see https://core.trac.wordpress.org/ticket/52883
492 *
493 * @param array[] $categories The list of default block categories.
494 *
495 * @return array[] Filtered block categories.
496 */
497 function gutenberg_register_theme_block_category( $categories ) {
498 foreach ( $categories as $category ) {
499 // Skip when the category is already set in WordPress core.
500 if (
501 isset( $category['slug'] ) &&
502 'theme' === $category['slug']
503 ) {
504 return $categories;
505 }
506 }
507
508 $categories[] = array(
509 'slug' => 'theme',
510 'title' => _x( 'Theme', 'block category', 'gutenberg' ),
511 'icon' => null,
512 );
513 return $categories;
514 }
515 // This can be removed when plugin support requires WordPress 5.8.0+.
516 if ( ! function_exists( 'get_default_block_categories' ) ) {
517 add_filter( 'block_categories', 'gutenberg_register_theme_block_category' );
518 }
519
520 /**
521 * Checks whether the current block type supports the feature requested.
522 *
523 * @param WP_Block_Type $block_type Block type to check for support.
524 * @param array $feature Path of the feature to check support for.
525 * @param mixed $default Fallback value for feature support, defaults to false.
526 *
527 * @return boolean Whether or not the feature is supported.
528 */
529 function gutenberg_block_has_support( $block_type, $feature, $default = false ) {
530 $block_support = $default;
531 if ( $block_type && property_exists( $block_type, 'supports' ) ) {
532 $block_support = _wp_array_get( $block_type->supports, $feature, $default );
533 }
534
535 return true === $block_support || is_array( $block_support );
536 }
537
538 /**
539 * Updates the shape of supports for declaring fontSize and lineHeight.
540 *
541 * @param array $metadata Metadata for registering a block type.
542 * @return array Metadata for registering a block type with the supports shape updated.
543 */
544 function gutenberg_migrate_old_typography_shape( $metadata ) {
545 // Temporarily disable migrations from core blocks to avoid warnings on versions older than 5.8.
546 if ( isset( $metadata['supports'] ) && false === strpos( $metadata['file'], '/wp-includes/blocks/' ) ) {
547 $typography_keys = array(
548 '__experimentalFontFamily',
549 '__experimentalFontStyle',
550 '__experimentalFontWeight',
551 '__experimentalLetterSpacing',
552 '__experimentalTextDecoration',
553 '__experimentalTextTransform',
554 'fontSize',
555 'lineHeight',
556 );
557 foreach ( $typography_keys as $typography_key ) {
558 $support_for_key = _wp_array_get( $metadata['supports'], array( $typography_key ), null );
559 if ( null !== $support_for_key ) {
560 trigger_error(
561 /* translators: %1$s: Block type, %2$s: typography supports key e.g: fontSize, lineHeight etc... */
562 sprintf( __( 'Block %1$s is declaring %2$s support on block.json under supports.%2$s. %2$s support is now declared under supports.typography.%2$s.', 'gutenberg' ), $metadata['name'], $typography_key ),
563 headers_sent() || WP_DEBUG ? E_USER_WARNING : E_USER_NOTICE
564 );
565 _wp_array_set( $metadata['supports'], array( 'typography', $typography_key ), $support_for_key );
566 unset( $metadata['supports'][ $typography_key ] );
567 }
568 }
569 }
570 return $metadata;
571 }
572
573 if ( ! function_exists( 'wp_migrate_old_typography_shape' ) ) {
574 add_filter( 'block_type_metadata', 'gutenberg_migrate_old_typography_shape' );
575 }
576
577 if ( ! function_exists( 'wp_enqueue_block_style' ) ) {
578 /**
579 * Enqueue a stylesheet for a specific block.
580 *
581 * If the theme has opted-in to separate-styles loading,
582 * then the stylesheet will be enqueued on-render,
583 * otherwise when the block inits.
584 *
585 * @param string $block_name The block-name, including namespace.
586 * @param array $args An array of arguments [handle,src,deps,ver,media].
587 *
588 * @return void
589 */
590 function wp_enqueue_block_style( $block_name, $args ) {
591 $args = wp_parse_args(
592 $args,
593 array(
594 'handle' => '',
595 'src' => '',
596 'deps' => array(),
597 'ver' => false,
598 'media' => 'all',
599 )
600 );
601
602 /**
603 * Callback function to register and enqueue styles.
604 *
605 * @param string $content When the callback is used for the render_block filter,
606 * the content needs to be returned so the function parameter
607 * is to ensure the content exists.
608 * @return string Block content.
609 */
610 $callback = static function( $content ) use ( $args ) {
611 // Register the stylesheet.
612 if ( ! empty( $args['src'] ) ) {
613 wp_register_style( $args['handle'], $args['src'], $args['deps'], $args['ver'], $args['media'] );
614 }
615
616 // Add `path` data if provided.
617 if ( isset( $args['path'] ) ) {
618 wp_style_add_data( $args['handle'], 'path', $args['path'] );
619
620 // Get the RTL file path.
621 $rtl_file_path = str_replace( '.css', '-rtl.css', $args['path'] );
622
623 // Add RTL stylesheet.
624 if ( file_exists( $rtl_file_path ) ) {
625 wp_style_add_data( $args['handle'], 'rtl', 'replace' );
626
627 if ( is_rtl() ) {
628 wp_style_add_data( $args['handle'], 'path', $rtl_file_path );
629 }
630 }
631 }
632
633 // Enqueue the stylesheet.
634 wp_enqueue_style( $args['handle'] );
635
636 return $content;
637 };
638
639 $hook = did_action( 'wp_enqueue_scripts' ) ? 'wp_footer' : 'wp_enqueue_scripts';
640 if ( wp_should_load_separate_core_block_assets() ) {
641 /**
642 * Callback function to register and enqueue styles.
643 *
644 * @param string $content The block content.
645 * @param array $block The full block, including name and attributes.
646 * @return string Block content.
647 */
648 $callback_separate = static function( $content, $block ) use ( $block_name, $callback ) {
649 if ( ! empty( $block['blockName'] ) && $block_name === $block['blockName'] ) {
650 return $callback( $content );
651 }
652 return $content;
653 };
654
655 /*
656 * The filter's callback here is an anonymous function because
657 * using a named function in this case is not possible.
658 *
659 * The function cannot be unhooked, however, users are still able
660 * to dequeue the stylesheets registered/enqueued by the callback
661 * which is why in this case, using an anonymous function
662 * was deemed acceptable.
663 */
664 add_filter( 'render_block', $callback_separate, 10, 2 );
665 return;
666 }
667
668 /*
669 * The filter's callback here is an anonymous function because
670 * using a named function in this case is not possible.
671 *
672 * The function cannot be unhooked, however, users are still able
673 * to dequeue the stylesheets registered/enqueued by the callback
674 * which is why in this case, using an anonymous function
675 * was deemed acceptable.
676 */
677 add_filter( $hook, $callback );
678
679 // Enqueue assets in the editor.
680 add_action( 'enqueue_block_assets', $callback );
681 }
682 }
683
684 /**
685 * Allow multiple block styles.
686 *
687 * @param array $metadata Metadata for registering a block type.
688 *
689 * @return array
690 */
691 function gutenberg_multiple_block_styles( $metadata ) {
692 foreach ( array( 'style', 'editorStyle' ) as $key ) {
693 if ( ! empty( $metadata[ $key ] ) && is_array( $metadata[ $key ] ) ) {
694 $default_style = array_shift( $metadata[ $key ] );
695 foreach ( $metadata[ $key ] as $handle ) {
696 $args = array( 'handle' => $handle );
697 if ( 0 === strpos( $handle, 'file:' ) && isset( $metadata['file'] ) ) {
698 $style_path = remove_block_asset_path_prefix( $handle );
699 $args = array(
700 'handle' => sanitize_key( "{$metadata['name']}-{$style_path}" ),
701 'src' => plugins_url( $style_path, $metadata['file'] ),
702 );
703 }
704
705 wp_enqueue_block_style( $metadata['name'], $args );
706 }
707
708 // Only return the 1st item in the array.
709 $metadata[ $key ] = $default_style;
710 }
711 }
712 return $metadata;
713 }
714 add_filter( 'block_type_metadata', 'gutenberg_multiple_block_styles' );
715