PluginProbe
Gutenberg / 11.7.0
Gutenberg v11.7.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 / blocks.php

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

515 lines 16.3 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 'cover',
25 'gallery',
26 'group',
27 'heading',
28 'html',
29 'home-link',
30 'image',
31 'list',
32 'media-text',
33 'missing',
34 'more',
35 'navigation-link',
36 'navigation-submenu',
37 'nextpage',
38 'paragraph',
39 'preformatted',
40 'pullquote',
41 'quote',
42 'separator',
43 'social-links',
44 'spacer',
45 'table',
46 // 'table-of-contents',
47 'text-columns',
48 'verse',
49 'video',
50 'embed',
51 ),
52 'block_names' => array(
53 'archives.php' => 'core/archives',
54 'block.php' => 'core/block',
55 'calendar.php' => 'core/calendar',
56 'categories.php' => 'core/categories',
57 'file.php' => 'core/file',
58 'latest-comments.php' => 'core/latest-comments',
59 'latest-posts.php' => 'core/latest-posts',
60 'loginout.php' => 'core/loginout',
61 'navigation.php' => 'core/navigation',
62 'navigation-link.php' => 'core/navigation-link',
63 'navigation-submenu.php' => 'core/navigation-submenu',
64 'home-link.php' => 'core/home-link',
65 'rss.php' => 'core/rss',
66 'search.php' => 'core/search',
67 'shortcode.php' => 'core/shortcode',
68 'social-link.php' => 'core/social-link',
69 'tag-cloud.php' => 'core/tag-cloud',
70 'page-list.php' => 'core/page-list',
71 'post-author.php' => 'core/post-author',
72 'post-comment.php' => 'core/post-comment',
73 'post-comment-author.php' => 'core/post-comment-author',
74 'post-comment-content.php' => 'core/post-comment-content',
75 'post-comment-date.php' => 'core/post-comment-date',
76 'post-comments.php' => 'core/post-comments',
77 'post-comments-count.php' => 'core/post-comments-count',
78 'post-comments-form.php' => 'core/post-comments-form',
79 'post-comments-link.php' => 'core/post-comments-link',
80 'post-content.php' => 'core/post-content',
81 'post-date.php' => 'core/post-date',
82 'post-excerpt.php' => 'core/post-excerpt',
83 'post-featured-image.php' => 'core/post-featured-image',
84 'post-terms.php' => 'core/post-terms',
85 'post-navigation-link.php' => 'core/post-navigation-link',
86 'post-title.php' => 'core/post-title',
87 'query.php' => 'core/query',
88 'post-template.php' => 'core/post-template',
89 'query-title.php' => 'core/query-title',
90 'query-pagination.php' => 'core/query-pagination',
91 'query-pagination-next.php' => 'core/query-pagination-next',
92 'query-pagination-numbers.php' => 'core/query-pagination-numbers',
93 'query-pagination-previous.php' => 'core/query-pagination-previous',
94 'site-logo.php' => 'core/site-logo',
95 'site-tagline.php' => 'core/site-tagline',
96 'site-title.php' => 'core/site-title',
97 // 'table-of-contents.php' => 'core/table-of-contents',
98 'template-part.php' => 'core/template-part',
99 'term-description.php' => 'core/term-description',
100 ),
101 ),
102 __DIR__ . '/../build/edit-widgets/blocks/' => array(
103 'block_folders' => array(
104 'widget-area',
105 ),
106 'block_names' => array(),
107 ),
108 __DIR__ . '/../build/widgets/blocks/' => array(
109 'block_folders' => array(
110 'legacy-widget',
111 'widget-group',
112 ),
113 'block_names' => array(
114 'legacy-widget.php' => 'core/legacy-widget',
115 'widget-group.php' => 'core/widget-group',
116 ),
117 ),
118 );
119 foreach ( $blocks_dirs as $blocks_dir => $details ) {
120 $block_folders = $details['block_folders'];
121 $block_names = $details['block_names'];
122
123 $registry = WP_Block_Type_Registry::get_instance();
124
125 foreach ( $block_folders as $folder_name ) {
126 $block_json_file = $blocks_dir . $folder_name . '/block.json';
127
128 // Ideally, all paths to block metadata files should be listed in
129 // WordPress core. In this place we should rather use filter
130 // to replace paths with overrides defined by the plugin.
131 $metadata = json_decode( file_get_contents( $block_json_file ), true );
132 if ( ! is_array( $metadata ) || ! $metadata['name'] ) {
133 return false;
134 }
135
136 if ( $registry->is_registered( $metadata['name'] ) ) {
137 $registry->unregister( $metadata['name'] );
138 }
139
140 gutenberg_register_core_block_assets( $folder_name );
141 register_block_type_from_metadata( $block_json_file );
142 }
143
144 foreach ( $block_names as $file => $sub_block_names ) {
145 if ( ! file_exists( $blocks_dir . $file ) ) {
146 return;
147 }
148
149 $sub_block_names_normalized = is_string( $sub_block_names ) ? array( $sub_block_names ) : $sub_block_names;
150 foreach ( $sub_block_names_normalized as $block_name ) {
151 if ( $registry->is_registered( $block_name ) ) {
152 $registry->unregister( $block_name );
153 }
154 gutenberg_register_core_block_assets( $block_name );
155 }
156
157 require_once $blocks_dir . $file;
158 }
159 }
160 }
161
162 add_action( 'init', 'gutenberg_reregister_core_block_types' );
163
164 /**
165 * Registers block styles for a core block.
166 *
167 * @param string $block_name The block-name.
168 *
169 * @return void
170 */
171 function gutenberg_register_core_block_assets( $block_name ) {
172 if ( ! wp_should_load_separate_core_block_assets() ) {
173 return;
174 }
175
176 $block_name = str_replace( 'core/', '', $block_name );
177
178 // When in production, use the plugin's version as the default asset version;
179 // else (for development or test) default to use the current time.
180 $default_version = defined( 'GUTENBERG_VERSION' ) && ! ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? GUTENBERG_VERSION : time();
181
182 $style_path = "build/block-library/blocks/$block_name/style.css";
183 $editor_style_path = "build/block-library/blocks/$block_name/style-editor.css";
184
185 if ( file_exists( gutenberg_dir_path() . $style_path ) ) {
186 wp_deregister_style( "wp-block-{$block_name}" );
187 wp_register_style(
188 "wp-block-{$block_name}",
189 gutenberg_url( $style_path ),
190 array(),
191 $default_version
192 );
193 wp_style_add_data( "wp-block-{$block_name}", 'rtl', 'replace' );
194
195 // Add a reference to the stylesheet's path to allow calculations for inlining styles in `wp_head`.
196 wp_style_add_data( "wp-block-{$block_name}", 'path', gutenberg_dir_path() . $style_path );
197 } else {
198 wp_register_style( "wp-block-{$block_name}", false );
199 }
200
201 // If the current theme supports wp-block-styles, dequeue the full stylesheet
202 // and instead attach each block's theme-styles to their block styles stylesheet.
203 if ( current_theme_supports( 'wp-block-styles' ) ) {
204
205 // Dequeue the full stylesheet.
206 // Make sure this only runs once, it doesn't need to run for every block.
207 static $stylesheet_removed;
208 if ( ! $stylesheet_removed ) {
209 add_action(
210 'wp_enqueue_scripts',
211 function() {
212 wp_dequeue_style( 'wp-block-library-theme' );
213 }
214 );
215 $stylesheet_removed = true;
216 }
217
218 // Get the path to the block's stylesheet.
219 $theme_style_path = is_rtl()
220 ? "build/block-library/blocks/$block_name/theme-rtl.css"
221 : "build/block-library/blocks/$block_name/theme.css";
222
223 // If the file exists, enqueue it.
224 if ( file_exists( gutenberg_dir_path() . $theme_style_path ) ) {
225
226 if ( file_exists( gutenberg_dir_path() . $style_path ) ) {
227 // If there is a main stylesheet for this block, append the theme styles to main styles.
228 wp_add_inline_style(
229 "wp-block-{$block_name}",
230 file_get_contents( gutenberg_dir_path() . $theme_style_path )
231 );
232 } else {
233 // If there is no main stylesheet for this block, register theme style.
234 wp_register_style(
235 "wp-block-{$block_name}",
236 gutenberg_url( $theme_style_path ),
237 array(),
238 $default_version
239 );
240 wp_style_add_data( "wp-block-{$block_name}", 'path', gutenberg_dir_path() . $theme_style_path );
241 }
242 }
243 }
244
245 if ( file_exists( gutenberg_dir_path() . $editor_style_path ) ) {
246 wp_deregister_style( "wp-block-{$block_name}-editor" );
247 wp_register_style(
248 "wp-block-{$block_name}-editor",
249 gutenberg_url( $editor_style_path ),
250 array(),
251 $default_version
252 );
253 wp_style_add_data( "wp-block-{$block_name}-editor", 'rtl', 'replace' );
254 } else {
255 wp_register_style( "wp-block-{$block_name}-editor", false );
256 }
257 }
258
259 /**
260 * Change the way styles get loaded depending on their size.
261 *
262 * Optimizes performance and sustainability of styles by inlining smaller stylesheets.
263 *
264 * @todo Remove this function when the minimum supported version is WordPress 5.8.
265 *
266 * @return void
267 */
268 function gutenberg_maybe_inline_styles() {
269
270 // Early exit if the "wp_maybe_inline_styles" function exists.
271 if ( function_exists( 'wp_maybe_inline_styles' ) ) {
272 return;
273 }
274
275 $total_inline_limit = 20000;
276 /**
277 * The maximum size of inlined styles in bytes.
278 *
279 * @param int $total_inline_limit The file-size threshold, in bytes. Defaults to 20000.
280 * @return int The file-size threshold, in bytes.
281 */
282 $total_inline_limit = apply_filters( 'styles_inline_size_limit', $total_inline_limit );
283
284 global $wp_styles;
285 $styles = array();
286
287 // Build an array of styles that have a path defined.
288 foreach ( $wp_styles->queue as $handle ) {
289 if ( wp_styles()->get_data( $handle, 'path' ) && file_exists( $wp_styles->registered[ $handle ]->extra['path'] ) ) {
290 $styles[] = array(
291 'handle' => $handle,
292 'path' => $wp_styles->registered[ $handle ]->extra['path'],
293 'size' => filesize( $wp_styles->registered[ $handle ]->extra['path'] ),
294 );
295 }
296 }
297
298 if ( ! empty( $styles ) ) {
299 // Reorder styles array based on size.
300 usort(
301 $styles,
302 function( $a, $b ) {
303 return ( $a['size'] <= $b['size'] ) ? -1 : 1;
304 }
305 );
306
307 /**
308 * The total inlined size.
309 *
310 * On each iteration of the loop, if a style gets added inline the value of this var increases
311 * to reflect the total size of inlined styles.
312 */
313 $total_inline_size = 0;
314
315 // Loop styles.
316 foreach ( $styles as $style ) {
317
318 // Size check. Since styles are ordered by size, we can break the loop.
319 if ( $total_inline_size + $style['size'] > $total_inline_limit ) {
320 break;
321 }
322
323 // Get the styles if we don't already have them.
324 $style['css'] = file_get_contents( $style['path'] );
325
326 // Set `src` to `false` and add styles inline.
327 $wp_styles->registered[ $style['handle'] ]->src = false;
328 if ( empty( $wp_styles->registered[ $style['handle'] ]->extra['after'] ) ) {
329 $wp_styles->registered[ $style['handle'] ]->extra['after'] = array();
330 }
331 array_unshift( $wp_styles->registered[ $style['handle'] ]->extra['after'], $style['css'] );
332
333 // Add the styles size to the $total_inline_size var.
334 $total_inline_size += (int) $style['size'];
335 }
336 }
337 }
338 // Run for styles enqueued in <head>.
339 add_action( 'wp_head', 'gutenberg_maybe_inline_styles', 1 );
340 // Run for late-loaded styles in the footer.
341 add_action( 'wp_footer', 'gutenberg_maybe_inline_styles', 1 );
342
343 /**
344 * Complements the implementation of block type `core/social-icon`, whether it
345 * be provided by core or the plugin, with derived block types for each
346 * "service" (WordPress, Twitter, etc.) supported by Social Links.
347 *
348 * This ensures backwards compatibility for any users running the Gutenberg
349 * plugin who have used Social Links prior to their conversion to block
350 * variations.
351 *
352 * This shim is INTENTIONALLY left out of core, as Social Links haven't yet
353 * landed there.
354 *
355 * @see https://github.com/WordPress/gutenberg/pull/19887
356 */
357 function gutenberg_register_legacy_social_link_blocks() {
358 $services = array(
359 'amazon',
360 'bandcamp',
361 'behance',
362 'chain',
363 'codepen',
364 'deviantart',
365 'dribbble',
366 'dropbox',
367 'etsy',
368 'facebook',
369 'feed',
370 'fivehundredpx',
371 'flickr',
372 'foursquare',
373 'goodreads',
374 'google',
375 'github',
376 'instagram',
377 'lastfm',
378 'linkedin',
379 'mail',
380 'mastodon',
381 'meetup',
382 'medium',
383 'pinterest',
384 'pocket',
385 'reddit',
386 'skype',
387 'snapchat',
388 'soundcloud',
389 'spotify',
390 'tumblr',
391 'twitch',
392 'twitter',
393 'vimeo',
394 'vk',
395 'wordpress',
396 'yelp',
397 'youtube',
398 );
399
400 foreach ( $services as $service ) {
401 register_block_type(
402 'core/social-link-' . $service,
403 array(
404 'category' => 'widgets',
405 'attributes' => array(
406 'url' => array(
407 'type' => 'string',
408 ),
409 'service' => array(
410 'type' => 'string',
411 'default' => $service,
412 ),
413 'label' => array(
414 'type' => 'string',
415 ),
416 ),
417 'render_callback' => 'gutenberg_render_block_core_social_link',
418 )
419 );
420 }
421 }
422
423 add_action( 'init', 'gutenberg_register_legacy_social_link_blocks' );
424
425 /**
426 * Filters the default block categories array to add a new one for themes.
427 *
428 * This can be removed when plugin support requires WordPress 5.8.0+.
429 *
430 * @see https://core.trac.wordpress.org/ticket/52883
431 *
432 * @param array[] $categories The list of default block categories.
433 *
434 * @return array[] Filtered block categories.
435 */
436 function gutenberg_register_theme_block_category( $categories ) {
437 foreach ( $categories as $category ) {
438 // Skip when the category is already set in WordPress core.
439 if (
440 isset( $category['slug'] ) &&
441 'theme' === $category['slug']
442 ) {
443 return $categories;
444 }
445 }
446
447 $categories[] = array(
448 'slug' => 'theme',
449 'title' => _x( 'Theme', 'block category', 'gutenberg' ),
450 'icon' => null,
451 );
452 return $categories;
453 }
454 // This can be removed when plugin support requires WordPress 5.8.0+.
455 if ( ! function_exists( 'get_default_block_categories' ) ) {
456 add_filter( 'block_categories', 'gutenberg_register_theme_block_category' );
457 }
458
459 /**
460 * Checks whether the current block type supports the feature requested.
461 *
462 * @param WP_Block_Type $block_type Block type to check for support.
463 * @param array $feature Path of the feature to check support for.
464 * @param mixed $default Fallback value for feature support, defaults to false.
465 *
466 * @return boolean Whether or not the feature is supported.
467 */
468 function gutenberg_block_has_support( $block_type, $feature, $default = false ) {
469 $block_support = $default;
470 if ( $block_type && property_exists( $block_type, 'supports' ) ) {
471 $block_support = _wp_array_get( $block_type->supports, $feature, $default );
472 }
473
474 return true === $block_support || is_array( $block_support );
475 }
476
477 /**
478 * Updates the shape of supports for declaring fontSize and lineHeight.
479 *
480 * @param array $metadata Metadata for registering a block type.
481 * @return array Metadata for registering a block type with the supports shape updated.
482 */
483 function gutenberg_migrate_old_typography_shape( $metadata ) {
484 // Temporarily disable migrations from core blocks to avoid warnings on versions older than 5.8.
485 if ( isset( $metadata['supports'] ) && false === strpos( $metadata['file'], '/wp-includes/blocks/' ) ) {
486 $typography_keys = array(
487 '__experimentalFontFamily',
488 '__experimentalFontStyle',
489 '__experimentalFontWeight',
490 '__experimentalLetterSpacing',
491 '__experimentalTextDecoration',
492 '__experimentalTextTransform',
493 'fontSize',
494 'lineHeight',
495 );
496 foreach ( $typography_keys as $typography_key ) {
497 $support_for_key = _wp_array_get( $metadata['supports'], array( $typography_key ), null );
498 if ( null !== $support_for_key ) {
499 trigger_error(
500 /* translators: %1$s: Block type, %2$s: typography supports key e.g: fontSize, lineHeight etc... */
501 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 ),
502 headers_sent() || WP_DEBUG ? E_USER_WARNING : E_USER_NOTICE
503 );
504 gutenberg_experimental_set( $metadata['supports'], array( 'typography', $typography_key ), $support_for_key );
505 unset( $metadata['supports'][ $typography_key ] );
506 }
507 }
508 }
509 return $metadata;
510 }
511
512 if ( ! function_exists( 'wp_migrate_old_typography_shape' ) ) {
513 add_filter( 'block_type_metadata', 'gutenberg_migrate_old_typography_shape' );
514 }
515