| @@ -5,239 +5,371 @@ | ||
| 5 | 5 | * @package gutenberg |
| 6 | 6 | */ |
| 7 | 7 | |
| 8 | 8 | /** |
| 9 | - * Registers block editor 'wp_navigation' post type. | |
| 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. | |
| 10 | 35 | */ |
| 11 | -function gutenberg_register_navigation_post_type() { | |
| 12 | - $labels = array( | |
| 13 | - 'name' => __( 'Navigation Menus', 'gutenberg' ), | |
| 14 | - 'singular_name' => __( 'Navigation Menu', 'gutenberg' ), | |
| 15 | - 'menu_name' => _x( 'Navigation Menus', 'Admin Menu text', 'gutenberg' ), | |
| 16 | - 'add_new' => _x( 'Add New', 'Navigation Menu', 'gutenberg' ), | |
| 17 | - 'add_new_item' => __( 'Add New Navigation Menu', 'gutenberg' ), | |
| 18 | - 'new_item' => __( 'New Navigation Menu', 'gutenberg' ), | |
| 19 | - 'edit_item' => __( 'Edit Navigation Menu', 'gutenberg' ), | |
| 20 | - 'view_item' => __( 'View Navigation Menu', 'gutenberg' ), | |
| 21 | - 'all_items' => __( 'All Navigation Menus', 'gutenberg' ), | |
| 22 | - 'search_items' => __( 'Search Navigation Menus', 'gutenberg' ), | |
| 23 | - 'parent_item_colon' => __( 'Parent Navigation Menu:', 'gutenberg' ), | |
| 24 | - 'not_found' => __( 'No Navigation Menu found.', 'gutenberg' ), | |
| 25 | - 'not_found_in_trash' => __( 'No Navigation Menu found in Trash.', 'gutenberg' ), | |
| 26 | - 'archives' => __( 'Navigation Menu archives', 'gutenberg' ), | |
| 27 | - 'insert_into_item' => __( 'Insert into Navigation Menu', 'gutenberg' ), | |
| 28 | - 'uploaded_to_this_item' => __( 'Uploaded to this Navigation Menu', 'gutenberg' ), | |
| 29 | - // Some of these are a bit weird, what are they for? | |
| 30 | - 'filter_items_list' => __( 'Filter Navigation Menu list', 'gutenberg' ), | |
| 31 | - 'items_list_navigation' => __( 'Navigation Menus list navigation', 'gutenberg' ), | |
| 32 | - 'items_list' => __( 'Navigation Menus list', 'gutenberg' ), | |
| 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' => '', | |
| 33 | 63 | ); |
| 34 | 64 | |
| 35 | - $args = array( | |
| 36 | - 'labels' => $labels, | |
| 37 | - 'description' => __( 'Navigation menus.', 'gutenberg' ), | |
| 38 | - 'public' => false, | |
| 39 | - 'has_archive' => false, | |
| 40 | - 'show_ui' => true, | |
| 41 | - 'show_in_menu' => false, | |
| 42 | - 'show_in_admin_bar' => false, | |
| 43 | - 'show_in_rest' => true, | |
| 44 | - 'map_meta_cap' => true, | |
| 45 | - 'rest_base' => 'navigation', | |
| 46 | - 'rest_controller_class' => WP_REST_Posts_Controller::class, | |
| 47 | - 'supports' => array( | |
| 48 | - 'title', | |
| 49 | - 'editor', | |
| 50 | - 'revisions', | |
| 51 | - ), | |
| 52 | - 'capabilities' => array( | |
| 53 | - 'edit_others_posts' => 'edit_theme_options', | |
| 54 | - 'delete_posts' => 'edit_theme_options', | |
| 55 | - 'publish_posts' => 'edit_theme_options', | |
| 56 | - 'create_posts' => 'edit_theme_options', | |
| 57 | - 'read_private_posts' => 'edit_theme_options', | |
| 58 | - 'delete_private_posts' => 'edit_theme_options', | |
| 59 | - 'delete_published_posts' => 'edit_theme_options', | |
| 60 | - 'delete_others_posts' => 'edit_theme_options', | |
| 61 | - 'edit_private_posts' => 'edit_theme_options', | |
| 62 | - 'edit_published_posts' => 'edit_theme_options', | |
| 63 | - ), | |
| 64 | - ); | |
| 65 | + $args = wp_parse_args( $args, $defaults ); | |
| 65 | 66 | |
| 66 | - register_post_type( 'wp_navigation', $args ); | |
| 67 | + update_post_meta( $menu_item_db_id, '_menu_item_content', wp_slash( $args['menu-item-content'] ) ); | |
| 67 | 68 | } |
| 68 | -add_action( 'init', 'gutenberg_register_navigation_post_type' ); | |
| 69 | +add_action( 'wp_update_nav_menu_item', 'gutenberg_update_nav_menu_item_content', 10, 3 ); | |
| 69 | 70 | |
| 70 | 71 | /** |
| 71 | - * Disable "Post Attributes" for wp_navigation post type. | |
| 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'`. | |
| 72 | 75 | * |
| 73 | - * The attributes are also conditionally enabled when a site has custom templates. | |
| 74 | - * Block Theme templates can be available for every post type. | |
| 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. | |
| 75 | 88 | */ |
| 76 | -add_filter( 'theme_wp_navigation_templates', '__return_empty_array' ); | |
| 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; | |
| 77 | 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 | + | |
| 78 | 103 | /** |
| 79 | - * Disable block editor for wp_navigation type posts so they can be managed via the UI. | |
| 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`'. | |
| 80 | 107 | * |
| 81 | - * @param bool $value Whether the CPT supports block editor or not. | |
| 82 | - * @param string $post_type Post type. | |
| 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()`. | |
| 83 | 112 | * |
| 84 | - * @return bool | |
| 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. | |
| 85 | 124 | */ |
| 86 | -function gutenberg_disable_block_editor_for_navigation_post_type( $value, $post_type ) { | |
| 87 | - if ( 'wp_navigation' === $post_type ) { | |
| 88 | - return false; | |
| 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; | |
| 89 | 131 | } |
| 90 | 132 | |
| 91 | - return $value; | |
| 133 | + return $item_output; | |
| 92 | 134 | } |
| 135 | +add_filter( 'walker_nav_menu_start_el', 'gutenberg_output_block_nav_menu_item', 10, 4 ); | |
| 93 | 136 | |
| 94 | -add_filter( 'use_block_editor_for_post_type', 'gutenberg_disable_block_editor_for_navigation_post_type', 10, 2 ); | |
| 95 | - | |
| 96 | 137 | /** |
| 97 | - * This callback disables the content editor for wp_navigation type posts. | |
| 98 | - * Content editor cannot handle wp_navigation type posts correctly. | |
| 99 | - * We cannot disable the "editor" feature in the wp_navigation's CPT definition | |
| 100 | - * because it disables the ability to save navigation blocks via REST API. | |
| 138 | + * Shim that prevents menu items with type `'block'` from being rendered in the | |
| 139 | + * frontend when the theme does not support block menus. | |
| 101 | 140 | * |
| 102 | - * @param WP_Post $post An instance of WP_Post class. | |
| 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. | |
| 103 | 153 | */ |
| 104 | -function gutenberg_disable_content_editor_for_navigation_post_type( $post ) { | |
| 105 | - $post_type = get_post_type( $post ); | |
| 106 | - if ( 'wp_navigation' !== $post_type ) { | |
| 107 | - return; | |
| 154 | +function gutenberg_remove_block_nav_menu_items( $menu_items ) { | |
| 155 | + if ( current_theme_supports( 'block-nav-menus' ) ) { | |
| 156 | + return $menu_items; | |
| 108 | 157 | } |
| 109 | 158 | |
| 110 | - remove_post_type_support( $post_type, 'editor' ); | |
| 159 | + return array_filter( | |
| 160 | + $menu_items, | |
| 161 | + function( $menu_item ) { | |
| 162 | + return 'block' !== $menu_item->type; | |
| 163 | + } | |
| 164 | + ); | |
| 111 | 165 | } |
| 166 | +add_filter( 'wp_nav_menu_objects', 'gutenberg_remove_block_nav_menu_items', 10 ); | |
| 112 | 167 | |
| 113 | -add_action( 'edit_form_after_title', 'gutenberg_disable_content_editor_for_navigation_post_type', 10, 1 ); | |
| 114 | - | |
| 115 | 168 | /** |
| 116 | - * This callback enables content editor for wp_navigation type posts. | |
| 117 | - * We need to enable it back because we disable it to hide | |
| 118 | - * the content editor for wp_navigation type posts. | |
| 169 | + * Recursively converts a list of menu items into a list of blocks. This is a | |
| 170 | + * helper function used by `gutenberg_output_block_nav_menu()`. | |
| 119 | 171 | * |
| 120 | - * @see gutenberg_disable_content_editor_for_navigation_post_type | |
| 172 | + * Transformation depends on the menu item type. Link menu items are turned into | |
| 173 | + * a `core/navigation-link` block. Block menu items are simply parsed. | |
| 121 | 174 | * |
| 122 | - * @param WP_Post $post An instance of WP_Post class. | |
| 175 | + * @param array $menu_items The menu items to convert, sorted by each menu item's menu order. | |
| 176 | + * @param array $menu_items_by_parent_id All menu items, indexed by their parent's ID. | |
| 177 | + | |
| 178 | + * @return array Updated menu items, sorted by each menu item's menu order. | |
| 123 | 179 | */ |
| 124 | -function gutenberg_enable_content_editor_for_navigation_post_type( $post ) { | |
| 125 | - $post_type = get_post_type( $post ); | |
| 126 | - if ( 'wp_navigation' !== $post_type ) { | |
| 127 | - return; | |
| 180 | +function gutenberg_convert_menu_items_to_blocks( | |
| 181 | + $menu_items, | |
| 182 | + &$menu_items_by_parent_id | |
| 183 | +) { | |
| 184 | + if ( empty( $menu_items ) ) { | |
| 185 | + return array(); | |
| 128 | 186 | } |
| 129 | 187 | |
| 130 | - add_post_type_support( $post_type, 'editor' ); | |
| 131 | -} | |
| 188 | + $blocks = array(); | |
| 132 | 189 | |
| 133 | -add_action( 'edit_form_after_editor', 'gutenberg_enable_content_editor_for_navigation_post_type', 10, 1 ); | |
| 190 | + foreach ( $menu_items as $menu_item ) { | |
| 191 | + if ( 'block' === $menu_item->type ) { | |
| 192 | + $parsed_blocks = parse_blocks( $menu_item->content ); | |
| 134 | 193 | |
| 194 | + if ( count( $parsed_blocks ) ) { | |
| 195 | + $block = $parsed_blocks[0]; | |
| 196 | + } else { | |
| 197 | + $block = array( | |
| 198 | + 'blockName' => 'core/freeform', | |
| 199 | + 'attrs' => array( | |
| 200 | + 'originalContent' => $menu_item->content, | |
| 201 | + ), | |
| 202 | + ); | |
| 203 | + } | |
| 204 | + } else { | |
| 205 | + $block = array( | |
| 206 | + 'blockName' => 'core/navigation-link', | |
| 207 | + 'attrs' => array( | |
| 208 | + 'label' => $menu_item->title, | |
| 209 | + 'url' => $menu_item->url, | |
| 210 | + ), | |
| 211 | + ); | |
| 212 | + } | |
| 213 | + | |
| 214 | + $block['innerBlocks'] = gutenberg_convert_menu_items_to_blocks( | |
| 215 | + isset( $menu_items_by_parent_id[ $menu_item->ID ] ) | |
| 216 | + ? $menu_items_by_parent_id[ $menu_item->ID ] | |
| 217 | + : array(), | |
| 218 | + $menu_items_by_parent_id | |
| 219 | + ); | |
| 220 | + | |
| 221 | + $blocks[] = $block; | |
| 222 | + } | |
| 223 | + | |
| 224 | + return $blocks; | |
| 225 | +}; | |
| 226 | + | |
| 135 | 227 | /** |
| 136 | - * Rename the menu title from "All Navigation Menus" to "Navigation Menus". | |
| 228 | + * Shim that causes `wp_nav_menu()` to output a Navigation block instead of a | |
| 229 | + * nav menu when the theme supports block menus. The Navigation block is | |
| 230 | + * constructed by transforming the stored tree of menu items into a tree of | |
| 231 | + * blocks. | |
| 232 | + * | |
| 233 | + * Specifically, this shim makes it so that `wp_nav_menu()` returns early when | |
| 234 | + * the theme supports block menus. When merged to Core, this functionality | |
| 235 | + * should exist in `wp_nav_menu()` after `$sorted_menu_items` is set. The | |
| 236 | + * duplicated code (marked using BEGIN and END) can be deleted. | |
| 237 | + * | |
| 238 | + * This shim can be removed when the Gutenberg plugin requires a WordPress | |
| 239 | + * version that has the ticket below. | |
| 240 | + * | |
| 241 | + * @see https://core.trac.wordpress.org/ticket/50544 | |
| 242 | + * | |
| 243 | + * @param string|null $output Nav menu output to short-circuit with. Default null. | |
| 244 | + * @param stdClass $args An object containing wp_nav_menu() arguments. | |
| 245 | + * | |
| 246 | + * @return string|null Nav menu output to short-circuit with. | |
| 137 | 247 | */ |
| 138 | -function gutenberg_rename_navigation_post_type_admin_menu_entry() { | |
| 139 | - global $submenu; | |
| 140 | - if ( ! isset( $submenu['themes.php'] ) ) { | |
| 141 | - return; | |
| 248 | +function gutenberg_output_block_nav_menu( $output, $args ) { | |
| 249 | + if ( ! current_theme_supports( 'block-nav-menus' ) ) { | |
| 250 | + return null; | |
| 142 | 251 | } |
| 143 | 252 | |
| 144 | - $post_type = get_post_type_object( 'wp_navigation' ); | |
| 145 | - if ( ! $post_type ) { | |
| 146 | - return; | |
| 253 | + // BEGIN: Code that already exists in wp_nav_menu(). | |
| 254 | + | |
| 255 | + // Get the nav menu based on the requested menu. | |
| 256 | + $menu = wp_get_nav_menu_object( $args->menu ); | |
| 257 | + | |
| 258 | + // Get the nav menu based on the theme_location. | |
| 259 | + $locations = get_nav_menu_locations(); | |
| 260 | + if ( ! $menu && $args->theme_location && $locations && isset( $locations[ $args->theme_location ] ) ) { | |
| 261 | + $menu = wp_get_nav_menu_object( $locations[ $args->theme_location ] ); | |
| 147 | 262 | } |
| 148 | 263 | |
| 149 | - $menu_title_index = 0; | |
| 150 | - foreach ( $submenu['themes.php'] as $key => $menu_item ) { | |
| 151 | - if ( $post_type->labels->all_items === $menu_item[ $menu_title_index ] ) { | |
| 152 | - $submenu['themes.php'][ $key ][ $menu_title_index ] = $post_type->labels->menu_name; // phpcs:ignore WordPress.WP.GlobalVariablesOverride | |
| 153 | - return; | |
| 264 | + // Get the first menu that has items if we still can't find a menu. | |
| 265 | + if ( ! $menu && ! $args->theme_location ) { | |
| 266 | + $menus = wp_get_nav_menus(); | |
| 267 | + foreach ( $menus as $menu_maybe ) { | |
| 268 | + $menu_items = wp_get_nav_menu_items( $menu_maybe->term_id, array( 'update_post_term_cache' => false ) ); | |
| 269 | + if ( $menu_items ) { | |
| 270 | + $menu = $menu_maybe; | |
| 271 | + break; | |
| 272 | + } | |
| 154 | 273 | } |
| 155 | 274 | } |
| 156 | -} | |
| 157 | 275 | |
| 158 | -add_action( 'admin_menu', 'gutenberg_rename_navigation_post_type_admin_menu_entry' ); | |
| 276 | + if ( empty( $args->menu ) ) { | |
| 277 | + $args->menu = $menu; | |
| 278 | + } | |
| 159 | 279 | |
| 160 | -/** | |
| 161 | - * Registers the navigation areas supported by the current theme. The expected | |
| 162 | - * shape of the argument is: | |
| 163 | - * array( | |
| 164 | - * 'primary' => 'Primary', | |
| 165 | - * 'secondary' => 'Secondary', | |
| 166 | - * 'tertiary' => 'Tertiary', | |
| 167 | - * ) | |
| 168 | - * | |
| 169 | - * @param array $new_areas Supported navigation areas. | |
| 170 | - */ | |
| 171 | -function gutenberg_register_navigation_areas( $new_areas ) { | |
| 172 | - global $gutenberg_navigation_areas; | |
| 173 | - $gutenberg_navigation_areas = $new_areas; | |
| 174 | -} | |
| 280 | + // If the menu exists, get its items. | |
| 281 | + if ( $menu && ! is_wp_error( $menu ) && ! isset( $menu_items ) ) { | |
| 282 | + $menu_items = wp_get_nav_menu_items( $menu->term_id, array( 'update_post_term_cache' => false ) ); | |
| 283 | + } | |
| 175 | 284 | |
| 176 | -// Register the default navigation areas. | |
| 177 | -gutenberg_register_navigation_areas( | |
| 178 | - array( | |
| 179 | - 'primary' => 'Primary', | |
| 180 | - 'secondary' => 'Secondary', | |
| 181 | - 'tertiary' => 'Tertiary', | |
| 182 | - ) | |
| 183 | -); | |
| 285 | + // Set up the $menu_item variables. | |
| 286 | + _wp_menu_item_classes_by_context( $menu_items ); | |
| 184 | 287 | |
| 185 | -/** | |
| 186 | - * Returns the available navigation areas. | |
| 187 | - * | |
| 188 | - * @return array Registered navigation areas. | |
| 189 | - */ | |
| 190 | -function gutenberg_get_navigation_areas() { | |
| 191 | - global $gutenberg_navigation_areas; | |
| 192 | - return $gutenberg_navigation_areas; | |
| 288 | + $sorted_menu_items = array(); | |
| 289 | + foreach ( (array) $menu_items as $menu_item ) { | |
| 290 | + $sorted_menu_items[ $menu_item->menu_order ] = $menu_item; | |
| 291 | + } | |
| 292 | + | |
| 293 | + unset( $menu_items, $menu_item ); | |
| 294 | + | |
| 295 | + // END: Code that already exists in wp_nav_menu(). | |
| 296 | + | |
| 297 | + $menu_items_by_parent_id = array(); | |
| 298 | + foreach ( $sorted_menu_items as $menu_item ) { | |
| 299 | + $menu_items_by_parent_id[ $menu_item->menu_item_parent ][] = $menu_item; | |
| 300 | + } | |
| 301 | + | |
| 302 | + $navigation_block = array( | |
| 303 | + 'blockName' => 'core/navigation', | |
| 304 | + 'attrs' => array(), | |
| 305 | + 'innerBlocks' => gutenberg_convert_menu_items_to_blocks( | |
| 306 | + isset( $menu_items_by_parent_id[0] ) | |
| 307 | + ? $menu_items_by_parent_id[0] | |
| 308 | + : array(), | |
| 309 | + $menu_items_by_parent_id | |
| 310 | + ), | |
| 311 | + ); | |
| 312 | + | |
| 313 | + return render_block( $navigation_block ); | |
| 193 | 314 | } |
| 315 | +add_filter( 'pre_wp_nav_menu', 'gutenberg_output_block_nav_menu', 10, 2 ); | |
| 194 | 316 | |
| 195 | 317 | /** |
| 196 | - * Retrieves navigation areas. | |
| 318 | + * Shim that makes nav-menus.php nicely display a menu item with its `type` set to | |
| 319 | + * `'block'`. | |
| 197 | 320 | * |
| 198 | - * @return array Navigation areas. | |
| 321 | + * Specifically, this shim makes it so that `Walker_Nav_Menu_Edit::start_el()` | |
| 322 | + * outputs extra form fields. When merged to Core, this markup should exist in | |
| 323 | + * `Walker_Nav_Menu_Edit::start_el()`. | |
| 324 | + * | |
| 325 | + * This shim can be removed when the Gutenberg plugin requires a WordPress | |
| 326 | + * version that has the ticket below. | |
| 327 | + * | |
| 328 | + * @see https://core.trac.wordpress.org/ticket/50544 | |
| 329 | + * | |
| 330 | + * @param int $item_id Menu item ID. | |
| 331 | + * @param WP_Post $item Menu item data object. | |
| 199 | 332 | */ |
| 200 | -function gutenberg_get_navigation_areas_menus() { | |
| 201 | - $areas = get_option( 'wp_navigation_areas', array() ); | |
| 202 | - if ( ! $areas ) { | |
| 203 | - // Original key used `fse` prefix but Core options should use `wp`. | |
| 204 | - // We fallback to the legacy option to catch sites with values in the | |
| 205 | - // original location. | |
| 206 | - $legacy_option_key = 'fse_navigation_areas'; | |
| 207 | - $areas = get_option( $legacy_option_key, array() ); | |
| 333 | +function gutenberg_output_block_menu_item_custom_fields( $item_id, $item ) { | |
| 334 | + if ( 'block' === $item->type ) { | |
| 335 | + ?> | |
| 336 | + <p class="field-content description description-wide"> | |
| 337 | + <label for="edit-menu-item-content-<?php echo $item_id; ?>"> | |
| 338 | + <?php _e( 'Content', 'gutenberg' ); ?><br /> | |
| 339 | + <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> | |
| 340 | + </label> | |
| 341 | + </p> | |
| 342 | + <?php | |
| 208 | 343 | } |
| 209 | - return $areas; | |
| 210 | 344 | } |
| 345 | +add_action( 'wp_nav_menu_item_custom_fields', 'gutenberg_output_block_menu_item_custom_fields', 10, 2 ); | |
| 211 | 346 | |
| 212 | 347 | /** |
| 213 | - * Shim that hides ability to edit visibility and status for wp_navigation type posts. | |
| 214 | - * When merged to Core, the CSS below should be moved to wp-admin/css/edit.css. | |
| 348 | + * Shim that adds extra styling to nav-menus.php. This lets us style menu items | |
| 349 | + * that have a `type` set to `'block'`. When merged to Core, this CSS should be | |
| 350 | + * moved to nav-menus.css. | |
| 215 | 351 | * |
| 216 | 352 | * This shim can be removed when the Gutenberg plugin requires a WordPress |
| 217 | 353 | * version that has the ticket below. |
| 218 | 354 | * |
| 219 | - * @see https://core.trac.wordpress.org/ticket/54407 | |
| 355 | + * @see https://core.trac.wordpress.org/ticket/50544 | |
| 220 | 356 | * |
| 221 | 357 | * @param string $hook The current admin page. |
| 222 | 358 | */ |
| 223 | -function gutenberg_hide_visibility_and_status_for_navigation_posts( $hook ) { | |
| 224 | - $allowed_hooks = array( 'post.php', 'post-new.php' ); | |
| 225 | - if ( ! in_array( $hook, $allowed_hooks, true ) ) { | |
| 226 | - return; | |
| 227 | - } | |
| 228 | - | |
| 229 | - /** | |
| 230 | - * HACK: We're hiding the description field using CSS because this | |
| 231 | - * cannot be done using a filter or an action. | |
| 232 | - */ | |
| 233 | - | |
| 234 | - $css = <<<CSS | |
| 235 | - body.post-type-wp_navigation div#minor-publishing { | |
| 359 | +function gutenberg_add_block_menu_item_styles_to_nav_menus( $hook ) { | |
| 360 | + if ( 'nav-menus.php' === $hook ) { | |
| 361 | + $css = <<<CSS | |
| 362 | + /** | |
| 363 | + * HACK: We're hiding the description field using CSS because this | |
| 364 | + * cannot be done using a filter. When merged to Core, we should | |
| 365 | + * actually remove the field from | |
| 366 | + * `Walker_Nav_Menu_Edit::start_el()`. | |
| 367 | + */ | |
| 368 | + .menu-item-block .description:not(.field-content) { | |
| 236 | 369 | display: none; |
| 237 | 370 | } |
| 238 | 371 | CSS; |
| 239 | - | |
| 240 | - wp_add_inline_style( 'common', $css ); | |
| 372 | + wp_add_inline_style( 'nav-menus', $css ); | |
| 373 | + } | |
| 241 | 374 | } |
| 242 | - | |
| 243 | -add_action( 'admin_enqueue_scripts', 'gutenberg_hide_visibility_and_status_for_navigation_posts' ); | |
| 375 | +add_action( 'admin_enqueue_scripts', 'gutenberg_add_block_menu_item_styles_to_nav_menus' ); | |