We built DEV3 AI Mega Menu as a WordPress plugin in PHP with a React admin and a dependency-free front-end script. It works with the menus WordPress already has (the same ones as Appearance → Menus) and stores its own settings in post meta on each menu item.
Key design decisions
- Refs, not URLs. Build my menu sends the model an inventory of the site's published pages, post categories, product categories and best-selling products, each with a ref such as
page:42 or product_cat:19. The model must answer with those refs. Menu_Builder::from_ai() drops any node whose ref isn't in the allowlist, and resolve() turns the rest into real menu items with an object id, so WordPress generates the permalink.
- Every AI result is a draft. The build, labels, audit, promo and icon routes return drafts and save nothing. The admin reviews, edits or removes rows, then accepts. Label drafts that name an item id outside the menu are thrown away.
- A rules audit that runs without AI. The Quick audit checks depth, top-level count, crowded groups, vague and long labels, duplicates, links to deleted or unpublished content, dead-end items and missing Home, Contact and Shop links, and scores the menu from 0 to 100. The AI review adds label and grouping advice on top, and its suggested links pass the same allowlist.
- Server-rendered, crawlable markup. The menu is plain HTML from PHP: every item with a destination is a real
<a href> in the page source, panels are in the DOM before any script runs, and the front end makes no AI or remote calls, so full-page caching works.
- The WAI disclosure pattern. Links stay links; each submenu gets a separate
<button> with aria-expanded and aria-controls. Items without a URL become a single button. Tabbed panels follow the ARIA tabs pattern, and the off-canvas drawer traps focus and closes on Escape.
- One renderer, many placements. Classic theme locations, a block, automatic replacement of the Navigation block in block themes, a shortcode, an Elementor widget and a WPBakery element all call the same
Renderer.
Architecture
A Tree class reads and saves nested menus, flags items whose target was deleted or unpublished, and caps a menu at 600 items. The Renderer builds the nav markup, mega panels with automatic columns or custom 12-column rows, and widgets for recent posts, WooCommerce products, search, images, promos, HTML, shortcodes and synced patterns. Styles are CSS custom properties, so five presets and any custom style share one cacheable stylesheet. The AI tools use structured JSON output with versioned, filterable prompt templates, a monthly budget, a request cache and usage logs. The API client and the settings screens come from a shared core used across DEV3's plugins.