Guide

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

<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

ParameterTypeDefaultDescription
namestring"main"Menu name or slug
idTypeMenuNodeIdTypeEnumNAMEHow 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' })

Each menu item contains:

interface MenuItem {
  label: string  // Display text
  uri: string    // Link URL (relative)
}
You can extend the MenuItem fragment to include additional fields. See Custom Queries.

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
The menu name in WordPress must match what you pass to useMenu(). By default, WPNuxt looks for a menu named "main".

Troubleshooting

If useMenu() returns empty:

  1. 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' })
    
  2. Verify the menu exists - Visit /wp-admin/nav-menus.php
  3. Check GraphQL - Test the query directly:
    {
      menu(id: "main", idType: NAME) {
        menuItems {
          nodes {
            label
            uri
          }
        }
      }
    }
    
  • 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:

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:

extend/queries/fragments/MenuItem.fragment.gql
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>
  • Custom Queries — Create custom menu fragments with additional fields
  • Quick Start — Tutorial that includes adding a navigation menu
Copyright © 2026