SEO-Audit 2026-11-09: Meta-Komposition, Sitemap, Redirects, robots.txt
- VitecMetaHandler: Record-Metadaten fuer News-/Produkt-/Story-Details (Titel, Description, og:/twitter:-Tags, og:image), '| VITEC'-Suffix, Fallback-Description aus Seitenfeldern, twitter:card large_image, Story-Canonical auf die oeffentliche Kurz-URL - PageJsonLdRenderer: Product- und NewsArticle-Nodes auf Detailseiten (News-Details hatten <title>article</title> und kein Schema) - NewsJsonRenderer: Listen ohne Volltext-Body (JSON 2.6 MB -> ~0.6 MB) - XML-Sitemap: News-Teil konfiguriert (Ordner 11+442, Detailseite 21), Record-Sitemaps fuer Produkte und Success Stories (kurze URLs), Route-Enhancer fuer alle Teile, Shell-/Altseiten ausgeschlossen - Migration seo_fixes_20261109: 161 Self-Canonicals geleert (warfen u.a. Home, Markets, Solutions, Support aus der Sitemap), noindex fuer technische und alte News-Seiten, 71 Redirects Alt-URLs -> neue Ziele, 51 tote Footer-Links ersetzt - public/robots.txt mit Sitemap-Verweis Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
be519f9bc1
commit
b9736b9ac7
11 files changed
+814
-25
No files matched your search
@@ -156,7 +156,7 @@ final class NewsJsonRenderer
|
||||
}
|
||||
|
||||
$newsRows = $this->fetchNewsList($contentElement, $settings);
|
||||
$items = array_map(fn (array $newsRow): array => $this->serializeNews($newsRow, $settings), $newsRows);
|
||||
$items = array_map(fn (array $newsRow): array => $this->serializeNews($newsRow, $settings, 'list'), $newsRows);
|
||||
|
||||
$response = [
|
||||
'mode' => 'list',
|
||||
@@ -323,7 +323,7 @@ final class NewsJsonRenderer
|
||||
* @param array<string,mixed> $settings
|
||||
* @return array<string,mixed>
|
||||
*/
|
||||
private function serializeNews(array $news, array $settings = []): array
|
||||
private function serializeNews(array $news, array $settings = [], string $mode = 'detail'): array
|
||||
{
|
||||
$uid = (int)($news['uid'] ?? 0);
|
||||
$pathSegment = (string)($news['path_segment'] ?? '');
|
||||
@@ -338,7 +338,14 @@ final class NewsJsonRenderer
|
||||
'detailUrl' => $urls['detailUrl'],
|
||||
'canonicalUrl' => $urls['canonicalUrl'],
|
||||
'teaser' => (string)($news['teaser'] ?? ''),
|
||||
'bodytext' => RteResolver::html($news['bodytext'] ?? ''),
|
||||
// List payloads do not carry the full article body: with ~600
|
||||
// records that inflated /_json/insights/news to 2.6 MB (and the
|
||||
// SSR HTML to 2.8 MB). Cards render from `teaser`; only records
|
||||
// WITHOUT a teaser get a plain-text excerpt in `bodytext` so no
|
||||
// card goes blank. The detail mode is unchanged.
|
||||
'bodytext' => $mode === 'list'
|
||||
? (trim((string)($news['teaser'] ?? '')) !== '' ? '' : $this->listExcerpt((string)($news['bodytext'] ?? '')))
|
||||
: RteResolver::html($news['bodytext'] ?? ''),
|
||||
'datetime' => (int)($news['datetime'] ?? 0),
|
||||
'archive' => (int)($news['archive'] ?? 0),
|
||||
'istopnews' => (bool)($news['istopnews'] ?? false),
|
||||
@@ -353,6 +360,23 @@ final class NewsJsonRenderer
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Plain-text excerpt of an RTE body for list cards (teaser fallback).
|
||||
*/
|
||||
private function listExcerpt(string $html): string
|
||||
{
|
||||
$text = trim((string)preg_replace('/\s+/u', ' ', strip_tags($html)));
|
||||
if (mb_strlen($text) <= 300) {
|
||||
return $text;
|
||||
}
|
||||
$cut = mb_substr($text, 0, 300);
|
||||
$lastSpace = mb_strrpos($cut, ' ');
|
||||
if ($lastSpace !== false && $lastSpace > 180) {
|
||||
$cut = mb_substr($cut, 0, $lastSpace);
|
||||
}
|
||||
return rtrim($cut, " .,;:") . '...';
|
||||
}
|
||||
|
||||
/**
|
||||
* Where a news item actually points.
|
||||
*
|
||||
|
||||
Reference in new issue
Block a user