WordPress REST API: Navigation Menu Items
A headless site (a React or Vue front end with WordPress as the back end) needs the menu of WordPress too. WordPress has routes for menus, menu items and menu locations. Let us make a menu and read it.
Create a menu
$ wp menu list –fields=term_id,name,slug,count
term_id name slug count
2 Main Menu main-menu 3
$ wp menu item list main-menu –fields=db_id,title,type,link
db_id title type link
6 About us post_type http://example.com/about/
7 Blog custom http://example.com/blog/
8 Contact custom http://example.com/contact/
The menu routes need a login
The routes /wp/v2/menus, /wp/v2/menu-items and /wp/v2/menu-locations are only for users who can edit the theme options, so a guest gets an error:
$ curl -s "http://example.com/wp-json/wp/v2/menu-items" | jq -c '{code, status: .data.status}'
{"code":"rest_cannot_view","status":401}
$ curl -s "http://example.com/wp-json/wp/v2/menus" | jq -c '{code, status: .data.status}'
{"code":"rest_cannot_view","status":401}
Read the menu with a login
$ curl -s -u "admin:APP_PASSWORD" "http://example.com/wp-json/wp/v2/menus?_fields=id,name,slug" | jq -c '.[]'
{"id":2,"name":"Main Menu","slug":"main-menu"}
$ curl -s -u "admin:APP_PASSWORD" "http://example.com/wp-json/wp/v2/menu-items?menus=2&_fields=id,title.rendered,url,parent,menu_order,type" | jq -c '.[]'
{"id":6,"title":{"rendered":"About us"},"url":"http://example.com/about/","type":"post_type","parent":0,"menu_order":0}
{"id":7,"title":{"rendered":"Blog"},"url":"http://example.com/blog/","type":"custom","parent":0,"menu_order":2}
{"id":8,"title":{"rendered":"Contact"},"url":"http://example.com/contact/","type":"custom","parent":0,"menu_order":3}
The menus parameter filters the items of one menu (use the ID of the menu). The parent value (0 for the top level) lets you build the sub menus. A link to a post, page or category also has an object_id.
Menu locations
$ curl -s -u "admin:APP_PASSWORD" "http://example.com/wp-json/wp/v2/menu-locations" | jq -c .
[]
The answer is empty because our block theme does not register any menu location. A classic theme with register_nav_menus() would be listed here. See Register Nav Menus.
Make a public menu endpoint
Most of the times a public site needs to show the menu to all visitors, without a login. The best way is to make your own small endpoint which returns only the data you want to show:
<?php
/**
* Plugin Name: TC Public Menu API
*/
add_action( 'rest_api_init', function () {
register_rest_route( 'tc/v1', '/menu/(?P<slug>[a-z0-9-]+)', array(
'methods' => 'GET',
'permission_callback' => '__return_true',
'callback' => function ( WP_REST_Request $request ) {
$items = wp_get_nav_menu_items( $request['slug'] );
if ( ! $items ) {
return new WP_Error( 'tc_no_menu', 'Menu not found', array( 'status' => 404 ) );
}
return array_map( function ( $item ) {
return array(
'id' => $item->ID,
'title' => $item->title,
'url' => $item->url,
'parent' => (int) $item->menu_item_parent,
);
}, $items );
},
) );
} );
$ wp plugin activate tc-menu-api
Plugin 'tc-menu-api' activated.
Success: Activated 1 of 1 plugins.
$ curl -s "http://example.com/wp-json/tc/v1/menu/main-menu" | jq -c '.[]'
{"id":6,"title":"About us","url":"http://example.com/about/","parent":0}
{"id":7,"title":"Blog","url":"http://example.com/blog/","parent":0}
{"id":8,"title":"Contact","url":"http://example.com/contact/","parent":0}
$ curl -s "http://example.com/wp-json/tc/v1/menu/nope" | jq -c '{code, message}'
{"code":"tc_no_menu","message":"Menu not found"}
Menus in block themes
Block themes keep menus as wp_navigation posts, and the REST route for them is /wp/v2/navigation. It also needs a login:
$ curl -s -u "admin:APP_PASSWORD" "http://example.com/wp-json/wp/v2/navigation?_fields=id,title.rendered,status" | jq -c '.[]'
{"id":4,"status":"publish","title":{"rendered":"Navigation"}}
| Exercises & Assignments |
|---|
| Get the latest posts with the REST API |
| Create a post with the REST API and an application password |
| Build a custom REST endpoint which greets a name |
| Interview Questions & Answers |
|---|
| What is the WordPress REST API? |
| How to create a custom REST API endpoint in WordPress? |