diff --git a/src/CP/Navigation/NavItem.php b/src/CP/Navigation/NavItem.php index 7e860638293..dfb95673911 100644 --- a/src/CP/Navigation/NavItem.php +++ b/src/CP/Navigation/NavItem.php @@ -292,6 +292,14 @@ protected function currentUrlIsRestfulDescendant(): bool ]); } + /** + * Check if we should assume nested URL conventions for active state on children. + */ + protected function doesntHaveExplicitChildren(): bool + { + return (bool) ! $this->children; + } + /** * Check if this nav item was ever a child before user preferences were applied. */ @@ -393,6 +401,7 @@ public function isActive() if ($this->currentUrlIsNotExplicitlyReferencedInNav()) { switch (true) { case $this->currentUrlIsRestfulDescendant(): + case $this->doesntHaveExplicitChildren(): case $this->wasOriginallyChild(): return $this->isActiveByPattern($this->active); } diff --git a/tests/CP/Navigation/ActiveNavItemTest.php b/tests/CP/Navigation/ActiveNavItemTest.php index ab560f7ddf1..d59d9f4ac0d 100644 --- a/tests/CP/Navigation/ActiveNavItemTest.php +++ b/tests/CP/Navigation/ActiveNavItemTest.php @@ -536,6 +536,25 @@ public function it_properly_handles_various_edge_cases_when_checking_is_active_o $this->assertFalse($externalSecure->isActive()); } + #[Test] + public function active_nav_descendant_url_still_functions_properly_when_parent_item_has_no_children() + { + Facades\CP\Nav::extend(function ($nav) { + $nav->tools('Schopify')->url('/cp/totally-custom-url'); + }); + + $this + ->prepareNavCaches() + ->get('http://localhost/cp/totally-custom-url/deeper/descendant') + ->assertStatus(200); + + $toolsItems = $this->build()->get('Tools'); + + $this->assertTrue($this->getItemByDisplay($toolsItems, 'Schopify')->isActive()); + $this->assertFalse($this->getItemByDisplay($toolsItems, 'Addons')->isActive()); + $this->assertFalse($this->getItemByDisplay($toolsItems, 'Utilities')->isActive()); + } + #[Test] public function active_nav_check_still_functions_properly_when_custom_nav_extension_hijacks_a_core_item_child() {