diff --git a/docs/anleitungen/SEO_ERWEITERUNG.md b/docs/anleitungen/SEO_ERWEITERUNG.md index 595a391..03f5d28 100644 --- a/docs/anleitungen/SEO_ERWEITERUNG.md +++ b/docs/anleitungen/SEO_ERWEITERUNG.md @@ -1,9 +1,60 @@ # SEO-Erweiterung +*Letzte Aktualisierung: 18. Dezember 2025* + ## Übersicht Diese Dokumentation beschreibt die implementierten SEO-Features für das Payload CMS Multi-Tenant System. +**Wichtig:** Frontends verwenden die **Production-API** (cms.c2sgmbh.de) für SEO-Daten, um konsistente Meta-Tags und Structured Data zu gewährleisten. + +--- + +## API-Endpoints für Frontend + +### SEO-Daten abrufen + +| Endpoint | Beschreibung | +|----------|--------------| +| `GET /api/globals/seo-settings` | Globale SEO-Konfiguration | +| `GET /api/pages?where[slug][equals]=...` | Page-spezifische SEO (meta-Feld) | +| `GET /api/posts?where[slug][equals]=...` | Post-spezifische SEO | + +### Beispiel: SEO-Settings laden + +```typescript +// Frontend: SEO-Defaults aus Production laden +const seoSettings = await fetch('https://cms.c2sgmbh.de/api/globals/seo-settings') + .then(r => r.json()) + +// Enthält: +// - metaDefaults (titleSuffix, defaultDescription, defaultImage) +// - organization (name, legalName, logo, foundingDate) +// - contact (email, phone, fax) +// - address (street, city, country, etc.) +// - socialProfiles (Array) +// - localBusiness (type, priceRange, openingHours) +// - robots (indexing, additionalDisallow) +// - verification (google, bing, yandex) +``` + +### Beispiel: Page-SEO laden + +```typescript +// Page mit SEO-Daten laden +const page = await fetch( + 'https://cms.c2sgmbh.de/api/pages?where[slug][equals]=about&where[tenant][equals]=4&locale=de' +).then(r => r.json()) + +// page.docs[0].meta enthält: +// - title (Page-spezifischer Titel) +// - description (Meta-Description) +// - image (OG-Image Override) +// - noIndex, noFollow (Indexierungssteuerung) +``` + +--- + ## Implementierte Features ### 1. Dynamische Sitemap (`/sitemap.xml`) @@ -16,6 +67,7 @@ Die Sitemap wird dynamisch aus der Datenbank generiert und enthält: - Alle veröffentlichten Posts mit typ-basierter URL (Priorität: 0.6, Änderungshäufigkeit: monatlich) **URL-Schema für Posts:** + | Post-Typ | URL-Prefix | |----------|------------| | blog | `/blog/{slug}` | @@ -42,8 +94,8 @@ Allow: / Disallow: /admin Disallow: /api -Host: https://pl.c2sgmbh.de -Sitemap: https://pl.c2sgmbh.de/sitemap.xml +Host: https://cms.c2sgmbh.de +Sitemap: https://cms.c2sgmbh.de/sitemap.xml ``` ### 3. Structured Data (JSON-LD) @@ -69,12 +121,26 @@ Bietet Helper-Funktionen für Schema.org-konforme JSON-LD Daten: | `combineSchemas()` | Kombiniert mehrere Schemas | | `renderJsonLd()` | Sicheres Rendering von JSON-LD | -#### Verwendungsbeispiel +#### Verwendungsbeispiel (Frontend) ```tsx +// src/components/seo/JsonLd.tsx import { generateArticleSchema, renderJsonLd } from '@/lib/structuredData' -export default function BlogPost({ post }) { +interface BlogPostProps { + post: { + title: string + excerpt: string + slug: string + publishedAt: string + updatedAt: string + author?: { name: string } + featuredImage?: { url: string } + categories?: Array<{ title: string }> + } +} + +export default function BlogPost({ post }: BlogPostProps) { const schema = generateArticleSchema({ title: post.title, description: post.excerpt, @@ -84,7 +150,7 @@ export default function BlogPost({ post }) { author: post.author, featuredImage: post.featuredImage, categories: post.categories, - }, 'https://example.com') + }, 'https://complexcaresolutions.de') // Tenant-Domain return ( <> @@ -149,6 +215,117 @@ Globale SEO-Konfiguration im Admin-Panel unter "Einstellungen > SEO Einstellunge - Bing Webmaster Tools - Yandex Webmaster +--- + +## Frontend-Integration + +### Next.js Metadata API + +```typescript +// src/app/[locale]/page.tsx +import type { Metadata } from 'next' + +async function getSeoSettings() { + const res = await fetch('https://cms.c2sgmbh.de/api/globals/seo-settings', { + next: { revalidate: 3600 } // 1 Stunde Cache + }) + return res.json() +} + +async function getPage(slug: string, tenantId: number, locale: string) { + const res = await fetch( + `https://cms.c2sgmbh.de/api/pages?where[slug][equals]=${slug}&where[tenant][equals]=${tenantId}&locale=${locale}`, + { next: { revalidate: 60 } } + ) + return res.json() +} + +export async function generateMetadata({ params }): Promise { + const seoSettings = await getSeoSettings() + const pageData = await getPage(params.slug || 'home', 4, params.locale) + const page = pageData.docs[0] + + const title = page?.meta?.title + ? `${page.meta.title} ${seoSettings.metaDefaults?.titleSuffix || ''}` + : seoSettings.metaDefaults?.titleSuffix + + const description = page?.meta?.description + || seoSettings.metaDefaults?.defaultDescription + + const image = page?.meta?.image?.url + || seoSettings.metaDefaults?.defaultImage?.url + + return { + title, + description, + openGraph: { + title, + description, + images: image ? [{ url: image }] : [], + type: 'website', + }, + twitter: { + card: 'summary_large_image', + title, + description, + images: image ? [image] : [], + }, + robots: { + index: !page?.meta?.noIndex, + follow: !page?.meta?.noFollow, + }, + } +} +``` + +### Verification Meta Tags + +```typescript +// src/app/layout.tsx +export async function generateMetadata(): Promise { + const seoSettings = await getSeoSettings() + + return { + verification: { + google: seoSettings.verification?.google, + // Bing und Yandex als other + other: { + 'msvalidate.01': seoSettings.verification?.bing, + 'yandex-verification': seoSettings.verification?.yandex, + }, + }, + } +} +``` + +--- + +## Multi-Tenant SEO + +Jeder Tenant hat eigene SEO-Konfigurationen. Die SEO Settings Global gilt pro Installation, aber Page/Post-SEO ist tenant-spezifisch. + +### Tenant-spezifische Domains + +| Tenant ID | Domain | Sitemap | +|-----------|--------|---------| +| 1 | porwoll.de | https://porwoll.de/sitemap.xml | +| 4 | complexcaresolutions.de | https://complexcaresolutions.de/sitemap.xml | +| 5 | gunshin.de | https://gunshin.de/sitemap.xml | + +### Lokalisierung + +SEO-Felder sind lokalisiert (de/en): + +```typescript +// Deutscher Content +fetch('https://cms.c2sgmbh.de/api/pages?slug=about&tenant=4&locale=de') + +// Englischer Content +fetch('https://cms.c2sgmbh.de/api/pages?slug=about&tenant=4&locale=en') +``` + +--- + ## Datenbank-Tabellen Die Migration `20251130_150000_blocks_tables.ts` erstellt: @@ -159,15 +336,43 @@ Die Migration `20251130_150000_blocks_tables.ts` erstellt: - `seo_settings_local_business_opening_hours` - Öffnungszeiten - `seo_settings_robots_additional_disallow` - Ausgeschlossene Pfade +--- + ## URLs -- **Sitemap:** https://pl.c2sgmbh.de/sitemap.xml -- **Robots:** https://pl.c2sgmbh.de/robots.txt -- **SEO Settings:** https://pl.c2sgmbh.de/admin/globals/seo-settings +### Production (für Frontends) -## Nächste Schritte +| Resource | URL | +|----------|-----| +| **API Base** | https://cms.c2sgmbh.de/api | +| **SEO Settings** | https://cms.c2sgmbh.de/api/globals/seo-settings | +| **Sitemap** | https://cms.c2sgmbh.de/sitemap.xml | +| **Robots** | https://cms.c2sgmbh.de/robots.txt | +| **Admin Panel** | https://cms.c2sgmbh.de/admin/globals/seo-settings | -1. SEO Settings im Admin-Panel konfigurieren -2. JSON-LD in Frontend-Templates einbinden -3. Meta-Tags in Layout integrieren -4. Google Search Console einrichten +### Development + +| Resource | URL | +|----------|-----| +| **API Base** | https://pl.porwoll.tech/api | +| **SEO Settings** | https://pl.porwoll.tech/api/globals/seo-settings | +| **Admin Panel** | https://pl.porwoll.tech/admin/globals/seo-settings | + +--- + +## Checkliste: SEO-Setup pro Tenant + +- [ ] SEO Settings im Admin-Panel konfigurieren +- [ ] Organisation (Name, Logo, Beschreibung) +- [ ] Kontaktdaten und Adresse +- [ ] Social Media Profile hinzufügen +- [ ] Local Business aktivieren (falls relevant) +- [ ] Google Search Console Code eintragen +- [ ] JSON-LD in Frontend-Templates einbinden +- [ ] Meta-Tags in Layout integrieren +- [ ] Sitemap bei Google Search Console einreichen +- [ ] robots.txt prüfen + +--- + +*Letzte Aktualisierung: 18. Dezember 2025*