From e037b14ae89018eabd9e3ae0cbc5d857ba304501 Mon Sep 17 00:00:00 2001 From: kjetilhole Date: Mon, 12 Jan 2026 19:39:30 +0100 Subject: [PATCH 1/4] If multisite is enabled, you can now customize the Control Panel navigation per site using each sites handle. --- src/CP/Navigation/NavBuilder.php | 3 ++- .../Preferences/Nav/DefaultNavController.php | 12 +++++++--- .../CP/Preferences/Nav/NavController.php | 14 ++++++++--- .../CP/Preferences/Nav/RoleNavController.php | 12 +++++++--- .../CP/Preferences/Nav/UserNavController.php | 23 ++++++++++++++++--- 5 files changed, 51 insertions(+), 13 deletions(-) diff --git a/src/CP/Navigation/NavBuilder.php b/src/CP/Navigation/NavBuilder.php index 978eb88c76d..ff6e94a96ac 100644 --- a/src/CP/Navigation/NavBuilder.php +++ b/src/CP/Navigation/NavBuilder.php @@ -6,6 +6,7 @@ use Illuminate\Support\Facades\Cache; use Statamic\Facades\Blink; use Statamic\Facades\Preference; +use Statamic\Facades\Site; use Statamic\Facades\User; use Statamic\Support\Arr; use Statamic\Support\Str; @@ -60,7 +61,7 @@ public function withHidden(bool $withHidden = false): self public function build($preferences = true) { if ($preferences === true) { - $preferences = Preference::get('nav'); + $preferences = Preference::get('nav.'.Site::selected()->handle()); } return $this diff --git a/src/Http/Controllers/CP/Preferences/Nav/DefaultNavController.php b/src/Http/Controllers/CP/Preferences/Nav/DefaultNavController.php index 672dda1f624..98fa323850e 100644 --- a/src/Http/Controllers/CP/Preferences/Nav/DefaultNavController.php +++ b/src/Http/Controllers/CP/Preferences/Nav/DefaultNavController.php @@ -5,6 +5,7 @@ use Illuminate\Http\Request; use Statamic\Facades\CP\Nav; use Statamic\Facades\Preference; +use Statamic\Facades\Site; use Statamic\Http\Controllers\Controller; class DefaultNavController extends Controller @@ -16,9 +17,14 @@ protected function ignoreSaveAsOption() return 'default'; } + protected function siteKey() + { + return 'nav.'.Site::selected()->handle(); + } + public function edit() { - $preferences = Preference::default()->get('nav'); + $preferences = Preference::default()->get($this->siteKey()); $nav = Nav::build( preferences: $preferences ?: false, @@ -40,7 +46,7 @@ public function update(Request $request) return $this->destroy(); } - Preference::default()->set('nav', $nav)->save(); + Preference::default()->set($this->siteKey(), $nav)->save(); Nav::clearCachedUrls(); @@ -51,7 +57,7 @@ public function update(Request $request) public function destroy() { - Preference::default()->remove('nav')->save(); + Preference::default()->remove($this->siteKey())->save(); Nav::clearCachedUrls(); diff --git a/src/Http/Controllers/CP/Preferences/Nav/NavController.php b/src/Http/Controllers/CP/Preferences/Nav/NavController.php index 2285918adbd..46d28528f34 100644 --- a/src/Http/Controllers/CP/Preferences/Nav/NavController.php +++ b/src/Http/Controllers/CP/Preferences/Nav/NavController.php @@ -5,27 +5,35 @@ use Inertia\Inertia; use Statamic\Facades\Preference; use Statamic\Facades\Role; +use Statamic\Facades\Site; use Statamic\Facades\User; use Statamic\Http\Controllers\Controller; use Statamic\Statamic; class NavController extends Controller { + protected function siteKey() + { + return 'nav.'.Site::selected()->handle(); + } + public function index() { if (! Statamic::pro() || User::current()->cannot('manage preferences')) { return redirect(cp_route('preferences.nav.user.edit')); } + $siteKey = $this->siteKey(); + return Inertia::render('preferences/nav/Index', [ - 'userPreferences' => User::current()->hasPreference('nav') ? ['nav' => true] : [], + 'userPreferences' => User::current()->hasPreference($siteKey) ? ['nav' => true] : [], 'userPreferencesUrl' => cp_route('preferences.nav.user.edit'), - 'defaultPreferences' => Preference::default()->hasPreference('nav') ? ['nav' => true] : [], + 'defaultPreferences' => Preference::default()->hasPreference($siteKey) ? ['nav' => true] : [], 'defaultPreferencesUrl' => cp_route('preferences.nav.default.edit'), 'roles' => Role::all()->map(fn ($role) => [ 'handle' => $role->handle(), 'title' => __($role->title()), - 'preferences' => $role->hasPreference('nav') ? ['nav' => true] : [], + 'preferences' => $role->hasPreference($siteKey) ? ['nav' => true] : [], 'editUrl' => cp_route('preferences.nav.role.edit', [$role->handle()]), ])->values(), ]); diff --git a/src/Http/Controllers/CP/Preferences/Nav/RoleNavController.php b/src/Http/Controllers/CP/Preferences/Nav/RoleNavController.php index 54d1b767363..c096ebbeae0 100644 --- a/src/Http/Controllers/CP/Preferences/Nav/RoleNavController.php +++ b/src/Http/Controllers/CP/Preferences/Nav/RoleNavController.php @@ -7,6 +7,7 @@ use Statamic\Facades\CP\Nav; use Statamic\Facades\Preference; use Statamic\Facades\Role; +use Statamic\Facades\Site; use Statamic\Http\Controllers\Controller; use function Statamic\trans as __; @@ -22,13 +23,18 @@ protected function ignoreSaveAsOption() return $this->currentHandle; } + protected function siteKey() + { + return 'nav.'.Site::selected()->handle(); + } + public function edit($handle) { throw_unless($role = Role::find($handle), new NotFoundHttpException); $this->currentHandle = $handle; - $preferences = $role->getPreference('nav') ?? Preference::default()->get('nav'); + $preferences = $role->getPreference($this->siteKey()) ?? Preference::default()->get($this->siteKey()); $nav = Nav::build( preferences: $preferences ?: false, @@ -48,7 +54,7 @@ public function update(Request $request, $handle) $nav = $this->getUpdatedNav($request); - $role->setPreference('nav', $nav)->save(); + $role->setPreference($this->siteKey(), $nav)->save(); Nav::clearCachedUrls(); @@ -61,7 +67,7 @@ public function destroy($handle) { throw_unless($role = Role::find($handle), new NotFoundHttpException); - $role->removePreference('nav')->save(); + $role->removePreference($this->siteKey())->save(); Nav::clearCachedUrls(); diff --git a/src/Http/Controllers/CP/Preferences/Nav/UserNavController.php b/src/Http/Controllers/CP/Preferences/Nav/UserNavController.php index 6adbee28480..664da7e6ce0 100644 --- a/src/Http/Controllers/CP/Preferences/Nav/UserNavController.php +++ b/src/Http/Controllers/CP/Preferences/Nav/UserNavController.php @@ -4,6 +4,7 @@ use Illuminate\Http\Request; use Statamic\Facades\CP\Nav; +use Statamic\Facades\Site; use Statamic\Facades\User; use Statamic\Http\Controllers\Controller; @@ -16,16 +17,32 @@ protected function ignoreSaveAsOption() return 'user'; } + protected function siteKey() + { + return 'nav.'.Site::selected()->handle(); + } + public function edit() { - return $this->navBuilder(); + $preferences = User::current()->getPreference($this->siteKey()); + + $nav = Nav::build( + preferences: $preferences ?: false, + editing: true, + ); + + return $this->navBuilder($nav, [ + 'title' => __('My Nav'), + 'updateUrl' => cp_route('preferences.nav.user.update'), + 'destroyUrl' => cp_route('preferences.nav.user.destroy'), + ]); } public function update(Request $request) { $nav = $this->getUpdatedNav($request); - User::current()->setPreference('nav', $nav)->save(); + User::current()->setPreference($this->siteKey(), $nav)->save(); Nav::clearCachedUrls(); @@ -36,7 +53,7 @@ public function update(Request $request) public function destroy() { - User::current()->removePreference('nav')->save(); + User::current()->removePreference($this->siteKey())->save(); Nav::clearCachedUrls(); From 47bbcb4b54cd1c67d6dd53f487799648430c0cb6 Mon Sep 17 00:00:00 2001 From: kjetilhole Date: Mon, 12 Jan 2026 20:09:31 +0100 Subject: [PATCH 2/4] Makes "Reset nav customizations" update the UI --- resources/js/pages/preferences/nav/Edit.vue | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/resources/js/pages/preferences/nav/Edit.vue b/resources/js/pages/preferences/nav/Edit.vue index fe721b8751e..bf14c459d95 100644 --- a/resources/js/pages/preferences/nav/Edit.vue +++ b/resources/js/pages/preferences/nav/Edit.vue @@ -291,6 +291,17 @@ export default { this.addToCommandPalette(); }, + watch: { + nav: { + handler(newNav) { + this.initialNav = clone(newNav); + this.setInitialNav(newNav); + this.changed = false; + }, + deep: true, + }, + }, + computed: { isDirty() { return this.changed; From 2b6ae308548e3cc890d82b6012ffb35af6da0212 Mon Sep 17 00:00:00 2001 From: kjetilhole Date: Mon, 12 Jan 2026 20:26:46 +0100 Subject: [PATCH 3/4] Revert --- resources/js/pages/preferences/nav/Edit.vue | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/resources/js/pages/preferences/nav/Edit.vue b/resources/js/pages/preferences/nav/Edit.vue index bf14c459d95..fe721b8751e 100644 --- a/resources/js/pages/preferences/nav/Edit.vue +++ b/resources/js/pages/preferences/nav/Edit.vue @@ -291,17 +291,6 @@ export default { this.addToCommandPalette(); }, - watch: { - nav: { - handler(newNav) { - this.initialNav = clone(newNav); - this.setInitialNav(newNav); - this.changed = false; - }, - deep: true, - }, - }, - computed: { isDirty() { return this.changed; From a92353079c4872ece86dc4996ae2c126e99e04b3 Mon Sep 17 00:00:00 2001 From: kjetilhole Date: Mon, 12 Jan 2026 20:30:23 +0100 Subject: [PATCH 4/4] Updates UI when clicking "Reset nav customizations" --- resources/js/pages/preferences/nav/Edit.vue | 25 +++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/resources/js/pages/preferences/nav/Edit.vue b/resources/js/pages/preferences/nav/Edit.vue index fe721b8751e..526d3529e84 100644 --- a/resources/js/pages/preferences/nav/Edit.vue +++ b/resources/js/pages/preferences/nav/Edit.vue @@ -694,8 +694,17 @@ export default { this.$axios .delete(this.destroyUrl) .then(() => { - router.reload(); - this.confirmingReset = false; + router.reload({ + preserveState: false, + preserveScroll: true, + onSuccess: (page) => { + const nav = page?.props?.nav ?? this.nav; + this.initialNav = clone(nav); + this.setInitialNav(nav); + this.changed = false; + this.confirmingReset = false; + }, + }); }) .catch(() => this.$toast.error(__('Something went wrong'))); }, @@ -714,8 +723,16 @@ export default { this.$axios .patch(url, { tree }) .then(() => { - router.reload(); - this.changed = false; + router.reload({ + preserveState: false, + preserveScroll: true, + onSuccess: (page) => { + const nav = page?.props?.nav ?? this.nav; + this.initialNav = clone(nav); + this.setInitialNav(nav); + this.changed = false; + }, + }); }) .catch(() => this.$toast.error(__('Something went wrong'))); },