From a8244681a864ccf18cfae7ff2ce1a6702e865d24 Mon Sep 17 00:00:00 2001 From: Joshua Blum Date: Tue, 21 Jul 2026 16:41:43 +0200 Subject: [PATCH 1/3] Don't overwrite explicitly set child nav item Ids --- src/CP/Navigation/NavItem.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/CP/Navigation/NavItem.php b/src/CP/Navigation/NavItem.php index 4b79fdc4250..ceec69f8da6 100644 --- a/src/CP/Navigation/NavItem.php +++ b/src/CP/Navigation/NavItem.php @@ -86,6 +86,16 @@ public function id($id = null) ->value($id); } + /** + * Check if an ID has been explicitly set, rather than generated from the display. + * + * @return bool + */ + public function hasCustomId() + { + return ! is_null($this->id); + } + /** * Preserve current ID. * @@ -277,7 +287,7 @@ public function children($items = null, $generateNewIds = true) }) ->map(function ($navItem) use ($generateNewIds) { return $navItem - ->id($generateNewIds ? $this->id().'::' : $navItem->id()) + ->id($generateNewIds && ! $navItem->hasCustomId() ? $this->id().'::' : $navItem->id()) ->icon($navItem->icon() ?? $this->icon()) ->section($this->section()) ->isChild(true); From 078d76697b635300cb7daa88391ca0cf374c45e5 Mon Sep 17 00:00:00 2001 From: Joshua Blum Date: Tue, 21 Jul 2026 16:42:24 +0200 Subject: [PATCH 2/3] Generate Ids from handle --- src/CP/Navigation/CoreNav.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/CP/Navigation/CoreNav.php b/src/CP/Navigation/CoreNav.php index 036e622cd1a..d070b365b0b 100644 --- a/src/CP/Navigation/CoreNav.php +++ b/src/CP/Navigation/CoreNav.php @@ -85,6 +85,7 @@ protected function makeContentSection() }) ->map(function ($collection) { return Nav::item($collection->title()) + ->id('content::collections::'.$collection->handle()) ->url( $collection->sites()->contains(Site::selected()->handle()) ? $collection->showUrl() @@ -122,6 +123,7 @@ protected function makeContentSection() : true; return Nav::item($nav->title()) + ->id('content::navigation::'.$nav->handle()) ->url($availableInSelectedSite ? $nav->showUrl() : $nav->editUrl()) ->can('view', $nav) ->extra([ @@ -145,6 +147,7 @@ protected function makeContentSection() ->children(function () { return TaxonomyAPI::all()->sortBy->title()->map(function ($taxonomy) { return Nav::item($taxonomy->title()) + ->id('content::taxonomies::'.$taxonomy->handle()) ->url($taxonomy->showUrl()) ->can('view', $taxonomy) ->extra([ @@ -168,6 +171,7 @@ protected function makeContentSection() ->children(function () { return AssetContainerAPI::all()->sortBy->title()->map(function ($assetContainer) { return Nav::item($assetContainer->title()) + ->id('content::assets::'.$assetContainer->handle()) ->url($assetContainer->showUrl()) ->can('view', $assetContainer) ->extra([ @@ -198,6 +202,7 @@ protected function makeContentSection() $localized = $globalSet->inSelectedSite(); return Nav::item($globalSet->title()) + ->id('content::globals::'.$globalSet->handle()) ->url($localized ? $localized->editUrl() : $globalSet->editUrl()) ->can('view', $globalSet) ->extra([ @@ -251,6 +256,7 @@ protected function makeToolsSection() ->children(function () { return FormAPI::all()->sortBy->title()->map(function ($form) { return Nav::item($form->title()) + ->id('tools::forms::'.$form->handle()) ->url($form->showUrl()) ->can('view', $form) ->extra(['breadcrumbs' => ['configure_url' => $form->editUrl()]]); From a68f3e9f4916d0cc6941cab709afde2a8d3b927b Mon Sep 17 00:00:00 2001 From: Joshua Blum Date: Tue, 21 Jul 2026 16:43:09 +0200 Subject: [PATCH 3/3] Add a fallback for nav item Ids --- src/CP/Navigation/NavBuilder.php | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/CP/Navigation/NavBuilder.php b/src/CP/Navigation/NavBuilder.php index 2c127de394c..80a8cecf004 100644 --- a/src/CP/Navigation/NavBuilder.php +++ b/src/CP/Navigation/NavBuilder.php @@ -583,7 +583,27 @@ protected function findItem($id, $removeAliasHash = true) } } - return $items->get($id); + return $items->get($id) ?? $this->findItemByLegacyId($id); + } + + /** + * Find existing nav item by the ID it would have been given before child IDs + * were generated from handles, so that preferences saved against the older + * display-based IDs continue to work. + * + * @param string $id + * @return \Statamic\CP\Navigation\NavItem|null + */ + protected function findItemByLegacyId($id) + { + if (! $parent = $this->findParentItem($id)) { + return null; + } + + return $parent + ->resolveChildren() + ->children() + ?->first(fn ($child) => $parent->id().'::'.NavItem::snakeCase($child->display()) === $id); } /**