web: Entitaeten im JSON-LD verknuepft, News-Sitemap und llms.txt (Roadmap 2.1, 2.2, 2.7)
- App\Support\StructuredData: Portal-Organization als Publisher mit @id und Logo (ImageObject), Newsroom-@id; NewsArticle.author auf der Meldung und Organization auf der Newsroom-Seite beschreiben jetzt dieselbe Entitaet. Startseiten nutzen denselben Publisher. - /sitemap-news.xml je Spoke (NewsSitemapController): im Archiv sichtbare Meldungen der letzten 48 h, max. 1.000, news:publication mit Portalname und Sprache; 15 min gecacht, mit den anderen Sitemaps geleert; in robots.txt der Spokes. Hub liefert leere Liste. - /llms.txt je Host (LlmsTxtController): sachliche Beschreibung, URL-Aufbau, aktive Kategorien, Seiten fuer Unternehmen, Rechtliches; Hub verweist auf beide Portale. Keine Aussagen ueber KI-Nennungen. - Protokoll Teil 5 (Block 2) inkl. Betreiber-Schritten fuer das Publisher Center und Befund zu 2.5/E5; Roadmap 2.1/2.7 abgehakt. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
8cd76df0bb
commit
b60a28dc9c
15 changed files with 521 additions and 23 deletions
|
|
@ -1,10 +1,12 @@
|
|||
@extends('web.layouts.web-master')
|
||||
|
||||
@php
|
||||
use App\Support\StructuredData;
|
||||
|
||||
$brand = config('domains.domains.businessportal24.brand', []);
|
||||
|
||||
// SEO: WebSite-Markup mit Sitelinks-Searchbox (SearchAction auf /suche).
|
||||
$portalBase = rtrim($domainUrl ?? config('app.url'), '/');
|
||||
$portalBase = StructuredData::portalBase($domainUrl ?? null);
|
||||
$brandFullName = ($brand['name'] ?? 'businessportal').($brand['accent'] ?? '24');
|
||||
|
||||
$jsonLd = [
|
||||
|
|
@ -24,11 +26,7 @@
|
|||
'query-input' => 'required name=search_term_string',
|
||||
],
|
||||
],
|
||||
[
|
||||
'@type' => 'Organization',
|
||||
'name' => $brandFullName,
|
||||
'url' => $portalBase.'/',
|
||||
],
|
||||
StructuredData::publisher($portalBase),
|
||||
],
|
||||
];
|
||||
@endphp
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
@extends('web.layouts.web-master')
|
||||
|
||||
@php
|
||||
use App\Support\StructuredData;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
\Carbon\Carbon::setLocale(app()->getLocale());
|
||||
|
|
@ -34,10 +35,11 @@
|
|||
// SEO: Der Newsroom ist die kanonische Firmenseite im Portal —
|
||||
// Organization-Markup verknüpft PMs (author) mit diesem Profil.
|
||||
// Portal-Basis wie beim Canonical im Layout (unabhängig von forceRootUrl).
|
||||
$newsroomUrl = rtrim($domainUrl ?? config('app.url'), '/').'/'.app()->getLocale().'/newsroom/'.$company->slug;
|
||||
$newsroomUrl = StructuredData::newsroomUrl(StructuredData::portalBase($domainUrl ?? null), $company->slug);
|
||||
$jsonLd = [
|
||||
'@context' => 'https://schema.org',
|
||||
'@type' => 'Organization',
|
||||
'@id' => StructuredData::newsroomId($newsroomUrl),
|
||||
'name' => $company->name,
|
||||
'url' => $newsroomUrl,
|
||||
...($company->websiteUrl() ? ['sameAs' => [$company->websiteUrl()]] : []),
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
@extends('web.layouts.web-master')
|
||||
|
||||
@php
|
||||
use App\Support\StructuredData;
|
||||
|
||||
$brand = config('domains.domains.presseecho.brand', []);
|
||||
|
||||
// SEO: WebSite-Markup mit Sitelinks-Searchbox (SearchAction auf /suche).
|
||||
$portalBase = rtrim($domainUrl ?? config('app.url'), '/');
|
||||
$portalBase = StructuredData::portalBase($domainUrl ?? null);
|
||||
$brandFullName = ($brand['name'] ?? 'presse').($brand['accent'] ?? 'echo');
|
||||
|
||||
$jsonLd = [
|
||||
|
|
@ -24,11 +26,7 @@
|
|||
'query-input' => 'required name=search_term_string',
|
||||
],
|
||||
],
|
||||
[
|
||||
'@type' => 'Organization',
|
||||
'name' => $brandFullName,
|
||||
'url' => $portalBase.'/',
|
||||
],
|
||||
StructuredData::publisher($portalBase),
|
||||
],
|
||||
];
|
||||
@endphp
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
@extends('web.layouts.web-master')
|
||||
|
||||
@php
|
||||
use App\Support\StructuredData;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
// Private Vorschau über Magic-Link (/pm-vorschau/{token}): identisches
|
||||
|
|
@ -93,7 +94,8 @@
|
|||
$jsonLd = null;
|
||||
|
||||
if (! $isPreview) {
|
||||
$portalBase = rtrim($domainUrl ?? config('app.url'), '/');
|
||||
$portalBase = StructuredData::portalBase($domainUrl ?? null);
|
||||
$authorNewsroomUrl = $company?->slug ? StructuredData::newsroomUrl($portalBase, $company->slug) : null;
|
||||
|
||||
// dateModified darf laut Google nicht vor datePublished liegen
|
||||
// (updated_at kann bei terminierten PMs älter sein als published_at).
|
||||
|
|
@ -125,12 +127,15 @@
|
|||
'wordCount' => $wordCount ?: null,
|
||||
'inLanguage' => app()->getLocale(),
|
||||
'isAccessibleForFree' => true,
|
||||
// author trägt die @id der Newsroom-Organization (2.1): Meldung
|
||||
// und Newsroom-Seite beschreiben dieselbe Entität.
|
||||
'author' => $companyName ? array_filter([
|
||||
'@type' => 'Organization',
|
||||
'@id' => $authorNewsroomUrl ? StructuredData::newsroomId($authorNewsroomUrl) : null,
|
||||
'name' => $companyName,
|
||||
'url' => $company?->slug ? $portalBase.'/'.app()->getLocale().'/newsroom/'.$company->slug : null,
|
||||
'url' => $authorNewsroomUrl,
|
||||
]) : null,
|
||||
'publisher' => ['@type' => 'Organization', 'name' => $brandLabel, 'url' => $portalBase],
|
||||
'publisher' => StructuredData::publisher($portalBase),
|
||||
], fn ($value) => $value !== null),
|
||||
[
|
||||
'@type' => 'BreadcrumbList',
|
||||
|
|
|
|||
16
resources/views/web/sitemap-news.blade.php
Normal file
16
resources/views/web/sitemap-news.blade.php
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
{!! '<?xml version="1.0" encoding="UTF-8"?>' !!}
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:news="http://www.google.com/schemas/sitemap-news/0.9">
|
||||
@foreach ($entries as $entry)
|
||||
<url>
|
||||
<loc>{{ $entry['loc'] }}</loc>
|
||||
<news:news>
|
||||
<news:publication>
|
||||
<news:name>{{ $entry['publication'] }}</news:name>
|
||||
<news:language>{{ $entry['language'] }}</news:language>
|
||||
</news:publication>
|
||||
<news:publication_date>{{ $entry['published_at'] }}</news:publication_date>
|
||||
<news:title>{{ $entry['title'] }}</news:title>
|
||||
</news:news>
|
||||
</url>
|
||||
@endforeach
|
||||
</urlset>
|
||||
Loading…
Add table
Add a link
Reference in a new issue