PluginProbe
Gutenberg / 11.5.0
Gutenberg v11.5.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.5.0, at lib/blocks.php

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