@wordpress/edit-navigation Edit
Edit Navigation page module for WordPress – a Gutenberg-based UI for editing navigation menus.
This package is meant to be used only with WordPress core. Feel free to use it in your own project but please keep in mind that it might never get fully documented.
Usage Usage
/** * WordPress dependencies */ import { initialize } from '@wordpress/edit-navigation'; /** * Internal dependencies */ import blockEditorSettings from './block-editor-settings'; initialize( '#navigation-editor-root', blockEditorSettings );
Purpose Purpose
By default, the Navigation Editor screen allows users to create and edit complex navigations using a block-based UI. The aim is to supercede the current Menus screen by providing a superior experience whilst retaining backwards compatibility.
The editing experience is provided as a block editor wrapper around the core functionality of the Navigation block. Features of the block are disabled/enhanced as necessary to provide an experience appropriate to editing a navigation outside of a Full Site Editing context.
Modes Modes
The Navigation Editor has two “modes” for persistence (“saving” navigations) and rendering:
- Default – navigations are saved to the existing (post type powered) Menus system and rendered using standard Walker classes.
- Block-based (opt in) – navigations continue to be saved using the existing post type system, but non-link blocks are saved (see technical implementation) and rendered as blocks to provide access to the full power of the Navigation block (with some tradeoffs in terms of backwards compatibility).
Default Mode Default Mode
In this mode, navigations created in the Navigation Editor are stored using the existing Menu post type (nav_menu_item
) system. As this method matches that used in the existing Menus screen, there is a smooth upgrade path to using new Navigation Editor screen to edit navigations.
Moreover, when the navigation is rendered on the front of the site the system continues to use the classic Navigation “Walker” class, thereby ensuring the HTML markup remains the same when using a classic Theme.
Block-based Mode Block-based Mode
If desired, themes are able to opt into rendering complete block-based menus using the Navigation Editor. This allows for arbitrarily complex navigation block structures to be used in an existing theme whilst still ensuring the navigation data is still saved to the existing (post type powered) Menus system.
Themes can opt into this behaviour by declaring:
add_theme_support( 'block-nav-menus' );
This unlocks significant additional capabilities in the Navigation Editor. For example, by default, the Navigation Editor screen only allows link (core/navigation-link
) blocks to be inserted into a navigation. When a theme opts into block-nav-menus
however, users are able to add non-link blocks to a navigation using the Navigation Editor screen, including:
core/navigation-link
.core/social
.core/search
.
Technical Implementation details Technical Implementation details
By default, core/navigation-link
items are serialized and persisted as nav_menu_item
posts. No serialized block HTML is stored for these standard link blocks.
Non-link navigation items however, are persisted as nav_menu_items
with a special type
of block
. These items have an additional content
field which is used to store the serialized block markup.
When rendered on the front-end, the blocks are parse
d from the content
field and rendered as blocks.
If the user switches to a theme that does not support block menus, or disables this functionality, non-link blocks are no longer rendered on the frontend. Care is taken, however, to ensure that users can still see their data on the existing Menus screen.
Block to Menu Item mapping Block to Menu Item mapping
The Navigation Editor needs to be able to map navigation items in two directions:
nav_menu_item
s to Blocks – when displaying an existing navigation.- Blocks to
nav_menu_item
s – when saving an navigation being editing in the Navigation screen.
The Navigation Editor has two dedicated methods for handling mapping between these two expressions of the data:
To understand these fully, one must appreciate that WordPress maps raw nav_menu_item
posts to Menu item objects. These have various properties which map as follows:
Menu Item object property | Equivalent Block Attribute | Description |
---|---|---|
ID |
Not mapped. | The term_id if the menu item represents a taxonomy term. |
attr_title |
title |
The title attribute of the link element for this menu item. |
classes |
classNames |
The array of class attribute values for the link element of this menu item. |
db_id |
Not mapped. | The DB ID of this item as a nav_menu_item object, if it exists (0 if it doesn’t exist). |
description |
description |
The description of this menu item. |
menu_item_parent |
Not mapped.1 | The DB ID of the nav_menu_item that is this item’s menu parent, if any. 0 otherwise. |
object |
type |
The type of object originally represented, such as ‘category’, ‘post’, or ‘attachment’. |
object_id |
id |
The DB ID of the original object this menu item represents, e.g. ID for posts and term_id for categories. |
post_parent |
Not mapped. | The DB ID of the original object’s parent object, if any (0 otherwise). |
post_title |
Not mapped. | A “no title” label if menu item represents a post that lacks a title. |
target |
opensInNewTab 2 |
The target attribute of the link element for this menu item. |
title |
label |
The title of this menu item. |
type |
kind |
The family of objects originally represented, such as ‘post_type’ or ‘taxonomy’. |
type_label |
Not mapped. | The singular label used to describe this type of menu item. |
url |
url |
The URL to which this menu item points. |
xfn |
rel |
The XFN relationship expressed in the link of this menu item. |
\_invalid |
Not mapped. | Whether the menu item represents an object that no longer exists. |
- [1] – the parent -> child relationship is expressed in block via the
innerBlocks
attribute and is therefore not required as a explicit block attribute. - [2] – applies only if the value of the
target
field is_blank
.
Inconsistencies Inconsistencies
Mapping Mapping
For historical reasons, the following properties display some inconsistency in their mapping from Menu Item Object to Block attribute:
type
->kind
– the family of objects is stored askind
on the block and so must be mapped accordingly.object
->type
– the type of object is stored astype
on the block and so must be mapped accordingly.object_id
->id
– the block stores a reference to the original object’s ID as theid
attribute. This should not be confused with the block’sclientId
which is unrelated.attr_title
->title
– the HTMLtitle
attribute is stored astitle
on the block and so must be mapped accordingly.
Object Types Object Types
- Menu Item objects which represent “Tags” are stored in WordPress as
post_tag
but the block expects theirtype
attribute to betag
(omiting thepost_
suffix). This inconsistency is accounted for in the mapping utilities methods.
Hooks Hooks
useMenuItems
and useNavigationBlock
hooks are the central part of this package. They bridge the gap between the API and the block editor interface:
const menuId = 1; const query = useMemo( () => ( { menus: menuId, per_page: -1 } ), [ menuId ] ); // Data manipulation: const { menuItems, eventuallySaveMenuItems, createMissingMenuItems, } = useMenuItems( query ); // Working state: const { blocks, setBlocks, menuItemsRef } = useNavigationBlocks( menuItems ); return ( <BlockEditorProvider value={ blocks } onInput={ ( updatedBlocks ) => setBlocks( updatedBlocks ) } onChange={ ( updatedBlocks ) => { createMissingMenuItems( updatedBlocks, menuItemsRef ); setBlocks( updatedBlocks ); } } settings={ blockEditorSettings } > <NavigationStructureArea blocks={ blocks } initialOpen /> <BlockEditorArea menuId={ menuId } saveBlocks={ () => eventuallySaveMenuItems( blocks, menuItemsRef ) } onDeleteMenu={ () => { /* ... */ } } /> </BlockEditorProvider> );
Glossary Glossary
- Link block – the basic
core/navigation-link
block which is the standard block used to add links within navigations. - Navigation block – the root
core/navigation
block which can be used both with the Navigation Editor and outside (eg: Post / Site Editor). - Navigation editor / screen – the new screen provided by Gutenberg to allow the user to edit navigations using a block-based UI.
- Menus screen – the current/existing interface/screen for managing Menus in WordPress WPAdmin.
This package assumes that your code will run in an ES2015+ environment. If you’re using an environment that has limited or no support for ES2015+ such as IE browsers then using core-js will add polyfills for these methods.