---
title: "Menus"
description: "Fetch and display WordPress navigation menus"
canonical_url: "https://wpnuxt.com/guide/menus"
---
# Menus

> Fetch and display WordPress navigation menus

WordPress menus let editors control site navigation without touching code — they can add, remove, and reorder menu items from the admin panel. WPNuxt exposes these menus to your Nuxt frontend via the `useMenu` composable, so navigation stays in sync with what editors configure in WordPress.

## Basic Usage

```vue
<script setup lang="ts">
const { data: menuItems } = await useMenu({ name: 'main' })
</script>

<template>
  <nav v-if="menuItems?.length">
    <NuxtLink
      v-for="item in menuItems"
      :key="item.uri"
      :to="item.uri"
    >
      {{ item.label }}
    </NuxtLink>
  </nav>
</template>
```

## Parameters

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Default
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        name
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        "main"
      </code>
    </td>
    
    <td>
      Menu name or slug
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        idType
      </code>
    </td>
    
    <td>
      <code>
        MenuNodeIdTypeEnum
      </code>
    </td>
    
    <td>
      <code>
        NAME
      </code>
    </td>
    
    <td>
      How to identify the menu
    </td>
  </tr>
</tbody>
</table>

```ts
// By name (default)
const { data } = await useMenu({ name: 'main' })

// By slug
const { data } = await useMenu({ name: 'main-menu', idType: 'SLUG' })

// By database ID
const { data } = await useMenu({ name: '5', idType: 'DATABASE_ID' })
```

## Menu Item Structure

Each menu item contains:

```ts
interface MenuItem {
  label: string  // Display text
  uri: string    // Link URL (relative)
}
```

<callout type="tip">

You can extend the MenuItem fragment to include additional fields. See [Custom Queries](https://wpnuxt.com/guide/custom-queries).

</callout>

## Classic Menus Required

WPNuxt queries **classic WordPress menus**, not the Navigation block used in block themes.

### Why Classic Menus?

- WPGraphQL exposes classic menus via the `menu` query
- Block theme Navigation blocks use a different system (`wp_navigation` posts)
- Classic menus are more structured and easier to query

### Creating a Classic Menu

Even with block themes (WordPress 6.0+), you can create classic menus:

1. Go to `/wp-admin/nav-menus.php` (direct URL, not in the admin menu)
2. Create a new menu with a name (e.g., "main")
3. Add menu items (pages, posts, custom links)
4. Save the menu

### Block Themes

If you're using a block theme and don't see **Appearance → Menus**:

1. Navigate directly to `/wp-admin/nav-menus.php`
2. Or install a classic theme temporarily to access the menu editor
3. The menu data persists regardless of active theme

<callout type="info">

**Which default themes are classic?** The last default WordPress theme built as a classic (non-FSE) theme is **Twenty Twenty-One**. Later default themes, starting with **Twenty Twenty-Two**, are block themes. If you want an official classic theme for menu editing, install Twenty Twenty-One.

</callout>

<callout type="info">

The menu name in WordPress must match what you pass to `useMenu()`. By default, WPNuxt looks for a menu named `"main"`.

</callout>

## Troubleshooting

### Menu Not Found

If `useMenu()` returns empty:

1. **Check the menu name** - Must match exactly (case-sensitive)```ts
// WordPress menu named "Main Menu"
useMenu({ name: 'Main Menu' })

// WordPress menu named "main"
useMenu({ name: 'main' })
```
2. **Verify the menu exists** - Visit `/wp-admin/nav-menus.php`
3. **Check GraphQL** - Test the query directly:```graphql
{
  menu(id: "main", idType: NAME) {
    menuItems {
      nodes {
        label
        uri
      }
    }
  }
}
```

### Menu Items Not Showing

- Ensure menu items are published pages/posts
- Check that custom links have valid URLs
- Verify WPGraphQL can access the linked content

## Extending Menu Items

To fetch additional menu item fields, create a custom fragment:

```graphql [extend/queries/fragments/MenuItem.fragment.gql]
fragment MenuItem on MenuItem {
  id
  label
  uri
  target
  cssClasses
  description
  parentId
}
```

Run `pnpm dev:prepare` to regenerate composables.

## Nested Menus

For hierarchical menus with parent/child relationships:

```graphql [extend/queries/fragments/MenuItem.fragment.gql]
fragment MenuItem on MenuItem {
  id
  label
  uri
  parentId
  childItems {
    nodes {
      id
      label
      uri
    }
  }
}
```

```vue
<script setup lang="ts">
const { data: menuItems } = await useMenu({ name: 'main' })

// Filter to top-level items only
const topLevel = computed(() =>
  menuItems.value?.filter(item => !item.parentId)
)
</script>
```

## Multiple Menus

Fetch different menus for different parts of your site:

```vue
<script setup lang="ts">
const { data: mainMenu } = await useMenu({ name: 'main' })
const { data: footerMenu } = await useMenu({ name: 'footer' })
</script>
```

## Related Pages

- **Custom Queries** — Create custom menu fragments with additional fields
- **Quick Start** — Tutorial that includes adding a navigation menu


## Sitemap

See the full [sitemap](https://wpnuxt.com/sitemap.md) for all pages.
