PluginProbe
Gutenberg / 16.7.1
Gutenberg v16.7.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 16.7.1, at lib/blocks.php

464 lines 15.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Block functions specific for the Gutenberg editor plugin.
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 'details',
25 'group',
26 'html',
27 'list',
28 'list-item',
29 'media-text',
30 'missing',
31 'more',
32 'nextpage',
33 'paragraph',
34 'preformatted',
35 'pullquote',
36 'quote',
37 'separator',
38 'social-links',
39 'spacer',
40 'table',
41 'table-of-contents',
42 'text-columns',
43 'verse',
44 'video',
45 'embed',
46 ),
47 'block_names' => array(
48 'archives.php' => 'core/archives',
49 'avatar.php' => 'core/avatar',
50 'block.php' => 'core/block',
51 'calendar.php' => 'core/calendar',
52 'categories.php' => 'core/categories',
53 'cover.php' => 'core/cover',
54 'comment-author-avatar.php' => 'core/comment-author-avatar',
55 'comment-author-name.php' => 'core/comment-author-name',
56 'comment-content.php' => 'core/comment-content',
57 'comment-date.php' => 'core/comment-date',
58 'comment-edit-link.php' => 'core/comment-edit-link',
59 'comment-reply-link.php' => 'core/comment-reply-link',
60 'comment-template.php' => 'core/comment-template',
61 'comments-pagination.php' => 'core/comments-pagination',
62 'comments-pagination-next.php' => 'core/comments-pagination-next',
63 'comments-pagination-numbers.php' => 'core/comments-pagination-numbers',
64 'comments-pagination-previous.php' => 'core/comments-pagination-previous',
65 'comments-title.php' => 'core/comments-title',
66 'comments.php' => 'core/comments',
67 'footnotes.php' => 'core/footnotes',
68 'file.php' => 'core/file',
69 'home-link.php' => 'core/home-link',
70 'image.php' => 'core/image',
71 'gallery.php' => 'core/gallery',
72 'heading.php' => 'core/heading',
73 'latest-comments.php' => 'core/latest-comments',
74 'latest-posts.php' => 'core/latest-posts',
75 'loginout.php' => 'core/loginout',
76 'navigation.php' => 'core/navigation',
77 'navigation-link.php' => 'core/navigation-link',
78 'navigation-submenu.php' => 'core/navigation-submenu',
79 'page-list.php' => 'core/page-list',
80 'page-list-item.php' => 'core/page-list-item',
81 'pattern.php' => 'core/pattern',
82 'post-author.php' => 'core/post-author',
83 'post-author-name.php' => 'core/post-author-name',
84 'post-author-biography.php' => 'core/post-author-biography',
85 'post-comment.php' => 'core/post-comment',
86 'post-comments-count.php' => 'core/post-comments-count',
87 'post-comments-form.php' => 'core/post-comments-form',
88 'post-comments-link.php' => 'core/post-comments-link',
89 'post-content.php' => 'core/post-content',
90 'post-date.php' => 'core/post-date',
91 'post-excerpt.php' => 'core/post-excerpt',
92 'post-featured-image.php' => 'core/post-featured-image',
93 'post-navigation-link.php' => 'core/post-navigation-link',
94 'post-terms.php' => 'core/post-terms',
95 'post-time-to-read.php' => 'core/post-time-to-read',
96 'post-title.php' => 'core/post-title',
97 'query.php' => 'core/query',
98 'post-template.php' => 'core/post-template',
99 'query-no-results.php' => 'core/query-no-results',
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 'read-more.php' => 'core/read-more',
106 'rss.php' => 'core/rss',
107 'search.php' => 'core/search',
108 'shortcode.php' => 'core/shortcode',
109 'social-link.php' => 'core/social-link',
110 'site-logo.php' => 'core/site-logo',
111 'site-tagline.php' => 'core/site-tagline',
112 'site-title.php' => 'core/site-title',
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 foreach ( $block_folders as $folder_name ) {
140 $block_json_file = $blocks_dir . $folder_name . '/block.json';
141
142 // Ideally, all paths to block metadata files should be listed in
143 // WordPress core. In this place we should rather use filter
144 // to replace paths with overrides defined by the plugin.
145 $metadata = json_decode( file_get_contents( $block_json_file ), true );
146 if ( ! is_array( $metadata ) || ! $metadata['name'] ) {
147 continue;
148 }
149
150 gutenberg_deregister_core_block_and_assets( $metadata['name'] );
151 gutenberg_register_core_block_assets( $folder_name );
152 register_block_type_from_metadata( $block_json_file );
153 }
154
155 foreach ( $block_names as $file => $sub_block_names ) {
156 if ( ! file_exists( $blocks_dir . $file ) ) {
157 continue;
158 }
159
160 $sub_block_names_normalized = is_string( $sub_block_names ) ? array( $sub_block_names ) : $sub_block_names;
161 foreach ( $sub_block_names_normalized as $block_name ) {
162 gutenberg_deregister_core_block_and_assets( $block_name );
163 gutenberg_register_core_block_assets( $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 * Adds the defer loading strategy to all registered blocks.
175 *
176 * This function would not be part of core merge. Instead, the register_block_script_handle() function would be patched
177 * as follows.
178 *
179 * ```
180 * --- a/wp-includes/blocks.php
181 * +++ b/wp-includes/blocks.php
182 * @ @ -153,7 +153,8 @ @ function register_block_script_handle( $metadata, $field_name, $index = 0 ) {
183 * $script_handle,
184 * $script_uri,
185 * $script_dependencies,
186 * - isset( $script_asset['version'] ) ? $script_asset['version'] : false
187 * + isset( $script_asset['version'] ) ? $script_asset['version'] : false,
188 * + array( 'strategy' => 'defer' )
189 * );
190 * if ( ! $result ) {
191 * return false;
192 * ```
193 *
194 * @see register_block_script_handle()
195 */
196 function gutenberg_defer_block_view_scripts() {
197 $block_types = WP_Block_Type_Registry::get_instance()->get_all_registered();
198 foreach ( $block_types as $block_type ) {
199 foreach ( $block_type->view_script_handles as $view_script_handle ) {
200 wp_script_add_data( $view_script_handle, 'strategy', 'defer' );
201 }
202 }
203 }
204
205 add_action( 'init', 'gutenberg_defer_block_view_scripts', 100 );
206
207 /**
208 * Deregisters the existing core block type and its assets.
209 *
210 * @param string $block_name The name of the block.
211 *
212 * @return void
213 */
214 function gutenberg_deregister_core_block_and_assets( $block_name ) {
215 $registry = WP_Block_Type_Registry::get_instance();
216 if ( $registry->is_registered( $block_name ) ) {
217 $block_type = $registry->get_registered( $block_name );
218 if ( ! empty( $block_type->view_script_handles ) ) {
219 foreach ( $block_type->view_script_handles as $view_script_handle ) {
220 if ( str_starts_with( $view_script_handle, 'wp-block-' ) ) {
221 wp_deregister_script( $view_script_handle );
222 }
223 }
224 }
225 $registry->unregister( $block_name );
226 }
227 }
228
229 /**
230 * Registers block styles for a core block.
231 *
232 * @param string $block_name The block-name.
233 *
234 * @return void
235 */
236 function gutenberg_register_core_block_assets( $block_name ) {
237 if ( ! wp_should_load_separate_core_block_assets() ) {
238 return;
239 }
240
241 $block_name = str_replace( 'core/', '', $block_name );
242
243 // When in production, use the plugin's version as the default asset version;
244 // else (for development or test) default to use the current time.
245 $default_version = defined( 'GUTENBERG_VERSION' ) && ! SCRIPT_DEBUG ? GUTENBERG_VERSION : time();
246
247 $style_path = "build/block-library/blocks/$block_name/";
248 $stylesheet_url = gutenberg_url( $style_path . 'style.css' );
249 $stylesheet_path = gutenberg_dir_path() . $style_path . ( is_rtl() ? 'style-rtl.css' : 'style.css' );
250
251 if ( file_exists( $stylesheet_path ) ) {
252 wp_deregister_style( "wp-block-{$block_name}" );
253 wp_register_style(
254 "wp-block-{$block_name}",
255 $stylesheet_url,
256 array(),
257 $default_version
258 );
259 wp_style_add_data( "wp-block-{$block_name}", 'rtl', 'replace' );
260
261 // Add a reference to the stylesheet's path to allow calculations for inlining styles in `wp_head`.
262 wp_style_add_data( "wp-block-{$block_name}", 'path', $stylesheet_path );
263 } else {
264 wp_register_style( "wp-block-{$block_name}", false, array() );
265 }
266
267 // If the current theme supports wp-block-styles, dequeue the full stylesheet
268 // and instead attach each block's theme-styles to their block styles stylesheet.
269 if ( current_theme_supports( 'wp-block-styles' ) ) {
270
271 // Dequeue the full stylesheet.
272 // Make sure this only runs once, it doesn't need to run for every block.
273 static $stylesheet_removed;
274 if ( ! $stylesheet_removed ) {
275 add_action(
276 'wp_enqueue_scripts',
277 static function () {
278 wp_dequeue_style( 'wp-block-library-theme' );
279 }
280 );
281 $stylesheet_removed = true;
282 }
283
284 // Get the path to the block's stylesheet.
285 $theme_style_path = is_rtl()
286 ? "build/block-library/blocks/$block_name/theme-rtl.css"
287 : "build/block-library/blocks/$block_name/theme.css";
288
289 // If the file exists, enqueue it.
290 if ( file_exists( gutenberg_dir_path() . $theme_style_path ) ) {
291
292 if ( file_exists( $stylesheet_path ) ) {
293 // If there is a main stylesheet for this block, append the theme styles to main styles.
294 wp_add_inline_style(
295 "wp-block-{$block_name}",
296 file_get_contents( gutenberg_dir_path() . $theme_style_path )
297 );
298 } else {
299 // If there is no main stylesheet for this block, register theme style.
300 wp_register_style(
301 "wp-block-{$block_name}",
302 gutenberg_url( $theme_style_path ),
303 array(),
304 $default_version
305 );
306 wp_style_add_data( "wp-block-{$block_name}", 'path', gutenberg_dir_path() . $theme_style_path );
307 }
308 }
309 }
310
311 $editor_style_path = "build/block-library/blocks/$block_name/style-editor.css";
312 if ( file_exists( gutenberg_dir_path() . $editor_style_path ) ) {
313 wp_deregister_style( "wp-block-{$block_name}-editor" );
314 wp_register_style(
315 "wp-block-{$block_name}-editor",
316 gutenberg_url( $editor_style_path ),
317 array(),
318 $default_version
319 );
320 wp_style_add_data( "wp-block-{$block_name}-editor", 'rtl', 'replace' );
321 } else {
322 wp_register_style( "wp-block-{$block_name}-editor", false );
323 }
324 }
325
326 /**
327 * Complements the implementation of block type `core/social-icon`, whether it
328 * be provided by core or the plugin, with derived block types for each
329 * "service" (WordPress, Twitter, etc.) supported by Social Links.
330 *
331 * This ensures backwards compatibility for any users running the Gutenberg
332 * plugin who have used Social Links prior to their conversion to block
333 * variations.
334 *
335 * This shim is INTENTIONALLY left out of core, as Social Links have never
336 * landed there.
337 *
338 * @see https://github.com/WordPress/gutenberg/pull/19887
339 */
340 function gutenberg_register_legacy_social_link_blocks() {
341 $services = array(
342 'amazon',
343 'bandcamp',
344 'behance',
345 'chain',
346 'codepen',
347 'deviantart',
348 'dribbble',
349 'dropbox',
350 'etsy',
351 'facebook',
352 'feed',
353 'fivehundredpx',
354 'flickr',
355 'foursquare',
356 'goodreads',
357 'google',
358 'github',
359 'instagram',
360 'lastfm',
361 'linkedin',
362 'mail',
363 'mastodon',
364 'meetup',
365 'medium',
366 'pinterest',
367 'pocket',
368 'reddit',
369 'skype',
370 'snapchat',
371 'soundcloud',
372 'spotify',
373 'tumblr',
374 'twitch',
375 'twitter',
376 'vimeo',
377 'vk',
378 'wordpress',
379 'yelp',
380 'youtube',
381 );
382
383 foreach ( $services as $service ) {
384 register_block_type(
385 'core/social-link-' . $service,
386 array(
387 'category' => 'widgets',
388 'attributes' => array(
389 'url' => array(
390 'type' => 'string',
391 ),
392 'service' => array(
393 'type' => 'string',
394 'default' => $service,
395 ),
396 'label' => array(
397 'type' => 'string',
398 ),
399 ),
400 'render_callback' => 'gutenberg_render_block_core_social_link',
401 )
402 );
403 }
404 }
405
406 add_action( 'init', 'gutenberg_register_legacy_social_link_blocks' );
407
408 /**
409 * Migrate the legacy `sync_status` meta key (added 16.1) to the new `wp_pattern_sync_status` meta key (16.1.1).
410 *
411 * This filter is INTENTIONALLY left out of core as the meta key was fist introduced to core in 6.3 as `wp_pattern_sync_status`.
412 * see https://github.com/WordPress/gutenberg/pull/52232
413 *
414 * @param mixed $value The value to return, either a single metadata value or an array of values depending on the value of $single.
415 * @param int $object_id ID of the object metadata is for.
416 * @param string $meta_key Metadata key.
417 * @param bool $single Whether to return only the first value of the specified $meta_key.
418 */
419 function gutenberg_legacy_wp_block_post_meta( $value, $object_id, $meta_key, $single ) {
420 if ( 'wp_pattern_sync_status' !== $meta_key ) {
421 return $value;
422 }
423
424 $sync_status = get_post_meta( $object_id, 'sync_status', $single );
425
426 if ( $single && 'unsynced' === $sync_status ) {
427 return $sync_status;
428 } elseif ( isset( $sync_status[0] ) && 'unsynced' === $sync_status[0] ) {
429 return $sync_status;
430 }
431
432 return $value;
433 }
434
435 add_filter( 'default_post_metadata', 'gutenberg_legacy_wp_block_post_meta', 10, 4 );
436
437 /**
438 * Complements the lightbox implementation for the 'core/image' block.
439 *
440 * This function is INTENTIONALLY left out of core as it only provides
441 * backwards compatibility for the legacy lightbox syntax that was only
442 * introduced in Gutenberg. The legacy syntax was using the `behaviors` key in
443 * the block attrbutes and the `theme.json` file.
444 *
445 * @since 16.7.0
446 *
447 * @param array $block The block to check.
448 * @return array The block with the legacyLightboxSettings set if available.
449 */
450 function gutenberg_should_render_lightbox( $block ) {
451
452 if ( 'core/image' !== $block['blockName'] ) {
453 return $block;
454 }
455
456 if ( isset( $block['attrs']['behaviors']['lightbox'] ) ) {
457 $block['legacyLightboxSettings'] = $block['attrs']['behaviors']['lightbox'];
458 }
459
460 return $block;
461 }
462
463 add_filter( 'render_block_data', 'gutenberg_should_render_lightbox', 15, 1 );
464