PluginProbe
Gutenberg / 8.5.1
Gutenberg v8.5.1
24.0.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 All 403 releases
← All changes | lib/compat.php +536 -46 12.6.0 → 8.5.1 View file →
@@ -8,73 +8,563 @@
8 8 * @package gutenberg
9 9 */
10 10
11 11 /**
12 - * Update allowed inline style attributes list.
12 + * These functions can be removed when plugin support requires WordPress 5.5.0+.
13 13 *
14 - * Note: This should be removed when the minimum required WP version is >= 5.9.
14 + * @see https://core.trac.wordpress.org/ticket/50263
15 + * @see https://core.trac.wordpress.org/changeset/48141
16 + */
17 +if ( ! function_exists( 'register_block_type_from_metadata' ) ) {
18 + /**
19 + * Removes the block asset's path prefix if provided.
20 + *
21 + * @since 5.5.0
22 + *
23 + * @param string $asset_handle_or_path Asset handle or prefixed path.
24 + *
25 + * @return string Path without the prefix or the original value.
26 + */
27 + function remove_block_asset_path_prefix( $asset_handle_or_path ) {
28 + $path_prefix = 'file:';
29 + if ( strpos( $asset_handle_or_path, $path_prefix ) !== 0 ) {
30 + return $asset_handle_or_path;
31 + }
32 + return substr(
33 + $asset_handle_or_path,
34 + strlen( $path_prefix )
35 + );
36 + }
37 +
38 + /**
39 + * Generates the name for an asset based on the name of the block
40 + * and the field name provided.
41 + *
42 + * @since 5.5.0
43 + *
44 + * @param string $block_name Name of the block.
45 + * @param string $field_name Name of the metadata field.
46 + *
47 + * @return string Generated asset name for the block's field.
48 + */
49 + function generate_block_asset_handle( $block_name, $field_name ) {
50 + $field_mappings = array(
51 + 'editorScript' => 'editor-script',
52 + 'script' => 'script',
53 + 'editorStyle' => 'editor-style',
54 + 'style' => 'style',
55 + );
56 + return str_replace( '/', '-', $block_name ) .
57 + '-' . $field_mappings[ $field_name ];
58 + }
59 +
60 + /**
61 + * Finds a script handle for the selected block metadata field. It detects
62 + * when a path to file was provided and finds a corresponding
63 + * asset file with details necessary to register the script under
64 + * automatically generated handle name. It returns unprocessed script handle
65 + * otherwise.
66 + *
67 + * @since 5.5.0
68 + *
69 + * @param array $metadata Block metadata.
70 + * @param string $field_name Field name to pick from metadata.
71 + *
72 + * @return string|boolean Script handle provided directly or created through
73 + * script's registration, or false on failure.
74 + */
75 + function register_block_script_handle( $metadata, $field_name ) {
76 + if ( empty( $metadata[ $field_name ] ) ) {
77 + return false;
78 + }
79 + $script_handle = $metadata[ $field_name ];
80 + $script_path = remove_block_asset_path_prefix( $metadata[ $field_name ] );
81 + if ( $script_handle === $script_path ) {
82 + return $script_handle;
83 + }
84 +
85 + $script_handle = generate_block_asset_handle( $metadata['name'], $field_name );
86 + $script_asset_path = realpath(
87 + dirname( $metadata['file'] ) . '/' .
88 + substr_replace( $script_path, '.asset.php', - strlen( '.js' ) )
89 + );
90 + if ( ! file_exists( $script_asset_path ) ) {
91 + $message = sprintf(
92 + /* translators: %1: field name. %2: block name */
93 + __( 'The asset file for the "%1$s" defined in "%2$s" block definition is missing.', 'default' ),
94 + $field_name,
95 + $metadata['name']
96 + );
97 + _doing_it_wrong( __FUNCTION__, $message, '5.5.0' );
98 + return false;
99 + }
100 + $script_asset = require( $script_asset_path );
101 + $result = wp_register_script(
102 + $script_handle,
103 + plugins_url( $script_path, $metadata['file'] ),
104 + $script_asset['dependencies'],
105 + $script_asset['version']
106 + );
107 + return $result ? $script_handle : false;
108 + }
109 +
110 + /**
111 + * Finds a style handle for the block metadata field. It detects when a path
112 + * to file was provided and registers the style under automatically
113 + * generated handle name. It returns unprocessed style handle otherwise.
114 + *
115 + * @since 5.5.0
116 + *
117 + * @param array $metadata Block metadata.
118 + * @param string $field_name Field name to pick from metadata.
119 + *
120 + * @return string|boolean Style handle provided directly or created through
121 + * style's registration, or false on failure.
122 + */
123 + function register_block_style_handle( $metadata, $field_name ) {
124 + if ( empty( $metadata[ $field_name ] ) ) {
125 + return false;
126 + }
127 + $style_handle = $metadata[ $field_name ];
128 + $style_path = remove_block_asset_path_prefix( $metadata[ $field_name ] );
129 + if ( $style_handle === $style_path ) {
130 + return $style_handle;
131 + }
132 +
133 + $style_handle = generate_block_asset_handle( $metadata['name'], $field_name );
134 + $block_dir = dirname( $metadata['file'] );
135 + $result = wp_register_style(
136 + $style_handle,
137 + plugins_url( $style_path, $metadata['file'] ),
138 + array(),
139 + filemtime( realpath( "$block_dir/$style_path" ) )
140 + );
141 + return $result ? $style_handle : false;
142 + }
143 +
144 + /**
145 + * Registers a block type from metadata stored in the `block.json` file.
146 + *
147 + * @since 7.9.0
148 + *
149 + * @param string $file_or_folder Path to the JSON file with metadata definition for
150 + * the block or path to the folder where the `block.json` file is located.
151 + * @param array $args {
152 + * Optional. Array of block type arguments. Any arguments may be defined, however the
153 + * ones described below are supported by default. Default empty array.
154 + *
155 + * @type callable $render_callback Callback used to render blocks of this block type.
156 + * }
157 + * @return WP_Block_Type|false The registered block type on success, or false on failure.
158 + */
159 + function register_block_type_from_metadata( $file_or_folder, $args = array() ) {
160 + $filename = 'block.json';
161 + $metadata_file = ( substr( $file_or_folder, -strlen( $filename ) ) !== $filename ) ?
162 + trailingslashit( $file_or_folder ) . $filename :
163 + $file_or_folder;
164 + if ( ! file_exists( $metadata_file ) ) {
165 + return false;
166 + }
167 +
168 + $metadata = json_decode( file_get_contents( $metadata_file ), true );
169 + if ( ! is_array( $metadata ) || empty( $metadata['name'] ) ) {
170 + return false;
171 + }
172 + $metadata['file'] = $metadata_file;
173 +
174 + $settings = array();
175 + $property_mappings = array(
176 + 'title' => 'title',
177 + 'category' => 'category',
178 + 'parent' => 'parent',
179 + 'icon' => 'icon',
180 + 'description' => 'description',
181 + 'keywords' => 'keywords',
182 + 'attributes' => 'attributes',
183 + 'providesContext' => 'provides_context',
184 + 'usesContext' => 'uses_context',
185 + // Deprecated: remove with Gutenberg 8.6 release.
186 + 'context' => 'context',
187 + 'supports' => 'supports',
188 + 'styles' => 'styles',
189 + 'example' => 'example',
190 + );
191 +
192 + foreach ( $property_mappings as $key => $mapped_key ) {
193 + if ( isset( $metadata[ $key ] ) ) {
194 + $settings[ $mapped_key ] = $metadata[ $key ];
195 + }
196 + }
197 +
198 + if ( ! empty( $metadata['editorScript'] ) ) {
199 + $settings['editor_script'] = register_block_script_handle(
200 + $metadata,
201 + 'editorScript'
202 + );
203 + }
204 +
205 + if ( ! empty( $metadata['script'] ) ) {
206 + $settings['script'] = register_block_script_handle(
207 + $metadata,
208 + 'script'
209 + );
210 + }
211 +
212 + if ( ! empty( $metadata['editorStyle'] ) ) {
213 + $settings['editor_style'] = register_block_style_handle(
214 + $metadata,
215 + 'editorStyle'
216 + );
217 + }
218 +
219 + if ( ! empty( $metadata['style'] ) ) {
220 + $settings['style'] = register_block_style_handle(
221 + $metadata,
222 + 'style'
223 + );
224 + }
225 +
226 + return register_block_type(
227 + $metadata['name'],
228 + array_merge(
229 + $settings,
230 + $args
231 + )
232 + );
233 + }
234 +}
235 +
236 +/**
237 + * Extends block editor settings to include a list of image dimensions per size.
15 238 *
16 - * @param string[] $attrs Array of allowed CSS attributes.
17 - * @return string[] CSS attributes.
239 + * This can be removed when plugin support requires WordPress 5.4.0+.
240 + *
241 + * @see https://core.trac.wordpress.org/ticket/49389
242 + * @see https://core.trac.wordpress.org/changeset/47240
243 + *
244 + * @param array $settings Default editor settings.
245 + *
246 + * @return array Filtered editor settings.
18 247 */
19 -function gutenberg_safe_style_attrs( $attrs ) {
20 - $attrs[] = 'object-position';
21 - $attrs[] = 'border-top-left-radius';
22 - $attrs[] = 'border-top-right-radius';
23 - $attrs[] = 'border-bottom-right-radius';
24 - $attrs[] = 'border-bottom-left-radius';
25 - $attrs[] = 'filter';
248 +function gutenberg_extend_settings_image_dimensions( $settings ) {
249 + /*
250 + * Only filter settings if:
251 + * 1. `imageDimensions` is not already assigned, in which case it can be
252 + * assumed to have been set from WordPress 5.4.0+ default settings.
253 + * 2. `imageSizes` is an array. Plugins may run `block_editor_settings`
254 + * directly and not provide all properties of the settings array.
255 + */
256 + if ( ! isset( $settings['imageDimensions'] ) && ! empty( $settings['imageSizes'] ) ) {
257 + $image_dimensions = array();
258 + $all_sizes = wp_get_registered_image_subsizes();
259 + foreach ( $settings['imageSizes'] as $size ) {
260 + $key = $size['slug'];
261 + if ( isset( $all_sizes[ $key ] ) ) {
262 + $image_dimensions[ $key ] = $all_sizes[ $key ];
263 + }
264 + }
265 + $settings['imageDimensions'] = $image_dimensions;
266 + }
26 267
27 - return $attrs;
268 + return $settings;
28 269 }
29 -add_filter( 'safe_style_css', 'gutenberg_safe_style_attrs' );
270 +add_filter( 'block_editor_settings', 'gutenberg_extend_settings_image_dimensions' );
30 271
31 272 /**
32 - * The new gallery block format is not compatible with the use_BalanceTags option
33 - * in WP versions <= 5.8 https://core.trac.wordpress.org/ticket/54130.
34 - * This method adds a variable to the wp namespace to indicate if the new gallery block
35 - * format can be enabled or not. It needs to be added this early and to the wp namespace
36 - * as it needs to be available when the initial block parsing runs on editor load, and most of
37 - * the editor store and standard flags are not loaded yet at that point
273 + * Adds a polyfill for the WHATWG URL in environments which do not support it.
274 + * The intention in how this action is handled is under the assumption that this
275 + * code would eventually be placed at `wp_default_packages_vendor`, which is
276 + * called as a result of `wp_default_packages` via the `wp_default_scripts`.
38 277 *
39 - * @since 12.1.0
40 - * @todo This should be removed when the minimum required WP version is >= 5.9.
278 + * This can be removed when plugin support requires WordPress 5.4.0+.
41 279 *
42 - * @return void.
280 + * The script registration occurs in `gutenberg_register_vendor_scripts`, which
281 + * should be removed in coordination with this function.
282 + *
283 + * @see gutenberg_register_vendor_scripts
284 + * @see https://core.trac.wordpress.org/ticket/49360
285 + * @see https://developer.mozilla.org/en-US/docs/Web/API/URL/URL
286 + * @see https://developer.wordpress.org/reference/functions/wp_default_packages_vendor/
287 + *
288 + * @since 7.3.0
289 + *
290 + * @param WP_Scripts $scripts WP_Scripts object.
43 291 */
44 -function gutenberg_check_gallery_block_v2_compatibility() {
45 - $use_balance_tags = (int) get_option( 'use_balanceTags' );
46 - $v2_gallery_enabled = boolval( 1 !== $use_balance_tags || is_wp_version_compatible( '5.9' ) ) ? 'true' : 'false';
292 +function gutenberg_add_url_polyfill( $scripts ) {
293 + did_action( 'init' ) && $scripts->add_inline_script(
294 + 'wp-polyfill',
295 + wp_get_script_polyfill(
296 + $scripts,
297 + array(
298 + 'window.URL && window.URL.prototype && window.URLSearchParams' => 'wp-polyfill-url',
299 + )
300 + )
301 + );
302 +}
303 +add_action( 'wp_default_scripts', 'gutenberg_add_url_polyfill', 20 );
47 304
48 - wp_add_inline_script(
49 - 'wp-dom-ready',
50 - 'wp.galleryBlockV2Enabled = ' . $v2_gallery_enabled . ';',
51 - 'after'
305 +/**
306 + * Adds a polyfill for DOMRect in environments which do not support it.
307 + *
308 + * This can be removed when plugin support requires WordPress 5.4.0+.
309 + *
310 + * The script registration occurs in `gutenberg_register_vendor_scripts`, which
311 + * should be removed in coordination with this function.
312 + *
313 + * @see gutenberg_register_vendor_scripts
314 + * @see gutenberg_add_url_polyfill
315 + * @see https://core.trac.wordpress.org/ticket/49360
316 + * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMRect
317 + * @see https://developer.wordpress.org/reference/functions/wp_default_packages_vendor/
318 + *
319 + * @since 7.5.0
320 + *
321 + * @param WP_Scripts $scripts WP_Scripts object.
322 + */
323 +function gutenberg_add_dom_rect_polyfill( $scripts ) {
324 + did_action( 'init' ) && $scripts->add_inline_script(
325 + 'wp-polyfill',
326 + wp_get_script_polyfill(
327 + $scripts,
328 + array(
329 + 'window.DOMRect' => 'wp-polyfill-dom-rect',
330 + )
331 + )
52 332 );
53 333 }
54 -add_action( 'init', 'gutenberg_check_gallery_block_v2_compatibility' );
334 +add_action( 'wp_default_scripts', 'gutenberg_add_dom_rect_polyfill', 20 );
55 335
56 336 /**
57 - * Prevent use_balanceTags being enabled on WordPress 5.8 or earlier as it breaks
58 - * the layout of the new Gallery block.
337 + * Filters default block categories to substitute legacy category names with new
338 + * block categories.
59 339 *
60 - * @since 12.1.0
61 - * @todo This should be removed when the minimum required WP version is >= 5.9.
340 + * This can be removed when plugin support requires WordPress 5.5.0+.
62 341 *
63 - * @param int $new_value The new value for use_balanceTags.
342 + * @see https://core.trac.wordpress.org/ticket/50278
343 + * @see https://core.trac.wordpress.org/changeset/48177
344 + *
345 + * @param array[] $default_categories Array of block categories.
346 + *
347 + * @return array[] Filtered block categories.
64 348 */
65 -function gutenberg_use_balancetags_check( $new_value ) {
66 - global $wp_version;
349 +function gutenberg_replace_default_block_categories( $default_categories ) {
350 + $substitution = array(
351 + 'common' => array(
352 + 'slug' => 'text',
353 + 'title' => __( 'Text', 'gutenberg' ),
354 + 'icon' => null,
355 + ),
356 + 'formatting' => array(
357 + 'slug' => 'media',
358 + 'title' => __( 'Media', 'gutenberg' ),
359 + 'icon' => null,
360 + ),
361 + 'layout' => array(
362 + 'slug' => 'design',
363 + 'title' => __( 'Design', 'gutenberg' ),
364 + 'icon' => null,
365 + ),
366 + );
67 367
68 - if ( 1 === (int) $new_value && version_compare( $wp_version, '5.9', '<' ) ) {
69 - /* translators: %s: Minimum required version */
70 - $message = sprintf( __( 'Gutenberg requires WordPress %s or later in order to enable the &#8220;Correct invalidly nested XHTML automatically&#8221; option. Please upgrade WordPress before enabling.', 'gutenberg' ), '5.9' );
71 - add_settings_error( 'gutenberg_use_balancetags_check', 'gutenberg_use_balancetags_check', $message, 'error' );
72 - if ( class_exists( 'WP_CLI' ) ) {
73 - WP_CLI::error( $message );
368 + // Loop default categories to perform in-place substitution by legacy slug.
369 + foreach ( $default_categories as $i => $default_category ) {
370 + $slug = $default_category['slug'];
371 + if ( isset( $substitution[ $slug ] ) ) {
372 + $default_categories[ $i ] = $substitution[ $slug ];
373 + unset( $substitution[ $slug ] );
74 374 }
75 - return 0;
76 375 }
77 376
78 - return $new_value;
377 + /*
378 + * At this point, `$substitution` should contain only the categories which
379 + * could not be in-place substituted with a default category, likely in the
380 + * case that core has since been updated to use the default categories.
381 + * Check to verify they exist.
382 + */
383 + $default_category_slugs = wp_list_pluck( $default_categories, 'slug' );
384 + foreach ( $substitution as $i => $substitute_category ) {
385 + if ( in_array( $substitute_category['slug'], $default_category_slugs, true ) ) {
386 + unset( $substitution[ $i ] );
387 + }
388 + }
389 +
390 + /*
391 + * Any substitutes remaining should be appended, as they are not yet
392 + * assigned in the default categories array.
393 + */
394 + return array_merge( $default_categories, array_values( $substitution ) );
79 395 }
80 -add_filter( 'pre_update_option_use_balanceTags', 'gutenberg_use_balancetags_check' );
396 +add_filter( 'block_categories', 'gutenberg_replace_default_block_categories' );
397 +
398 +/**
399 + * Shim that hooks into `pre_render_block` so as to override `render_block` with
400 + * a function that assigns block context.
401 + *
402 + * This can be removed when plugin support requires WordPress 5.5.0+.
403 + *
404 + * @see https://core.trac.wordpress.org/ticket/49927
405 + * @see https://core.trac.wordpress.org/changeset/48243
406 + *
407 + * @param string|null $pre_render The pre-rendered content. Defaults to null.
408 + * @param array $parsed_block The parsed block being rendered.
409 + *
410 + * @return string String of rendered HTML.
411 + */
412 +function gutenberg_render_block_with_assigned_block_context( $pre_render, $parsed_block ) {
413 + global $post, $wp_query;
414 +
415 + /*
416 + * If a non-null value is provided, a filter has run at an earlier priority
417 + * and has already handled custom rendering and should take precedence.
418 + */
419 + if ( null !== $pre_render ) {
420 + return $pre_render;
421 + }
422 +
423 + $source_block = $parsed_block;
424 +
425 + /** This filter is documented in src/wp-includes/blocks.php */
426 + $parsed_block = apply_filters( 'render_block_data', $parsed_block, $source_block );
427 +
428 + $context = array();
429 +
430 + if ( $post instanceof WP_Post ) {
431 + $context['postId'] = $post->ID;
432 +
433 + /*
434 + * The `postType` context is largely unnecessary server-side, since the
435 + * ID is usually sufficient on its own. That being said, since a block's
436 + * manifest is expected to be shared between the server and the client,
437 + * it should be included to consistently fulfill the expectation.
438 + */
439 + $context['postType'] = $post->post_type;
440 + }
441 +
442 + if ( isset( $wp_query->tax_query->queried_terms['category'] ) ) {
443 + $context['query'] = array( 'categoryIds' => array() );
444 +
445 + foreach ( $wp_query->tax_query->queried_terms['category']['terms'] as $category_slug_or_id ) {
446 + $context['query']['categoryIds'][] = 'slug' === $wp_query->tax_query->queried_terms['category']['field'] ? get_cat_ID( $category_slug_or_id ) : $category_slug_or_id;
447 + }
448 + }
449 +
450 + /**
451 + * Filters the default context provided to a rendered block.
452 + *
453 + * @param array $context Default context.
454 + * @param array $parsed_block Block being rendered, filtered by `render_block_data`.
455 + */
456 + $context = apply_filters( 'render_block_context', $context, $parsed_block );
457 +
458 + $block = new WP_Block( $parsed_block, $context );
459 +
460 + return $block->render();
461 +}
462 +add_filter( 'pre_render_block', 'gutenberg_render_block_with_assigned_block_context', 9, 2 );
463 +
464 +/**
465 + * Shim that hooks into `wp_update_nav_menu_item` and makes it so that nav menu
466 + * items support a 'content' field. This field contains HTML and is used by nav
467 + * menu items with `type` set to `'html'`.
468 + *
469 + * Specifically, this shim makes it so that:
470 + *
471 + * 1) The `wp_update_nav_menu_item()` function supports setting
472 + * `'menu-item-content'` on a menu item. When merged to Core, this functionality
473 + * should exist in `wp_update_nav_menu_item()`.
474 + *
475 + * 2) The `customize_save` ajax action supports setting `'content'` on a nav
476 + * menu item. When merged to Core, this functionality should exist in
477 + * `WP_Customize_Manager::save()`.
478 + *
479 + * This shim can be removed when the Gutenberg plugin requires a WordPress
480 + * version that has the ticket below.
481 + *
482 + * @see https://core.trac.wordpress.org/ticket/50544
483 + *
484 + * @param int $menu_id ID of the updated menu.
485 + * @param int $menu_item_db_id ID of the new menu item.
486 + * @param array $args An array of arguments used to update/add the menu item.
487 + */
488 +function gutenberg_update_nav_menu_item_content( $menu_id, $menu_item_db_id, $args ) {
489 + global $wp_customize;
490 +
491 + // Support setting content in customize_save admin-ajax.php requests by
492 + // grabbing the unsanitized $_POST values.
493 + if ( isset( $wp_customize ) ) {
494 + $values = $wp_customize->unsanitized_post_values();
495 + if ( isset( $values[ "nav_menu_item[$menu_item_db_id]" ]['content'] ) ) {
496 + if ( is_string( $values[ "nav_menu_item[$menu_item_db_id]" ]['content'] ) ) {
497 + $args['menu-item-content'] = $values[ "nav_menu_item[$menu_item_db_id]" ]['content'];
498 + } elseif ( isset( $values[ "nav_menu_item[$menu_item_db_id]" ]['content']['raw'] ) ) {
499 + $args['menu-item-content'] = $values[ "nav_menu_item[$menu_item_db_id]" ]['content']['raw'];
500 + }
501 + }
502 + }
503 +
504 + $defaults = array(
505 + 'menu-item-content' => '',
506 + );
507 +
508 + $args = wp_parse_args( $args, $defaults );
509 +
510 + update_post_meta( $menu_item_db_id, '_menu_item_content', wp_slash( $args['menu-item-content'] ) );
511 +}
512 +add_action( 'wp_update_nav_menu_item', 'gutenberg_update_nav_menu_item_content', 10, 3 );
513 +
514 +/**
515 + * Shim that hooks into `wp_setup_nav_menu_items` and makes it so that nav menu
516 + * items have a 'content' field. This field contains HTML and is used by nav
517 + * menu items with `type` set to `'html'`.
518 + *
519 + * Specifically, this shim makes it so that the `wp_setup_nav_menu_item()`
520 + * function sets `content` on the returned menu item. When merged to Core, this
521 + * functionality should exist in `wp_setup_nav_menu_item()`.
522 + *
523 + * This shim can be removed when the Gutenberg plugin requires a WordPress
524 + * version that has the ticket below.
525 + *
526 + * @see https://core.trac.wordpress.org/ticket/50544
527 + *
528 + * @param object $menu_item The menu item object.
529 + */
530 +function gutenberg_setup_html_nav_menu_item( $menu_item ) {
531 + if ( 'html' === $menu_item->type ) {
532 + $menu_item->type_label = __( 'HTML', 'gutenberg' );
533 + $menu_item->content = ! isset( $menu_item->content ) ? get_post_meta( $menu_item->db_id, '_menu_item_content', true ) : $menu_item->content;
534 + }
535 +
536 + return $menu_item;
537 +}
538 +add_filter( 'wp_setup_nav_menu_item', 'gutenberg_setup_html_nav_menu_item' );
539 +
540 +/**
541 + * Shim that hooks into `walker_nav_menu_start_el` and makes it so that the
542 + * default walker which renders a menu will correctly render the HTML associated
543 + * with any navigation menu item that has `type` set to `'html`'.
544 + *
545 + * Specifically, this shim makes it so that `Walker_Nav_Menu::start_el()`
546 + * renders the `content` of a nav menu item when its `type` is `'html'`. When
547 + * merged to Core, this functionality should exist in
548 + * `Walker_Nav_Menu::start_el()`.
549 + *
550 + * This shim can be removed when the Gutenberg plugin requires a WordPress
551 + * version that has the ticket below.
552 + *
553 + * @see https://core.trac.wordpress.org/ticket/50544
554 + *
555 + * @param string $item_output The menu item's starting HTML output.
556 + * @param WP_Post $item Menu item data object.
557 + * @param int $depth Depth of menu item. Used for padding.
558 + * @param stdClass $args An object of wp_nav_menu() arguments.
559 + */
560 +function gutenberg_output_html_nav_menu_item( $item_output, $item, $depth, $args ) {
561 + if ( 'html' === $item->type ) {
562 + $item_output = $args->before;
563 + /** This filter is documented in wp-includes/post-template.php */
564 + $item_output .= apply_filters( 'the_content', $item->content );
565 + $item_output .= $args->after;
566 + }
567 +
568 + return $item_output;
569 +}
570 +add_filter( 'walker_nav_menu_start_el', 'gutenberg_output_html_nav_menu_item', 10, 4 );