presseportale/app/Enums/IndexState.php
Kevin Adametz 6b8728242f admin: Indexierungsstatus aus der Search Console, Kundenansicht vorbereitet und zu (Anhang 1: 1c.4, E8)
press-releases:check-index-status fragt täglich je Portal ein Kontingent
veröffentlichter Meldungen über die URL Inspection API ab, nach Alter
gestaffelt, nie geprüfte zuerst. Jede Antwort wird als Momentaufnahme in
press_release_index_checks gespeichert; der reduzierte Befund (IndexState)
trennt „noch nicht gecrawlt" von „gecrawlt, nicht indexiert".

Client authentifiziert sich als Service-Konto über ein selbst signiertes
JWT — kein Google-SDK. Admin ▸ Reports ▸ Indexierung zeigt die Verteilung
je Portal getrennt nach Direkteinreichung und Syndikation (Status-Log
source=api; Altbestand ohne Log zählt als direkt).

Das Kundenpanel heißt jetzt „Auslieferung", zeigt Sitemap-Datum und die
Abrufe durch Such- und KI-Dienste mit dem Satz „Ein Abruf ist kein Zitat";
der Google-Index-Block hängt an GSC_CUSTOMER_VISIBLE (false).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-17 14:21:51 +00:00

62 lines
2.3 KiB
PHP

<?php
namespace App\Enums;
/**
* Befund einer URL-Inspektion, auf das reduziert, was in jeder Anzeige
* unterschieden werden muss (Anhang 17.09.2026, 1c.4): „noch nicht
* gecrawlt" und „gecrawlt, aber nicht indexiert" sind verschiedene Befunde.
*/
enum IndexState: string
{
case Indexed = 'indexed';
case CrawledNotIndexed = 'crawled_not_indexed';
case NotCrawled = 'not_crawled';
case Excluded = 'excluded';
case Unknown = 'unknown';
/**
* @param array<string, mixed> $indexStatus `inspectionResult.indexStatusResult` der URL Inspection API
*/
public static function fromIndexStatus(array $indexStatus): self
{
$verdict = strtoupper((string) ($indexStatus['verdict'] ?? ''));
$coverage = mb_strtolower((string) ($indexStatus['coverageState'] ?? ''));
$indexing = strtoupper((string) ($indexStatus['indexingState'] ?? ''));
$robots = strtoupper((string) ($indexStatus['robotsTxtState'] ?? ''));
$fetch = strtoupper((string) ($indexStatus['pageFetchState'] ?? ''));
$crawled = ! empty($indexStatus['lastCrawlTime']);
if ($verdict === 'PASS' || (str_contains($coverage, 'indexed') && ! str_contains($coverage, 'not indexed'))) {
return self::Indexed;
}
if ($robots === 'DISALLOWED'
|| in_array($indexing, ['BLOCKED_BY_META_TAG', 'BLOCKED_BY_HTTP_HEADER', 'BLOCKED_BY_ROBOTS_TXT'], true)
|| ($fetch !== '' && $fetch !== 'SUCCESSFUL' && $crawled)
|| str_contains($coverage, 'duplicate')
|| str_contains($coverage, 'canonical')
|| str_contains($coverage, 'redirect')
|| str_contains($coverage, 'noindex')
|| str_contains($coverage, 'blocked')) {
return self::Excluded;
}
if (! $crawled) {
return $verdict === '' && $coverage === '' ? self::Unknown : self::NotCrawled;
}
return self::CrawledNotIndexed;
}
public function label(): string
{
return match ($this) {
self::Indexed => 'indexiert',
self::CrawledNotIndexed => 'gecrawlt, nicht indexiert',
self::NotCrawled => 'noch nicht gecrawlt',
self::Excluded => 'ausgeschlossen',
self::Unknown => 'unbekannt',
};
}
}