PluginProbe
Gutenberg / 10.8.1
Gutenberg v10.8.1
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 10.8.1, at lib/blocks.php

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