4.0.0-beta.1
Pre-release
Pre-release
Added
- Added
MenuCraft element for menu-level fields and public menu queries (craft.navigation.menu(),getMenuByHandle(),getAllMenus()). - Added Menu Fields field layout tab and Menu Content tab in menu settings CP (layout via project config; values saved on the
Menuelement). - Added React CP menu builder (
src/web/) replacing the legacy Garnish build UI. - Added build session staging (
BuildSessionsservice,navigation_build_sessionstable) with publish/discard workflow for structure moves, staged node adds/deletes, and menu content drafts. - Added builder JSON API:
navigation/builder/get-state,save-draft,stage-delete,menu-content-form,save-menu-content,menu-content-slideout; plusnavigation/build-sessions/publishanddiscard. - Added
BuilderState,BuilderSchemaHelper, andBuilderUihelpers for builder bootstrap JSON and dynamic add-node forms. - Added
MenuContentFieldLayouthelper and menu content editing in the builder via Craft CP slide-out (field layout configured on the Menu Fields tab). - Added CP asset bundles
NavigationCpAsset(shared Navigation CP layout) andBuilderAsset(React builder). - Added
NodeType::getAddNodeSchema()andNodeType::getAddNodeDefaultData()so each node type owns its builder quick-add fields;BuilderSchemaHelperonly adds the shared parent field and compiles schema. - Added
NodeType::getEditorHtml()for slide-out editor fields. - Added
NodeTypeSchemaFields,SiteSettings, and consolidated Dynamic node slide-out rendering in PHP helpers (#413). - Added element actions Stage delete and Unstage delete for builder staged deletions.
- Added explicit node type classes:
Entry,Category,Asset,Product,GroupColumn,Dynamic,Custom,Passive, andSiteinverbb\navigation\nodetypes\(Hyper-style short names). - Added Group/column structural node type (
GroupColumn) (#416). - Added unified Dynamic node type with pluggable dynamic sources (
DynamicSourcesservice,RegisterDynamicSourceEvent); built-in sources:entrySection,categoryGroup,assetVolume, andproductType(Commerce). - Added read-time
ProjectedNodeprojection for Dynamic nodes (stored children first, projected appended) (#413). - Added Dynamic node source picker in the builder add panel (searchable combobox) and node editor slide-out; configured source name shown in the node type label (#413).
- Added Dynamic node slide-out settings: entry conditions (Craft condition builder), sort order, and searchable source picker (#413).
- Added
Node::getTag()for passive/group structural nodes (#369). - Added
navigation_nodes_sitestable for per-site link settings (url,urlSuffix,linkedElementSiteId) (#405, #360). - Added menu Title Translation Method settings (matching entry types) so node title overrides propagate across sites by site, site group, language, or custom key (#394).
- Added copy node to site API (
Nodes::copyNodeToSite,navigation/nodes/copy-to-site) (#425). - Added auto-enable new sites plugin setting (#428).
- Added Feed Me mapping for
linkedElementSiteIdon node imports (#405). - Added Context API —
craft.navigation.context(handle)withsiblings(),branch(),ancestors(), etc. (Discussion #368). - Added menu breadcrumbs —
craft.navigation.menuBreadcrumbs(handle)(#335). - Added
craft.navigation.urlBreadcrumbs()for URL-segment breadcrumbs. - Added
NodeReadservice for batched linked-element hydration, in-memory hierarchy wiring, and tree assembly (#341, #412). - Added
NavigationCacheservice with tagged tree caching for front-end nav reads (off,auto,static,manualmodes;lite,standard, andfullprofiles). - Added Performance plugin settings (cache mode, cache profile, static cache duration).
- Added
craft.navigation.invalidateCache()Twig/PHP helper andNavigationCache::EVENT_INVALIDATEfor custom cache-busting integrations (e.g. Blitz) (#367). - Added
withMenu()node query flag to batch-hydrate parent Menu elements (including custom fields) on node reads. - Added
withLinkedElements()query flag to batch-hydrate linked Craft elements after a node query executes (explicit opt-in). - Added smart auto
withNodeHierarchy()behaviour for nav-scoped front-end reads; usewithNodeHierarchy(false)to opt out, orwithNodeHierarchy(true)to force on (#341). - Added
withProjectedChildren(false)node query flag to skip Dynamic node read-time projections (#413). - Added
withNavigationCache()query flag for manual cache mode opt-in. - Added
craft.navigation.tree()options:withLinkedElementsfor opt-in linked element hydration in tree output. - Added
navigation:section:{uid}(and related source) cache tags for Dynamic nodes; invalidated when source elements are saved or deleted (#413). - Added
ActiveMatcherservice for single-pass active-state resolution. - Added
craft.navigation.getActiveNodes()andcraft.navigation.getCurrentNodes()helpers (#418). - Added
currentandhasActiveChildkeys tocraft.navigation.tree()output. - Added GraphQL
{handle}_Menu,navigationContext, andnavigationMenuBreadcrumbsqueries (#325, #335, Discussion #368). - Added GraphQL
withMenu,withProjectedChildren,withLinkedElements, andwithNodeHierarchyarguments for node queries (#413, #422). - Added GraphQL
isProjectedfield,ProjectedNavigationNodetype, and in-memorychildrenresolution for projected nodes (#413). - Added Pest integration and performance test harness with Craft fixture factories.
- Added Pest coverage for build sessions, builder state, menu content saves, Dynamic node builder schema (#413), linked-element lifecycle, and active-state edge cases.
- Added plugin documentation for node query cache/hydration flags, active-state helpers, GraphQL site/language contract, linked-element lifecycle, and cache invalidation (#426).
Changed
- Renamed
Navsservice toMenus(getMenus(),saveMenu(), etc.);getNavs()and related methods remain as deprecated shims. - Renamed DB tables
navigation_navs→navigation_menus,navigation_navs_sites→navigation_menus_sites; node FK columnnavId→menuId;deletedWithNav→deletedWithMenu. - Renamed project config path
navigation.navs→navigation.menus(migrated on upgrade). - Renamed user permissions
navigation-manageNav:{uid}→navigation-manageMenu:{uid}(and related create/edit/delete permissions). - Renamed GraphQL schema components
navigationNavs.*→navigationMenus.*. - Renamed internal settings model to
MenuSettings(distinct from theMenuelement). - CP routes and templates moved from
navigation/navstonavigation/menus(legacy navs URLs redirect to menus controller). - Renamed
craft.navigation.breadcrumbs()tourlBreadcrumbs()(v3 shim retained). - Node
typevalues are now node type class names inverbb\navigation\nodetypes\(e.g.Entry) instead of Craft element FQCNs (migrated on upgrade). - Menu Permissions settings are keyed by node type class names (migrated on upgrade; legacy keys normalized on load/save).
- Dynamic nodes are removed when their source section, category group, volume, or product type is deleted (#385).
- Improved linked-element lifecycle hooks to resolve 4.x node type classes and per-site
linkedElementSiteIdinstead of the legacy slug hack (#386). - Linked-element soft-delete now disables nodes (preserving prior enabled state) instead of deleting them; restore re-enables nodes (#386); hard-delete removes nodes.
- Linked entry title sync respects per-site node title overrides via
hasOverriddenTitle()(#230, #394). - Active-state matching now includes per-site
urlSuffixand is skipped for CP, console, and preview requests (#360, #384). - Improved active-state matching for entry-backed nodes to compare joined element URIs, avoiding mismatches with path-style site URLs (#408).
- Improved site-type nodes to be active for sub-pages on the same site (#435).
- Improved
craft.navigation.getActiveNode()to return the deepest exact URL match (current page) rather than the first branch-active node in structure order; may return a different (deeper) node when multiple nodes match the current URL branch (#418). - Improved
node.hasActiveChild()to use resolved in-memory state instead of querying all descendants; now returns aboolinstead of?bool. - Improved
craft.navigation.render()andcraft.navigation.tree()to build nested output in a single pass viaNodeReadinstead of recursive structure queries. - Improved cache invalidation on menu save/delete, node save/delete/move, with menu/node cache tags alongside existing Craft element cache invalidation; active / ancestor state is always applied after cache hits, never stored in cached payloads.
- Passive/group nodes may render as
<span>instead of<a>viagetTag(); update custom templates that assume all nodes are anchors (#369). - Restructured plugin docs: Menus, Templates, Frontend, GraphQL, Reference, and Integrations sections.
Fixed
- Fixed an error when restoring a soft-deleted menu via project config (#415).
- Fixed N+1 query patterns when accessing
node.childrenon front-end menu reads without hierarchy wiring (#341). - Fixed N+1 query patterns when accessing
node.elementwithoutwithLinkedElements()(#412). - Fixed ancestor active-state propagation firing additional structure queries per nested node (#412).
- Fix per-site custom URLs and link settings are stored in
navigation_nodes_sites, notnavigation_nodes.url/ slug hack (#405, #360).
Deprecated
- Twig / PHP variable API (
NavigationVariableDeprecations):craft.navigation.nav(),getNavByHandle(),getNavById(),getAllNavs(),breadcrumbs(),getRegisteredElements(). Canonical replacements:menu(),getMenuByHandle(),getMenuById(),getAllMenus(),urlBreadcrumbs(),getRegisteredNodeTypes(). - Node element (
NodeDeprecations):getNav(),getIsActive(),setIsActive(). UsegetMenu(),getActive(), andgetActiveState()instead. - Menu element (
MenuDeprecations):getNav(). Use theMenuelement API orgetMenuHandle()instead. - NodeQuery (
NodeQueryDeprecations):nav(),navHandle(),navId(),elementSiteId(). Usemenu(),menuHandle()/handle(),menuId(), and per-site link settings instead. - Node query criteria (Twig
craft.navigation.nodes(), context criteria):navHandle,nav, andnavIdkeys are normalized tomenuHandle/menuIdwith deprecation notices. - GraphQL node queries:
nav,navHandle, andnavIdarguments normalize tomenuHandle/menuId. Node fieldsnavId,navHandle, andnavNameremain available; usemenuId,menuHandle, andmenuNameinstead. - Plugin API (
MenusDeprecations,PluginTrait::getNavs()):getAllNavs(),getNavByHandle(),getNavById(),saveNav(),deleteNav(), etc. UsegetMenus()and the*Menu*equivalents. - Events:
NavEvent→MenuEvent;EVENT_BEFORE_SAVE_NAV→EVENT_BEFORE_SAVE_MENU, etc. Legacy class aliases and$event->navshims added in 4.0.0 — preferMenuEvent/$event->menu. Elementsservice andRegisterElementEvent: useNodeTypesandRegisterNodeTypeEventwithElementNodeTypesubclasses instead.builderLiveStructureplugin setting: structure changes are staged via build sessions by default; the live-save opt-out will be removed in a future release.
Removed
- Removed plugin settings
disabledElementsandpropagateSiteElements. - Removed legacy
_types/*/modal.htmlTwig templates for Site, Custom URL, and Dynamic nodes; slide-out fields render via PHP helpers (#413).