DEV Community

WPPilot
WPPilot

Posted on

Rebuild a WordPress navigation menu with Claude without touching the live header until you're ready

Reorganising a site's main menu is one of those jobs that sounds small and isn't. A client wants "Services" split into three, the blog moved under "Resources", two dead links gone and the order changed. In wp-admin that's twenty minutes of dragging items around on the menu visitors are using right now. One wrong drop and the header is broken until you notice.

It's also a job people now ask an AI client to do. The risky way is to let the agent edit the live menu item by item. This post shows a safer pattern that works with any MCP client (Claude Code, Claude Desktop, Cursor, VS Code and others): build the new menu beside the old one, check it, swap the theme location, and keep the old menu as your way back.

Everything here uses WPPilot Free, a self-hosted WordPress plugin that turns your site into an MCP server. Your AI client brings its own model; there's no relay in between.

Disclosure: I work on WPPilot. Ability names and behaviour below are taken from the public WordPress core ability reference.

One scope note first: classic menus

The menu abilities in WPPilot work on classic navigation menus: the ones you manage under Appearance → Menus and assign to theme locations like "Primary" or "Footer". If your site runs a block theme whose header uses a Navigation block, this exact workflow doesn't apply. Check before you start: if Appearance → Menus exists and your theme lists menu locations, you're good.

The abilities you'll use (all Free)

Step Ability What it does
Look list-menus Classic menus and the theme locations they occupy
Look list-menu-locations Locations the active theme registers, and what's in each
Look list-menu-items One menu as an ordered list with parents, targets, URLs, labels, CSS classes
Look list-content, search-content Find the page and post IDs the new items should point to
Build create-menu Creates an empty classic menu and returns its ID
Build upsert-menu-item Adds or partially updates an item (custom URL, page, post, taxonomy…)
Build reorder-menu-items Sets order and nesting in one call
Swap assign-menu-location Puts a menu into a location. The previous assignment is captured first, so this is reversible from the change ledger
Check list-changes, get-change, rollback-change The change ledger and rollback for supported operations

Two abilities to keep away from in this job: delete-menu (permanent, menus have no trash) and delete-menu-item (permanent). Both need explicit confirmation anyway. The whole point of this pattern is that you never need them until the new menu has been live for a while.

Setup in five minutes

You need self-hosted WordPress 6.9+, PHP 8.0+ and HTTPS if your client connects remotely.

  1. Download wppilot.zip from the latest GitHub release (it isn't on WordPress.org) and upload it under Plugins → Add New → Upload Plugin.
  2. Leave the safety profile on Production Safe, the install default. It blocks PHP execution, WP-CLI, filesystem and database access, and plugin/theme installs, none of which a menu job needs.
  3. Connect your client. With Claude Code over OAuth:
claude mcp add --transport http wppilot https://your-site.com/wp-json/mcp/wppilot-oauth
# then run /mcp and finish the browser sign-in
Enter fullscreen mode Exit fullscreen mode

Use a WordPress account that can already manage menus in wp-admin. Every MCP call inherits that user's permissions, so the agent can't do more than that account can.

Step 1: Have the agent describe what's there

Start with reads only. This prompt changes nothing:

Change nothing on the site.
1. Run list-menu-locations and tell me which menu sits in each location.
2. For the menu in the primary header location, run list-menu-items and
   show it as an indented outline: label, target (page ID or URL), parent.
3. Flag items that point to a trashed or draft page, or to a custom URL
   on this domain that could be a page link instead.
Enter fullscreen mode Exit fullscreen mode

You now have a written snapshot of the current menu. Save it next to your ticket. It's the plan's "before".

Step 2: Build the new menu beside the old one

Give the agent the target structure in plain language and make it build a new menu:

Create a new classic menu called "Primary 2026-10 (staging)" with create-menu.
Do NOT modify or assign any existing menu.

Target structure:
- Home
- Services
  - Web design (page "Web Design")
  - Care plans (page "WordPress Care Plans")
  - Audits (page "Site Audit")
- Resources
  - Blog (posts page)
  - Guides (category "guides")
- About
- Contact

Use search-content or list-content to find the real page IDs and link items
to those objects, not to hard-coded URLs. If a page doesn't exist, stop and
list what's missing instead of creating pages.
When all items exist, use reorder-menu-items once to set the final order and
nesting, then show me list-menu-items for the new menu.
Enter fullscreen mode Exit fullscreen mode

Why link to objects instead of URLs? If someone later changes a page slug, an object-linked item follows it; a pasted URL silently breaks.

The live header hasn't changed at this point. Visitors still see the old menu, because the new one isn't assigned to any location.

Step 3: Review the new menu like a diff

Ask for a side-by-side before you swap:

Compare the current primary menu and "Primary 2026-10 (staging)" as two
outlines. List: items added, items removed, items renamed, items moved.
Confirm every item in the new menu points at a published page, post or term.
Enter fullscreen mode Exit fullscreen mode

This is the review step people skip when they drag items around by hand. Read it properly. If something's wrong, fix it with upsert-menu-item or another reorder-menu-items call on the staging menu, which still isn't live.

Step 4: Swap the location (the only live change)

Use assign-menu-location to put "Primary 2026-10 (staging)" into the primary
header location. Then run list-changes and show me the entry for that call,
including whether rollback is available.
Enter fullscreen mode Exit fullscreen mode

That one call is the entire live change. Because assign-menu-location captures the previous assignment before writing, the ledger entry should show a rollback option. Load the site in a private window and click through the header on desktop and mobile.

If your client can open a browser, get-page-view-link gives it the URL to look at. If it can't, capture-page asks the site to take a screenshot, though it only runs while someone has WPPilot's Visual Runtime tab open in wp-admin. compare-captures then scores a before and after capture of the same width and points at the regions that changed.

Step 5: If anything looks wrong, swap back

You have two ways back, and neither involves rebuilding anything:

  • Ledger rollback: ask the agent to run rollback-change on the assign-menu-location entry. It needs explicit confirmation and verifies the restored state against the stored before-image.
  • Plain re-assign: put the old menu back into the location with another assign-menu-location call. The old menu was never edited, so it comes back exactly as it was.

Once the new menu has been live for a week or two and nobody has complained, rename it with update-menu and delete the old one by hand, or with delete-menu and confirmation, knowing it's permanent.

What this pattern doesn't protect you from

  • Creating and editing items isn't the reversible part. The docs promise ledger rollback for the location assignment. They don't make that promise for create-menu or upsert-menu-item. That's why you build on a menu nobody sees.
  • Theme-specific extras. Mega-menu settings, icons or CSS classes added by a theme or plugin may live outside what list-menu-items returns. Check any menu that relies on them by hand.
  • Caching. A page cache can keep serving the old header for a while after the swap. Purge it before you judge the result.
  • It's not a backup. Take one before any live change, as always.

Why bother with an agent at all?

For a five-item menu, don't. Where this pays off is the messy one: 40 items, three levels, half of them custom URLs someone pasted in 2019. Having the agent map every item to a real object, flag dead targets and produce a before/after diff is the tedious part, and it's all reads. The only write that touches visitors is a single location swap you can undo.


Links

What's the worst menu you've inherited? Tell me in the comments.

Top comments (1)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.