PluginProbe ʕ •ᴥ•ʔ
Widget Options – Advanced Conditional Visibility for Gutenberg Blocks & Classic Widgets / 4.0.5
Widget Options – Advanced Conditional Visibility for Gutenberg Blocks & Classic Widgets v4.0.5
4.2.5 4.2.4 trunk 3.7.10 3.7.11 3.7.12 3.7.13 3.7.14 3.7.2 3.7.5 3.7.6 3.7.7 3.7.8 3.7.9 3.8 3.8.1 3.8.10 3.8.2 3.8.3 3.8.4 3.8.5 3.8.6 3.8.7 3.8.8 3.8.9 3.8.9.1 3.9.0 3.9.1 3.9.2 3.9.3 3.9.4 3.9.5 3.9.6 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.0.5 4.0.5.1 4.0.6 4.0.6.1 4.0.7 4.0.8 4.0.9 4.1.0 4.1.1 4.1.2 4.1.3 4.2.0 4.2.1 4.2.2 4.2.3
widget-options / includes / widgets / gutenberg / lib / experimental / navigation-theme-opt-in.php
widget-options / includes / widgets / gutenberg / lib / experimental Last commit date
fonts-api 2 years ago interactivity-api 2 years ago block-editor-settings-mobile.php 2 years ago block-editor-settings.php 2 years ago blocks.php 2 years ago class-gutenberg-rest-global-styles-revisions-controller.php 2 years ago class-wp-classic-to-block-menu-converter.php 2 years ago class-wp-navigation-fallback-gutenberg.php 2 years ago class-wp-rest-block-editor-settings-controller.php 2 years ago class-wp-rest-customizer-nonces.php 2 years ago class-wp-rest-navigation-fallback-controller.php 2 years ago editor-settings.php 2 years ago kses.php 2 years ago l10n.php 2 years ago navigation-fallback.php 2 years ago navigation-theme-opt-in.php 2 years ago rest-api.php 2 years ago
navigation-theme-opt-in.php
387 lines
1 <?php
2 /**
3 * Extend WordPress core's rendering of menus to support block-based menus.
4 *
5 * @package gutenberg
6 */
7
8 /**
9 * Shim that hooks into `wp_update_nav_menu_item` and makes it so that nav menu
10 * items support a 'content' field. This field contains HTML and is used by nav
11 * menu items with `type` set to `'block'`.
12 *
13 * Specifically, this shim makes it so that:
14 *
15 * 1) The `wp_update_nav_menu_item()` function supports setting
16 * `'menu-item-content'` on a menu item. When merged to Core, this functionality
17 * should exist in `wp_update_nav_menu_item()`.
18 *
19 * 2) Updating a menu via nav-menus.php supports setting `'menu-item-content'`
20 * on a menu item. When merged to Core, this functionality should exist in
21 * `wp_nav_menu_update_menu_items()`.
22 *
23 * 3) The `customize_save` ajax action supports setting `'content'` on a nav
24 * menu item. When merged to Core, this functionality should exist in
25 * `WP_Customize_Manager::save()`.
26 *
27 * This shim can be removed when the Gutenberg plugin requires a WordPress
28 * version that has the ticket below.
29 *
30 * @see https://core.trac.wordpress.org/ticket/50544
31 *
32 * @param int $menu_id ID of the updated menu.
33 * @param int $menu_item_db_id ID of the new menu item.
34 * @param array $args An array of arguments used to update/add the menu item.
35 */
36 function gutenberg_update_nav_menu_item_content( $menu_id, $menu_item_db_id, $args ) {
37 global $wp_customize;
38
39 // Support setting content in nav-menus.php by grabbing the value from
40 // $_POST. This belongs in `wp_nav_menu_update_menu_items()`.
41 if ( isset( $_POST['menu-item-content'][ $menu_item_db_id ] ) ) {
42 $args['menu-item-content'] = wp_unslash( $_POST['menu-item-content'][ $menu_item_db_id ] );
43 }
44
45 // Support setting content in customize_save admin-ajax.php requests by
46 // grabbing the unsanitized $_POST values. This belongs in
47 // `WP_Customize_Manager::save()`.
48 if ( isset( $wp_customize ) ) {
49 $values = $wp_customize->unsanitized_post_values();
50 if ( isset( $values[ "nav_menu_item[$menu_item_db_id]" ]['content'] ) ) {
51 if ( is_string( $values[ "nav_menu_item[$menu_item_db_id]" ]['content'] ) ) {
52 $args['menu-item-content'] = $values[ "nav_menu_item[$menu_item_db_id]" ]['content'];
53 } elseif ( isset( $values[ "nav_menu_item[$menu_item_db_id]" ]['content']['raw'] ) ) {
54 $args['menu-item-content'] = $values[ "nav_menu_item[$menu_item_db_id]" ]['content']['raw'];
55 }
56 }
57 }
58
59 // Everything else belongs in `wp_update_nav_menu_item()`.
60
61 $defaults = array(
62 'menu-item-content' => '',
63 );
64
65 $args = wp_parse_args( $args, $defaults );
66
67 update_post_meta( $menu_item_db_id, '_menu_item_content', wp_slash( $args['menu-item-content'] ) );
68 }
69 add_action( 'wp_update_nav_menu_item', 'gutenberg_update_nav_menu_item_content', 10, 3 );
70
71 /**
72 * Shim that hooks into `wp_setup_nav_menu_items` and makes it so that nav menu
73 * items have a 'content' field. This field contains HTML and is used by nav
74 * menu items with `type` set to `'block'`.
75 *
76 * Specifically, this shim makes it so that the `wp_setup_nav_menu_item()`
77 * function sets `content` on the returned menu item. When merged to Core, this
78 * functionality should exist in `wp_setup_nav_menu_item()`.
79 *
80 * This shim can be removed when the Gutenberg plugin requires a WordPress
81 * version that has the ticket below.
82 *
83 * @see https://core.trac.wordpress.org/ticket/50544
84 *
85 * @param object $menu_item The menu item object.
86 *
87 * @return object Updated menu item object.
88 */
89 function gutenberg_setup_block_nav_menu_item( $menu_item ) {
90 if ( 'block' === $menu_item->type ) {
91 $menu_item->type_label = __( 'Block', 'gutenberg' );
92 $menu_item->content = ! isset( $menu_item->content ) ? get_post_meta( $menu_item->db_id, '_menu_item_content', true ) : $menu_item->content;
93
94 // Set to make the menu item display nicely in nav-menus.php.
95 $menu_item->object = 'block';
96 $menu_item->title = __( 'Block', 'gutenberg' );
97 }
98
99 return $menu_item;
100 }
101 add_filter( 'wp_setup_nav_menu_item', 'gutenberg_setup_block_nav_menu_item' );
102
103 /**
104 * Shim that hooks into `walker_nav_menu_start_el` and makes it so that the
105 * default walker which renders a menu will correctly render the HTML associated
106 * with any navigation menu item that has `type` set to `'block`'.
107 *
108 * Specifically, this shim makes it so that `Walker_Nav_Menu::start_el()`
109 * renders the `content` of a nav menu item when its `type` is `'block'`. When
110 * merged to Core, this functionality should exist in
111 * `Walker_Nav_Menu::start_el()`.
112 *
113 * This shim can be removed when the Gutenberg plugin requires a WordPress
114 * version that has the ticket below.
115 *
116 * @see https://core.trac.wordpress.org/ticket/50544
117 *
118 * @param string $item_output The menu item's starting HTML output.
119 * @param WP_Post $item Menu item data object.
120 * @param int $depth Depth of menu item. Used for padding.
121 * @param stdClass $args An object of wp_nav_menu() arguments.
122 *
123 * @return string The menu item's updated HTML output.
124 */
125 function gutenberg_output_block_nav_menu_item( $item_output, $item, $depth, $args ) {
126 if ( 'block' === $item->type ) {
127 $item_output = $args->before;
128 /** This filter is documented in wp-includes/post-template.php */
129 $item_output .= apply_filters( 'the_content', $item->content );
130 $item_output .= $args->after;
131 }
132
133 return $item_output;
134 }
135 add_filter( 'walker_nav_menu_start_el', 'gutenberg_output_block_nav_menu_item', 10, 4 );
136
137 /**
138 * Shim that prevents menu items with type `'block'` from being rendered in the
139 * frontend when the theme does not support block menus.
140 *
141 * Specifically, this shim makes it so that `wp_nav_menu()` will remove any menu
142 * items that have a `type` of `'block'` from `$sorted_menu_items`. When merged
143 * to Core, this functionality should exist in `wp_nav_menu()`.
144 *
145 * This shim can be removed when the Gutenberg plugin requires a WordPress
146 * version that has the ticket below.
147 *
148 * @see https://core.trac.wordpress.org/ticket/50544
149 *
150 * @param array $menu_items The menu items, sorted by each menu item's menu order.
151 *
152 * @return array Updated menu items, sorted by each menu item's menu order.
153 */
154 function gutenberg_remove_block_nav_menu_items( $menu_items ) {
155 // We should uncomment the line below when the block-nav-menus feature becomes stable.
156 // @see https://github.com/WordPress/gutenberg/issues/34265.
157 /*if ( current_theme_supports( 'block-nav-menus' ) ) {*/
158 if ( false ) {
159 return $menu_items;
160 }
161
162 return array_filter(
163 $menu_items,
164 function( $menu_item ) {
165 return 'block' !== $menu_item->type;
166 }
167 );
168 }
169 add_filter( 'wp_nav_menu_objects', 'gutenberg_remove_block_nav_menu_items', 10 );
170
171 /**
172 * Recursively converts a list of menu items into a list of blocks. This is a
173 * helper function used by `gutenberg_output_block_nav_menu()`.
174 *
175 * Transformation depends on the menu item type. Link menu items are turned into
176 * a `core/navigation-link` block. Block menu items are simply parsed.
177 *
178 * @param array $menu_items The menu items to convert, sorted by each menu item's menu order.
179 * @param array $menu_items_by_parent_id All menu items, indexed by their parent's ID.
180
181 * @return array Updated menu items, sorted by each menu item's menu order.
182 */
183 function gutenberg_convert_menu_items_to_blocks(
184 $menu_items,
185 &$menu_items_by_parent_id
186 ) {
187 if ( empty( $menu_items ) ) {
188 return array();
189 }
190
191 $blocks = array();
192
193 foreach ( $menu_items as $menu_item ) {
194 if ( 'block' === $menu_item->type ) {
195 $parsed_blocks = parse_blocks( $menu_item->content );
196
197 if ( count( $parsed_blocks ) ) {
198 $block = $parsed_blocks[0];
199 } else {
200 $block = array(
201 'blockName' => 'core/freeform',
202 'attrs' => array(
203 'originalContent' => $menu_item->content,
204 ),
205 );
206 }
207 } else {
208 $block = array(
209 'blockName' => 'core/navigation-link',
210 'attrs' => array(
211 'label' => $menu_item->title,
212 'url' => $menu_item->url,
213 ),
214 );
215 }
216
217 $block['innerBlocks'] = gutenberg_convert_menu_items_to_blocks(
218 isset( $menu_items_by_parent_id[ $menu_item->ID ] )
219 ? $menu_items_by_parent_id[ $menu_item->ID ]
220 : array(),
221 $menu_items_by_parent_id
222 );
223
224 $blocks[] = $block;
225 }
226
227 return $blocks;
228 }
229
230 /**
231 * Shim that causes `wp_nav_menu()` to output a Navigation block instead of a
232 * nav menu when the theme supports block menus. The Navigation block is
233 * constructed by transforming the stored tree of menu items into a tree of
234 * blocks.
235 *
236 * Specifically, this shim makes it so that `wp_nav_menu()` returns early when
237 * the theme supports block menus. When merged to Core, this functionality
238 * should exist in `wp_nav_menu()` after `$sorted_menu_items` is set. The
239 * duplicated code (marked using BEGIN and END) can be deleted.
240 *
241 * This shim can be removed when the Gutenberg plugin requires a WordPress
242 * version that has the ticket below.
243 *
244 * @see https://core.trac.wordpress.org/ticket/50544
245 *
246 * @param string|null $output Nav menu output to short-circuit with. Default null.
247 * @param stdClass $args An object containing wp_nav_menu() arguments.
248 *
249 * @return string|null Nav menu output to short-circuit with.
250 */
251 function gutenberg_output_block_nav_menu( $output, $args ) {
252 // We should uncomment the line below when the block-nav-menus feature becomes stable.
253 // @see https://github.com/WordPress/gutenberg/issues/34265.
254 /*if ( ! current_theme_supports( 'block-nav-menus' ) ) {*/
255 if ( true ) {
256 return null;
257 }
258
259 // BEGIN: Code that already exists in wp_nav_menu().
260
261 // Get the nav menu based on the requested menu.
262 $menu = wp_get_nav_menu_object( $args->menu );
263
264 // Get the nav menu based on the theme_location.
265 $locations = get_nav_menu_locations();
266 if ( ! $menu && $args->theme_location && $locations && isset( $locations[ $args->theme_location ] ) ) {
267 $menu = wp_get_nav_menu_object( $locations[ $args->theme_location ] );
268 }
269
270 // Get the first menu that has items if we still can't find a menu.
271 if ( ! $menu && ! $args->theme_location ) {
272 $menus = wp_get_nav_menus();
273 foreach ( $menus as $menu_maybe ) {
274 $menu_items = wp_get_nav_menu_items( $menu_maybe->term_id, array( 'update_post_term_cache' => false ) );
275 if ( $menu_items ) {
276 $menu = $menu_maybe;
277 break;
278 }
279 }
280 }
281
282 if ( empty( $args->menu ) ) {
283 $args->menu = $menu;
284 }
285
286 // If the menu exists, get its items.
287 if ( $menu && ! is_wp_error( $menu ) && ! isset( $menu_items ) ) {
288 $menu_items = wp_get_nav_menu_items( $menu->term_id, array( 'update_post_term_cache' => false ) );
289 }
290
291 // Set up the $menu_item variables.
292 _wp_menu_item_classes_by_context( $menu_items );
293
294 $sorted_menu_items = array();
295 foreach ( (array) $menu_items as $menu_item ) {
296 $sorted_menu_items[ $menu_item->menu_order ] = $menu_item;
297 }
298
299 unset( $menu_items, $menu_item );
300
301 // END: Code that already exists in wp_nav_menu().
302
303 $menu_items_by_parent_id = array();
304 foreach ( $sorted_menu_items as $menu_item ) {
305 $menu_items_by_parent_id[ $menu_item->menu_item_parent ][] = $menu_item;
306 }
307
308 $block_attributes = array();
309 if ( isset( $args->block_attributes ) ) {
310 $block_attributes = $args->block_attributes;
311 }
312
313 $navigation_block = array(
314 'blockName' => 'core/navigation',
315 'attrs' => $block_attributes,
316 'innerBlocks' => gutenberg_convert_menu_items_to_blocks(
317 isset( $menu_items_by_parent_id[0] )
318 ? $menu_items_by_parent_id[0]
319 : array(),
320 $menu_items_by_parent_id
321 ),
322 );
323
324 return render_block( $navigation_block );
325 }
326 add_filter( 'pre_wp_nav_menu', 'gutenberg_output_block_nav_menu', 10, 2 );
327
328 /**
329 * Shim that makes nav-menus.php nicely display a menu item with its `type` set to
330 * `'block'`.
331 *
332 * Specifically, this shim makes it so that `Walker_Nav_Menu_Edit::start_el()`
333 * outputs extra form fields. When merged to Core, this markup should exist in
334 * `Walker_Nav_Menu_Edit::start_el()`.
335 *
336 * This shim can be removed when the Gutenberg plugin requires a WordPress
337 * version that has the ticket below.
338 *
339 * @see https://core.trac.wordpress.org/ticket/50544
340 *
341 * @param int $item_id Menu item ID.
342 * @param WP_Post $item Menu item data object.
343 */
344 function gutenberg_output_block_menu_item_custom_fields( $item_id, $item ) {
345 if ( 'block' === $item->type ) {
346 ?>
347 <p class="field-content description description-wide">
348 <label for="edit-menu-item-content-<?php echo $item_id; ?>">
349 <?php _e( 'Content', 'gutenberg' ); ?><br />
350 <textarea id="edit-menu-item-content-<?php echo $item_id; ?>" class="widefat" rows="3" cols="20" name="menu-item-content[<?php echo $item_id; ?>]" readonly><?php echo esc_textarea( trim( $item->content ) ); ?></textarea>
351 </label>
352 </p>
353 <?php
354 }
355 }
356 add_action( 'wp_nav_menu_item_custom_fields', 'gutenberg_output_block_menu_item_custom_fields', 10, 2 );
357
358 /**
359 * Shim that adds extra styling to nav-menus.php. This lets us style menu items
360 * that have a `type` set to `'block'`. When merged to Core, this CSS should be
361 * moved to nav-menus.css.
362 *
363 * This shim can be removed when the Gutenberg plugin requires a WordPress
364 * version that has the ticket below.
365 *
366 * @see https://core.trac.wordpress.org/ticket/50544
367 *
368 * @param string $hook The current admin page.
369 */
370 function gutenberg_add_block_menu_item_styles_to_nav_menus( $hook ) {
371 if ( 'nav-menus.php' === $hook ) {
372 $css = <<<CSS
373 /**
374 * HACK: We're hiding the description field using CSS because this
375 * cannot be done using a filter. When merged to Core, we should
376 * actually remove the field from
377 * `Walker_Nav_Menu_Edit::start_el()`.
378 */
379 .menu-item-block .description:not(.field-content) {
380 display: none;
381 }
382 CSS;
383 wp_add_inline_style( 'nav-menus', $css );
384 }
385 }
386 add_action( 'admin_enqueue_scripts', 'gutenberg_add_block_menu_item_styles_to_nav_menus' );
387