selectedFamilies($build); if ($families === []) { $this->error('No valid sitemap families selected.'); return self::INVALID; } $diskName = (string) ($this->option('disk') ?: config('sitemaps.static_publish.disk', 'sitemaps_public')); $disk = Storage::disk($diskName); $written = 0; $failed = 0; $this->info('Disk: ' . $diskName); $this->info('Families: ' . implode(', ', $families)); $this->newLine(); // ── Root sitemap index ──────────────────────────────────────────── // Write several paths so nginx `location = /sitemap.xml` and child // listings stay in sync. `sitemaps/index.xml` is the canonical generated // index: it is a new filename, so a scheduler user can create it even // when a stale `sitemaps/sitemap.xml` is owned by another account. $t = microtime(true); $index = $build->buildIndex(force: true, persist: false, families: $families); $indexPaths = ['sitemaps/index.xml', 'sitemaps/sitemap.xml', 'sitemap.xml']; $indexWritten = 0; foreach ($indexPaths as $path) { if ($this->writeXml($disk, $path, $index['content'])) { $written++; $indexWritten++; } } if ($indexWritten === 0) { $this->error('Failed to write any root sitemap index file. Check ownership of public/sitemap.xml and public/sitemaps/.'); return self::FAILURE; } $this->line(sprintf( ' ✔ sitemap index %d entries %d path(s) %.3fs', $index['url_count'], $indexWritten, microtime(true) - $t, )); // ── Per-family documents ────────────────────────────────────────── foreach ($families as $family) { $familyStart = microtime(true); $names = $build->canonicalDocumentNamesForFamily($family); $this->newLine(); $this->line(sprintf(' %s (%d document(s))', $family, count($names))); foreach ($names as $documentName) { $t = microtime(true); $built = $build->buildNamed($documentName, force: true, persist: false); if ($built === null) { $this->line(sprintf(' – %s SKIPPED (builder returned null)', $documentName)); $failed++; continue; } $path = 'sitemaps/' . $documentName . '.xml'; if (! $this->writeXml($disk, $path, $built['content'])) { $this->line(sprintf(' ✖ %s write failed', $documentName . '.xml')); $failed++; continue; } $written++; $this->line(sprintf( ' ✔ %s %d URLs %.3fs', $documentName . '.xml', $built['url_count'] ?? 0, microtime(true) - $t, )); } $this->line(sprintf( ' %s done %.3fs', $family, microtime(true) - $familyStart, )); } foreach ($build->enabledGroupIndexes() as $groupName => $groupFamilies) { foreach ($groupFamilies as $family) { if (! in_array($family, $families, true)) { continue 2; } } $t = microtime(true); $built = $build->buildNamed($groupName, force: true, persist: false); if ($built === null) { $this->line(sprintf(' – %s.xml SKIPPED (group builder returned null)', $groupName)); $failed++; continue; } $path = 'sitemaps/' . $groupName . '.xml'; if (! $this->writeXml($disk, $path, $built['content'])) { $this->line(sprintf(' ✖ %s.xml write failed', $groupName)); $failed++; continue; } $written++; $this->line(sprintf( ' ✔ %s %d entries %.3fs', $groupName . '.xml', $built['url_count'] ?? 0, microtime(true) - $t, )); } // ── Summary ─────────────────────────────────────────────────────── $this->newLine(); $this->info(sprintf( 'Done: %d file(s) written, %d failed total %.3fs', $written, $failed, microtime(true) - $totalStart, )); return $failed > 0 ? self::FAILURE : self::SUCCESS; } /** @return list */ private function selectedFamilies(SitemapBuildService $build): array { $only = []; foreach ((array) $this->option('only') as $value) { foreach (explode(',', (string) $value) as $family) { $normalized = trim($family); if ($normalized !== '') { $only[] = $normalized; } } } $enabled = $build->enabledFamilies(); if ($only === []) { return $enabled; } return array_values(array_filter($enabled, fn (string $f): bool => in_array($f, $only, true))); } private function writeXml(\Illuminate\Contracts\Filesystem\Filesystem $disk, string $path, string $content): bool { $ok = $disk->put($path, $content); if ($ok !== true) { $this->warn(' Could not write '.$path); return false; } return true; } }