github verbb/navigation 4.0.0

8 hours ago

{warning} Before upgrading to Navigation 4, review the Upgrading from v3 guide for breaking changes and required migration steps.

Breaking Changes

  • Menu builder changes are now staged until the menu is saved. Editors must save the menu to publish node additions, deletions, and structure changes.
  • craft.navigation.getActiveNode() now returns the deepest exact current-page match instead of the first active ancestor.
  • Custom URLs no longer expand environment variables or Craft aliases. Use relative URLs, literal destinations, or the {site.baseUrl} token.

Added

  • Added a React control panel menu builder with staged build sessions for structure moves, node additions and deletions, and menu content drafts, including publish and discard workflows.
  • Added a Menu Craft element with menu-level custom fields, public menu queries, and dedicated Menu Fields and Menu Content editing interfaces.
  • Added explicit node type classes and extensible schemas and editors for node creation and editing (#413).
  • Added the Group/column structural node type (#416) and Node::getTag() support for passive and structural nodes (#369).
  • Added a unified Dynamic node type with extensible entry, category, asset, and Commerce product sources; read-time projected children; source conditions and ordering; optional limits; and pending/preview projections (#413).
  • Added per-site node link settings for URLs, suffixes, and linked elements (#405, #360).
  • Added menu title translation settings so node title overrides can propagate by site, site group, language, or custom key (#394).
  • Added controls for whether propagated nodes are enabled on other sites by default (#400), an auto-enable-new-sites plugin setting (#428), and Feed Me mapping for per-site linked elements (#405).
  • Added node copying between sites with per-copy element remapping (#425, #453).
  • Added migration support for MenuBuilder, Navkit, and FreeNav menus, including compatible hierarchy, site, element-link, attribute, and dynamic-source data.
  • Added the Context API through craft.navigation.context(handle), including sibling, branch, and ancestor helpers (Discussion #368).
  • Added menu breadcrumbs through craft.navigation.menuBreadcrumbs(handle) (#335) and URL-segment breadcrumbs through craft.navigation.urlBreadcrumbs().
  • Added batched linked-element hydration, in-memory hierarchy wiring, and tree assembly through the NodeRead service (#341, #412).
  • Added tagged front-end navigation caching with configurable modes and profiles, plus craft.navigation.invalidateCache() and NavigationCache::EVENT_INVALIDATE for custom cache integrations (#367).
  • Added node query controls for menu, linked-element, hierarchy, projected-child, and navigation-cache hydration, including automatic hierarchy wiring for navigation-scoped reads (#341, #413).
  • Added single-pass active-state resolution, craft.navigation.getActiveNodes(), craft.navigation.getCurrentNodes(), and current and hasActiveChild tree output (#418).
  • Added GraphQL menu, navigation context, and menu breadcrumb queries (#325, #335, Discussion #368), plus node hydration arguments and projected-node schema support (#413, #422).
  • Added an indicator when an element-linked node has a custom title and no longer follows its linked element’s title.
  • Added Pest integration and coverage for build sessions, builder state, menu content, Dynamic node schemas, linked-element lifecycles, and active-state behavior (#413).
  • Added documentation for node query cache and hydration controls, active-state helpers, GraphQL site and language behavior, linked-element lifecycles, and cache invalidation (#426).

Changed

  • Navigation now requires Craft CMS 5.9.11 or later.
  • Renamed the Navs service and related APIs, database tables and columns, project config paths, permissions, GraphQL schema components, control panel routes, templates, events, and internal settings from “nav” to “menu”; deprecated compatibility shims and redirects remain where documented.
  • Node type values and menu permission settings now use Navigation node type class names and are migrated automatically.
  • Dynamic nodes are removed when their source section, category group, volume, or product type is deleted (#385).
  • Linked-element lifecycle handling now uses node type classes and per-site linked elements (#386); soft deletion disables nodes while preserving their previous state, restoration re-enables them, and hard deletion removes them.
  • Linked entry title synchronization now respects per-site node title overrides (#230, #394).
  • Active-state matching now includes per-site URL suffixes and skips control panel, console, and preview requests (#360, #384).
  • Improved active-state matching for entry-backed nodes on sites with path-based URLs (#408), site nodes on descendant pages (#435), and duplicate URL matches by returning the deepest current-page match (#418).
  • Improved node.hasActiveChild(), craft.navigation.render(), and craft.navigation.tree() to use resolved in-memory hierarchy and active-state data instead of recursive structure queries.
  • Improved cache invalidation for menu and node changes; active and ancestor state is applied after cache hits rather than stored in cached payloads.
  • Dynamic projections now default to Craft’s live/public statuses, with non-live sources available only through explicit pending or preview reads.
  • Author-supplied URL, class, and custom-attribute tokens now render in Craft’s sandboxed Twig environment with bounded site context. Custom URLs no longer expand environment variables or aliases; use a relative URL, literal destination, or the sandboxed {site.baseUrl} token.
  • Passive and group nodes can render as <span> rather than <a> through getTag(); custom templates that assume every node is an anchor must be updated (#369).
  • Restructured the plugin documentation into Menus, Templates, Frontend, GraphQL, Reference, and Integrations sections.

Fixed

  • Fixed cross-site node copies losing their hierarchy or returning empty node.children, including cached level-scoped queries (#452).
  • Fixed an error when restoring a soft-deleted menu through project config (#415).
  • Fixed N+1 queries when reading node.children without pre-wired hierarchy data (#341), reading node.element without linked-element hydration, and propagating ancestor active states (#412).
  • Fixed per-site custom URLs and link settings being stored against shared node data instead of the corresponding site (#405, #360).

Deprecated

  • Deprecated craft.navigation.nav(), getNavByHandle(), getNavById(), getAllNavs(), breadcrumbs(), and getRegisteredElements() in favor of the corresponding menu, URL breadcrumb, and node type APIs.
  • Deprecated Node::getNav(), getIsActive(), and setIsActive() in favor of getMenu(), getActive(), and getActiveState().
  • Deprecated Menu::getNav() in favor of the Menu element API or getMenuHandle().
  • Deprecated NodeQuery::nav(), navHandle(), navId(), and elementSiteId() in favor of menu(), menuHandle() / handle(), menuId(), and per-site link settings.
  • Deprecated the navHandle, nav, and navId node query criteria keys in favor of handle and menuId.
  • Deprecated the nav, navHandle, and navId GraphQL node query arguments in favor of menuHandle and menuId, and the navId, navHandle, and navName fields in favor of their menu* equivalents.
  • Deprecated the Navs plugin API, PluginTrait::getNavs(), NavEvent, EVENT_*_NAV events, and $event->nav in favor of their Menu equivalents.
  • Deprecated the Elements service and RegisterElementEvent in favor of NodeTypes and RegisterNodeTypeEvent with ElementNodeType subclasses.
  • Deprecated the builderLiveStructure plugin setting; structure changes are staged through build sessions by default.

Removed

  • Removed the disabledElements and propagateSiteElements plugin settings.
  • Removed the legacy _types/*/modal.html Twig templates for Site, Custom URL, and Dynamic nodes; slide-out fields now render through PHP helpers (#413).

Don't miss a new navigation release

NewReleases is sending notifications on new releases.