*/ private const HUB_PAGES = [ 'faq', 'hilfe', 'gute-pressemitteilung', 'api', 'kuendigung', 'was-kostet-eine-pressemitteilung', 'pressemitteilung-veroeffentlichen-ohne-abo', 'pressemitteilung-loeschen-oder-aendern-lassen', 'impressum', 'datenschutz', 'agb', 'richtlinien', 'melden', ]; /** @var list */ private const PORTAL_PAGES = [ 'preise', 'veroeffentlichen', 'newsrooms', 'faq', 'hilfe', 'gute-pressemitteilung', 'api', 'was-kostet-eine-pressemitteilung', 'pressemitteilung-veroeffentlichen-ohne-abo', 'pressemitteilung-loeschen-oder-aendern-lassen', 'impressum', 'datenschutz', 'agb', 'richtlinien', 'melden', ]; public function __invoke(Request $request): Response { $host = $request->getHost(); $base = rtrim($request->getSchemeAndHttpHost(), '/'); $isHub = str_contains($host, 'pressekonto'); $xml = Cache::remember('web.sitemap.'.$host, 3600, function () use ($base, $isHub): string { $urls = $isHub ? $this->hubUrls($base) : $this->portalUrls($base); return view('web.sitemap', ['urls' => $urls])->render(); }); return response($xml, 200, ['Content-Type' => 'application/xml; charset=UTF-8']); } /** * @return list */ private function hubUrls(string $base): array { $urls = [['loc' => $base.'/', 'lastmod' => null]]; foreach (self::HUB_PAGES as $page) { $urls[] = ['loc' => $base.'/de/'.$page, 'lastmod' => null]; } return $urls; } /** * @return list */ private function portalUrls(string $base): array { $context = WebPortalContext::fromRequest(); $urls = [['loc' => $base.'/de', 'lastmod' => null]]; foreach (self::PORTAL_PAGES as $page) { $urls[] = ['loc' => $base.'/de/'.$page, 'lastmod' => null]; } // Kategorien über die lokalisierten Slugs (CategoryTranslation), // dazu je Kategorie die Jahresarchive (2.3). $categories = Category::query() ->where('is_active', true) ->whereIn('portal', $context->portalValues) ->with(['translations', 'children' => fn ($query) => $query->where('is_active', true)]) ->get(); foreach ($categories as $category) { $slug = $category->translations->firstWhere('locale', 'de')?->slug; if (! $slug) { continue; } $urls[] = ['loc' => $base.'/de/category/'.$slug, 'lastmod' => null]; $categoryIds = $category->children->pluck('id')->prepend($category->id)->unique()->values()->all(); foreach (array_keys(CategoryArchivePageData::yearsWithCounts($categoryIds, $context->portalValues, 'de')) as $year) { $urls[] = ['loc' => $base.'/de/category/'.$slug.'/archiv/'.$year, 'lastmod' => null]; } } // Öffentliche Newsrooms: aktive Firmen mit mindestens einer im Archiv // sichtbaren PM des Portals (gleiche Regel wie NewsroomsPageData). $companies = Company::query() ->where('is_active', true) ->whereHas('pressReleases', fn ($query) => $query ->withoutGlobalScope(PortalScope::class) ->visibleInArchive() ->forPortalValues($context->portalValues)) ->get(['slug', 'updated_at']); foreach ($companies as $company) { $urls[] = [ 'loc' => $base.'/de/newsroom/'.$company->slug, 'lastmod' => $company->updated_at?->toAtomString(), ]; } // Alle im Archiv sichtbaren Pressemitteilungen des Portals. $releases = PressRelease::query() ->withoutGlobalScope(PortalScope::class) ->visibleInArchive() ->forPortalValues($context->portalValues) ->orderByDesc('published_at') ->get(['slug', 'published_at', 'updated_at']); foreach ($releases as $release) { $urls[] = [ 'loc' => $base.'/de/press-release/'.$release->slug, 'lastmod' => ($release->updated_at ?? $release->published_at)?->toAtomString(), ]; } return $urls; } }