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
<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
| Parameter | Type | Default | Description |
|---|---|---|---|
name | string | "main" | Menu name or slug |
idType | MenuNodeIdTypeEnum | NAME | How to identify the menu |
// 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:
interface MenuItem {
label: string // Display text
uri: string // Link URL (relative)
}
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
menuquery - Block theme Navigation blocks use a different system (
wp_navigationposts) - 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:
- Go to
/wp-admin/nav-menus.php(direct URL, not in the admin menu) - Create a new menu with a name (e.g., "main")
- Add menu items (pages, posts, custom links)
- Save the menu
Block Themes
If you're using a block theme and don't see Appearance → Menus:
- Navigate directly to
/wp-admin/nav-menus.php - Or install a classic theme temporarily to access the menu editor
- The menu data persists regardless of active theme
useMenu(). By default, WPNuxt looks for a menu named "main".Troubleshooting
Menu Not Found
If useMenu() returns empty:
- Check the menu name - Must match exactly (case-sensitive)
// WordPress menu named "Main Menu" useMenu({ name: 'Main Menu' }) // WordPress menu named "main" useMenu({ name: 'main' }) - Verify the menu exists - Visit
/wp-admin/nav-menus.php - Check GraphQL - Test the query directly:
{ 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:
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:
fragment MenuItem on MenuItem {
id
label
uri
parentId
childItems {
nodes {
id
label
uri
}
}
}
<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:
<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