# Navigation Menus as a REST API Endpoint

> Adds a public /wp-json/site/v1/menu/{location} endpoint that returns the menu assigned to a theme location as a nested list, ready for a headless or app front end.

- Type: PHP
- Runs: Run everywhere
- Category: [Developer](https://wpide.com/library/category/developer/)
- Tags: rest-api, menus, headless
- Author: WPIDE Team
- Installs: 0
- Updated: 2026-10-28
- Page: https://wpide.com/library/rest-menu-endpoint/

## Code

```php
add_action( 'rest_api_init', function () {
    register_rest_route( 'site/v1', '/menu/(?P<location>[a-z0-9_-]+)', array(
        'methods'             => WP_REST_Server::READABLE,
        'permission_callback' => '__return_true', // Menus are public on the site anyway.
        'callback'            => function ( WP_REST_Request $request ) {
            $locations = get_nav_menu_locations();
            $location  = $request['location'];

            if ( empty( $locations[ $location ] ) ) {
                return new WP_Error( 'no_menu', 'No menu is assigned to this location.', array( 'status' => 404 ) );
            }

            $items = wp_get_nav_menu_items( $locations[ $location ] );
            if ( ! $items ) {
                return rest_ensure_response( array() );
            }

            $by_parent = array();
            foreach ( $items as $item ) {
                $by_parent[ (int) $item->menu_item_parent ][] = $item;
            }

            $build = function ( $parent_id ) use ( &$build, $by_parent ) {
                $out = array();
                foreach ( $by_parent[ $parent_id ] ?? array() as $item ) {
                    $out[] = array(
                        'id'       => (int) $item->ID,
                        'title'    => wp_strip_all_tags( $item->title ),
                        'url'      => $item->url,
                        'target'   => $item->target,
                        'classes'  => array_values( array_filter( (array) $item->classes ) ),
                        'children' => $build( (int) $item->ID ),
                    );
                }
                return $out;
            };

            return rest_ensure_response( $build( 0 ) );
        },
    ) );
} );
```

## Notes

Works with classic menu locations (Appearance > Menus); block themes that only use the Navigation block have no locations to return.

## How to use it

Install the free WPIDE plugin (https://wordpress.org/plugins/wpide/), find "Navigation Menus as a REST API Endpoint" in its snippet library and add it in one click; or create a new PHP snippet in WPIDE (or any code snippets plugin) and paste the code above. More snippets: https://wpide.com/library/
