@php // Build a deduplicated menu: dynamic items from DB + fallback hardcoded links $dynamicLabels = $headerMenu->pluck('label')->map(fn($l) => mb_strtolower(trim($l)))->toArray(); $dynamicUrls = $headerMenu->map(fn($m) => rtrim($m->url ?? '', '/'))->filter()->toArray(); $hardcodedLinks = [ ['label' => __('Meal Plans'), 'url' => route('meal-plans.index'), 'route' => 'meal-plans.*'], ['label' => __('Market'), 'url' => route('meals.index'), 'route' => 'meals.*'], ['label' => __('Blog'), 'url' => route('blog.index'), 'route' => 'blog.*'], ['label' => __('FAQs'), 'url' => '/#faq', 'route' => null], ]; // Only keep hardcoded links that aren't already in the dynamic menu $extraLinks = collect($hardcodedLinks)->filter(function ($link) use ($dynamicLabels, $dynamicUrls) { $labelMatch = in_array(mb_strtolower(trim($link['label'])), $dynamicLabels); $urlMatch = in_array(rtrim($link['url'], '/'), $dynamicUrls); return !$labelMatch && !$urlMatch; }); /** * Returns true when the given URL is "active" for the current request. * * Active when: * • Current path exactly matches the link's path, OR * • Current path is a child of the link's path (prefix match), which * covers child routes such as /blog/my-post matching /blog. * * Never active when: * • The link is a fragment-only anchor on the home page (e.g. /#faq). * Those are handled client-side by the IntersectionObserver below. * • The link points to an external host. * • The link path is "/" and the current path is not exactly "/". */ $isActiveUrl = function (string $url): bool { $currentPath = '/' . ltrim(request()->path(), '/'); $parsed = parse_url($url); $linkPath = rtrim($parsed['path'] ?? '/', '/') ?: '/'; // Fragment-only links on home (e.g. /#faq) — handled by JS observer if ($linkPath === '/' && !empty($parsed['fragment'])) { return false; } // External URLs if (!empty($parsed['host']) && $parsed['host'] !== request()->getHost()) { return false; } // Home "/" — exact match only (avoids marking every page active) if ($linkPath === '/') { return $currentPath === '/'; } // Exact match OR prefix/child-route match return $currentPath === $linkPath || str_starts_with($currentPath, $linkPath . '/'); }; /** * Combines named-route pattern matching with URL-path matching so * callers need a single call for extra/hardcoded links. * * Named-route patterns (e.g. "blog.*") are checked first because they * are faster and also cover URL structures that differ from the link href. */ $isActiveLink = function (array $link) use ($isActiveUrl): bool { if (!empty($link['route']) && request()->routeIs($link['route'])) { return true; } return $isActiveUrl($link['url'] ?? ''); }; @endphp