Mein Platz in der WordPress-Community
- Mein wordpress.org-Konto besteht seit 2006.
- Ich habe zum WordPress-Core in den Versionen 7.0 und 7.1 beigetragen.
- Ich betreue 30 Plugins auf wordpress.org.
- Ich organisiere WordCamps und trete dort als Speaker auf.
- Ich war bei jedem WordCamp Europe von 2017 bis 2026 dabei.
- Lokales WordPress-Meetup: WordPress Meetup Mannheim
Wer in Mannheim eine Schnittstelle für Partner, eine App oder das eigene Portal baut, entscheidet früh über fünf Dinge: wie die Schnittstelle beschrieben wird, wie sie Listen ausliefert, wie sie Fehler meldet, wie sie über Jahre stabil bleibt und wie sich Aufrufer ausweisen. Diese Seite geht die fünf Punkte an einer echten Schnittstelle aus der Stadt durch und zeigt, was ich daraus für Ihre mache. Ich bin Mariusz Szatkowski, PHP-Entwickler aus Gdynia, und arbeite allein, remote und ausschließlich schriftlich.
Eine echte Schnittstelle aus Mannheim als Vorlage
Die Startseite des Open-Data-Portals der Stadt trägt den Titel “Stadt Mannheim Open Data” und läuft auf Opendatasoft. Bei meinem Abruf am 11.11.2026 listete der Katalog 36 Datensätze, darunter Verkehrszähler an Rheinbrücken wie der Konrad-Adenauer-Brücke, Wahlergebnisse, den Bevölkerungsbestand und die E-Ladeparkstände. Alle liegen hinter einer REST-Schnittstelle, der Explore API in Version 2.1. Sie beschreibt sich selbst: Unter /api/explore/v2.1/swagger.json liegt ein OpenAPI-Dokument.
Ein kurzes PHP-Skript (PHP 8.4.27, am 11.11.2026 gegen die Live-Schnittstelle gelaufen) liest dieses Dokument und ruft den Datensatz der E-Ladeparkstände einmal gültig und einmal mit einem zu großen limit ab:
<?php
declare(strict_types=1);
$basis = 'https://mannheim.opendatasoft.com/api/explore/v2.1';
$ctx = stream_context_create(['http' => ['ignore_errors' => true, 'timeout' => 10]]);
$spec = json_decode(file_get_contents("$basis/swagger.json", false, $ctx), true, flags: JSON_THROW_ON_ERROR);
$limit = $spec['components']['parameters']['limit']['schema'];
echo "OpenAPI {$spec['openapi']}, API-Version {$spec['info']['version']}, ", count($spec['paths']), " Pfade\n";
echo "limit: Standard {$limit['default']}, Maximum {$limit['maximum']}\n";
foreach (['limit=2', 'limit=500'] as $query) {
$antwort = file_get_contents("$basis/catalog/datasets/e-ladeparkstande/records?$query", false, $ctx);
preg_match('#HTTP/\S+ (\d{3})#', $http_response_header[0], $m);
$body = json_decode($antwort, true, flags: JSON_THROW_ON_ERROR);
echo "$query: HTTP {$m[1]}, ", $body['error_code'] ?? "total_count {$body['total_count']}", "\n";
}Die Ausgabe:
OpenAPI 3.0.3, API-Version v2.1, 16 Pfade
limit: Standard 10, Maximum 100
limit=2: HTTP 200, total_count 227
limit=500: HTTP 400, InvalidRESTParameterError
Foto: Heinz-Vale, CC BY-SA 4.0, Wikimedia Commons.
Drei Dinge an diesem Beispiel zeigen, worauf es bei jeder eigenen Schnittstelle ankommt. Die Beschreibung ist maschinenlesbar und ein Programm kann Grenzen wie das limit aus ihr lesen. Die Grenze wird tatsächlich durchgesetzt: Der Server antwortet auf limit=500 mit “Invalid value for limit API parameter: 500 was found but -1 <= limit <= 100 is expected.” Und die Fehlerantwort hat ein eigenes Format mit error_code und message. Dazu unten mehr.
Der Vertrag zuerst: OpenAPI als Beschreibung
Die Seite spec.openapis.org führt die Spezifikation in drei Reihen: 3.2 (neueste Fassung 3.2.1), 3.1 (3.1.2) und 3.0 (3.0.4). Was für Ihre Entscheidung zählt, steht in der Spezifikation selbst:
- Seit 3.1 ist das Schema Object laut Spezifikation eine Obermenge von JSON Schema Draft 2020-12. Dieselbe Schemasprache beschreibt also Anfragen, Antworten und Validierung.
- Das Feld
openapinennt die Version der Spezifikation. Es hat laut Text nichts mitinfo.versionzu tun, der Version Ihrer eigenen Schnittstelle. - Die Reihe 3.1 kennt das Feld
webhooksfür Aufrufe, die der Anbieter auslöst, etwa bei einer Bestellung, die Ihr System an einen Partner meldet. - Sicherheitsschemata sind
apiKey,http,mutualTLS,oauth2undopenIdConnect.
Die neueste Reihe ist nicht automatisch die richtige. Maßgeblich ist, was Ihre Werkzeuge lesen:
| Quelle | OpenAPI-Version laut Quelle |
|---|---|
| Mannheimer Explore API | 3.0.3 |
| API Platform | erzeugt standardmäßig 3.2.0, mit spec_version=3.0.0 das ältere Format |
league/openapi-psr7-validator 0.24 | nennt in README und Beschreibung die Reihe 3.0 |
cebe/php-openapi | nennt in der README die Reihe 3.0.x |
Für ein neues Projekt kläre ich deshalb vor dem ersten Endpunkt, welche Version Generator, Dokumentationsseite, Client-Generierung und Testbibliothek gemeinsam lesen, und halte das im Angebot fest. Wenn alle 3.1 oder höher können, nehme ich diese Reihe. Sonst bleibe ich bei 3.0 und wechsle später, wenn die Werkzeuge es tragen.
Die zweite Entscheidung ist die Richtung. Bei der Beschreibung zuerst schreibe ich die OpenAPI-Datei gemeinsam mit Ihrem Partner oder Frontend, bevor Code entsteht. Bei der Beschreibung aus dem Code erzeugt das Framework sie aus Attributen. Für Schnittstellen, die externe Partner nutzen, bevorzuge ich die erste Richtung, weil der Vertrag dann nicht von der Implementierung abhängt.
Laravel Resources oder API Platform
In Laravel steht zwischen den Eloquent-Modellen und dem JSON eine Resource-Klasse. php artisan make:resource UserResource legt sie an, sie erbt von JsonResource, und UserResource::collection() verarbeitet Listen. Die Dokumentation nennt drei Punkte, die für eine Schnittstelle zählen:
- Eine Antwort liegt standardmäßig unter dem Schlüssel
data. Paginierte Antworten tragen zusätzlichlinksundmeta. whenLoadednimmt eine Relation nur auf, wenn sie schon geladen ist. Die Dokumentation nennt als Zweck, “N+1”-Abfragen zu vermeiden.- Die Klasse listet jedes ausgelieferte Feld ausdrücklich. Das ist auch ein Datenschutzwerkzeug: Eine neue Spalte im Modell erscheint nicht von selbst in der Antwort (dazu unten Art. 5 Abs. 1 Buchstabe c DSGVO).
Die Laravel-Dokumentation zu Resources, Routing und Sanctum erwähnt OpenAPI nicht. Bei einer Laravel-Anwendung pflege ich die Beschreibung daher als Datei im Repository und prüfe die Antworten in Tests gegen sie.
API Platform geht den anderen Weg. Die Dokumentation sagt, die Spezifikation sei unter /docs.jsonopenapi erreichbar, bin/console api:openapi:export schreibt sie in eine Datei, und Swagger UI, ReDoc und Scalar sind eingebunden. Die Beispiele in der Dokumentation gelten für Symfony und für Laravel.
| Laravel mit Resources | API Platform | |
|---|---|---|
| Beschreibung | Datei, die ich pflege | wird aus Attributen erzeugt |
| Seitenwerte | links und meta des Paginators | pagination_items_per_page (Standard 30), Obergrenze einstellbar |
| Fehlerformat | eigener Handler, siehe unten | application/problem+json ab Werk |
| Passt, wenn | die Anwendung ohnehin Laravel ist | die Schnittstelle der Kern des Produkts ist |
Seitenweise Daten: limit, offset und ihre Grenzen
Die Mannheimer Beschreibung legt fest: limit hat den Standardwert 10 und das Maximum 100, offset beginnt bei 0. Ohne group_by muss die Summe aus offset und limit unter 10000 bleiben. Mit group_by liegt die Grenze bei 20000. Wer mehr braucht, soll den Endpunkt /exports nutzen. Bei meinem Test mit offset=10000 und limit=2 kam ein 400 mit der Meldung, die Summe 10002 sei größer als der erlaubte Wert.
Daraus lässt sich für eine eigene Schnittstelle ableiten:
- Jede Liste braucht eine Obergrenze, die in der Beschreibung steht und vom Server durchgesetzt wird. Ohne sie holt ein einziger Aufruf die ganze Tabelle.
- Tiefes Blättern per
offsetwird teuer. Die Mannheimer Lösung ist eine harte Grenze plus ein Export-Endpunkt für den Rest. - API Platform kennt dafür die cursor-basierte Paginierung. Laut Dokumentation muss man dafür auf der Cursor-Eigenschaft einen
RangeFilterund einenOrderFilterdeklarieren undpaginationViaCursoraktivieren. - Der Server nennt in den Antwort-Headern, wie viele Aufrufe noch frei sind. Die Mannheimer Antworten tragen
x-ratelimit-limit: 5000undx-ratelimit-remaining. In Laravel gibtLimit::perMinute()die Grenze vor, und bei Überschreitung antwortet das Framework laut Dokumentation automatisch mit 429.
Fehler als Problem Details nach RFC 9457
Die Mannheimer Beschreibung kennt zwei Fehlerformen. Das 400 hat die Felder message und error_code. Das 429 hat die Felder errorcode, reset_time, limit_time_unit, call_limit und error. Ein Client braucht also pro Statuscode eine eigene Auswertung.
Genau dafür gibt es RFC 9457 (Juli 2023, löst RFC 7807 ab). Er definiert den Medientyp application/problem+json und fünf Mitglieder:
type: ein URI, der die Art des Problems benennt und als Hauptkennung gilt. Fehlt er, giltabout:blank. Absolute URIs sind empfohlen.status: der HTTP-Statuscode, nur als Hinweis. Die Antwort selbst muss denselben Code tragen.title: eine kurze Zusammenfassung der Problemart, die sich von Fall zu Fall nicht ändern soll.detail: eine Erklärung für diesen einen Fall. Sie soll dem Aufrufer helfen, das Problem zu beheben, und der RFC rät davon ab, sie maschinell auszuwerten.instance: ein URI für das einzelne Vorkommnis.
Eigene Erweiterungsmitglieder sind erlaubt, Clients müssen unbekannte ignorieren. Der RFC sagt auch, was Problem Details nicht sind: kein Debugging-Werkzeug, keine Stelle für Interna der Implementierung.
API Platform liefert Fehler ab Version 3.1 nach RFC 7807 als application/problem+json. In Laravel hängt man sich in bootstrap/app.php ein. Die Dokumentation beschreibt $exceptions->render(), und gibt der Callback nichts zurück, greift die Standarddarstellung. Ich habe mit illuminate/http 12.72.0 geprüft, dass ein selbst gesetzter Content-Type bei response()->json() erhalten bleibt:
->withExceptions(function (Exceptions $exceptions): void {
$exceptions->render(function (ValidationException $e, Request $request) {
if (! $request->is('api/*')) {
return null; // Standarddarstellung von Laravel
}
return response()->json([
'type' => 'https://api.example.org/probleme/validierung',
'title' => 'Die Anfrage ist ungültig.',
'status' => 422,
'errors' => $e->errors(), // Erweiterungsmitglied
], 422, ['Content-Type' => 'application/problem+json']);
});
})In der OpenAPI-Beschreibung steht dieses Schema einmal unter components und jede Fehlerantwort verweist darauf.
Versionierung: abkündigen statt abreißen
Die Mannheimer Schnittstelle trägt ihre Version in der URL (/v2.1) und in info.version. Das ist die einfachste Form, und in Laravel lässt sich ein Präfix wie v1 über Routengruppen setzen. Entscheidender als der Ort der Nummer ist, wie Änderungen laufen. Meine Regel ist: Felder und Endpunkte kommen dazu, ohne dass eine neue Version nötig wird, und Clients ignorieren unbekannte Felder. Das deckt sich mit der Regel des RFC für Erweiterungsmitglieder.
Wenn etwas weg muss, hilft die Dokumentation von API Platform. Sie trägt den Untertitel “Alternative to Versioning”. Mit deprecationReason markiert man eine Ressource oder Eigenschaft als veraltet, und die erzeugte OpenAPI-Beschreibung übernimmt das. Mit dem Attribut sunset setzt das Framework den Header Sunset nach RFC 8594, der anzeigt, ab wann eine URL voraussichtlich nicht mehr antwortet. Ihre Partner erfahren es dann aus der Antwort selbst, nicht aus einer Rundmail.
Authentifizierung: Token im Header
Die Mannheimer Beschreibung deklariert ein Sicherheitsschema apikey mit dem Ort query: Der Schlüssel wäre ein Parameter in der URL. Meine Abrufe liefen ohne Schlüssel. Für eine eigene Schnittstelle schiebe ich Tokens in den Header, weil URLs in Server- und Proxy-Logs landen.
Laravel Sanctum macht genau das und wird laut Dokumentation mit php artisan install:api eingerichtet. Die Dokumentation beschreibt:
- Tokens werden mit SHA-256 gehasht gespeichert. Der Klartext ist nur beim Erzeugen über
plainTextTokenverfügbar und soll dem Nutzer sofort angezeigt werden. - Ein Token trägt Abilities, die laut Dokumentation Scopes aus OAuth entsprechen.
tokenCan()prüft sie. - Tokens lassen sich jederzeit widerrufen. Eine Ablaufzeit gilt global über die Konfiguration
expiration(in Minuten) oder pro Token als drittes Argument voncreateToken(). - Sanctum ist die Variante ohne die Komplexität von OAuth. Brauchen Sie Fremdanwendungen, die im Namen Ihrer Nutzer handeln, plane ich oauth2 ein, das die OpenAPI-Spezifikation als Schema vorsieht.
Pro Partner ein eigener Token mit den kleinsten nötigen Abilities heißt: Wird einer abgegriffen, widerrufe ich genau diesen, und die anderen laufen weiter.
Vertragstests: die Antwort gegen die Beschreibung prüfen
Eine Beschreibung, die nicht geprüft wird, veraltet. Vertragstests prüfen, ob Anfrage und Antwort zur Beschreibung passen. Für Laravel gibt es Spectator (hotmeteor/spectator, Version 3.0.4 vom 23.08.2026, verlangt PHP 8.3 und Laravel 12). Die README trennt Vertragstests ausdrücklich von funktionalen Tests: “The data doesn’t have to be real; the shape does.” Ein Test sieht so aus:
Spectator::using('Api.v1.yml');
$this->postJson('/users', ['name' => 'Alice', 'email' => '[email protected]'])
->assertValidRequest()
->assertValidResponse(201);Die README nennt außerdem spectator:routes, das Operationen der Beschreibung mit den Laravel-Routen abgleicht, und spectator:coverage, das jede definierte Operation auflistet. Für Symfony und andere Frameworks prüft league/openapi-psr7-validator PSR-7-Nachrichten gegen die Beschreibung. Beide Wege hängen an der Frage aus dem Abschnitt zur Version: Die Bibliotheken nennen die Reihe 3.0. Läuft die Beschreibung in 3.1, prüfe ich vor der Zusage, ob das Werkzeug sie liest.
Datenschutz: Datenminimierung, Protokoll und die Meldung beim LfDI
Für Unternehmen mit Sitz in Mannheim ist in Baden-Württemberg der Landesbeauftragte für den Datenschutz und die Informationsfreiheit (LfDI) die Anlaufstelle. Drei Stellen der DSGVO berühren eine Schnittstelle direkt:
- Art. 5 Abs. 1 Buchstabe c: Daten müssen “auf das für die Zwecke der Verarbeitung notwendige Maß beschränkt” sein. Eine Resource-Klasse oder ein API-Platform-Attribut, das jedes Feld einzeln nennt, setzt das um.
- Art. 32: geeignete technische und organisatorische Maßnahmen nach Risiko. Dazu gehören Tokens mit kleinen Abilities, Ablaufzeiten und Widerruf.
- Art. 33 Abs. 1: Eine Verletzung des Schutzes personenbezogener Daten ist “unverzüglich und möglichst binnen 72 Stunden”, nachdem sie bekannt wurde, der Aufsichtsbehörde zu melden, es sei denn, sie führt voraussichtlich nicht zu einem Risiko für die Betroffenen.
Der LfDI bietet dafür das Online-Formular “Für Verantwortliche: Datenpanne melden” an. Es fragt unter anderem nach dem Zeitpunkt des Vorfalls, dem Zeitpunkt der Kenntnisnahme, den betroffenen Datenarten, der Zahl der Betroffenen, einer Risikoeinschätzung und den Gegenmaßnahmen. Die Seite weist darauf hin, dass nicht jede Verletzung meldepflichtig ist, entscheidend sei das Risiko. Ob ein Vorfall meldepflichtig ist, beurteilen Sie mit Ihrer Datenschutzberatung.
Für die Schnittstelle folgt daraus ein technischer Auftrag, den ich von Anfang an einplane: Das Zugriffsprotokoll hält fest, welcher Token wann welchen Endpunkt aufgerufen hat, damit Zeitpunkt, Umfang und Betroffene nach einem Vorfall rekonstruierbar sind. Die Token selbst und die Antwortinhalte stehen nicht im Protokoll.
Setzen Sie umgekehrt Mannheimer Daten ein, gilt ihre Lizenz. Die beiden Datensätze, die ich geprüft habe (E-Ladeparkstände von der MVV Energie AG, Verkehrszähler der Konrad-Adenauer-Brücke), nennen dl-de-by 2.0. Diese Lizenz erlaubt kommerzielle Nutzung und verlangt laut Lizenztext einen Quellenvermerk mit Bereitsteller, dem Vermerk “dl-de/by-2-0” samt Link auf den Lizenztext und einem Verweis auf den Datensatz.
Checkliste vor dem ersten Endpunkt
| Frage | Was ich vor dem Start festhalte |
|---|---|
| Wer ruft auf? | eigene App, Partner, beides; davon hängt Beschreibung zuerst oder aus dem Code ab |
| OpenAPI-Version | die Reihe, die Generator, Dokumentation und Tests gemeinsam lesen |
| Listen | Standard und Maximum von limit, Grenze für tiefes Blättern, Export-Weg |
| Fehler | ein Format für alle Endpunkte, type-URIs, Statuscodes je Fall |
| Version | Ort der Nummer, Umgang mit Abkündigung, Sunset-Header |
| Tokens | ein Token pro Partner, kleinste Abilities, Ablauf, Widerruf |
| Datenschutz | Feldliste je Endpunkt, Zugriffsprotokoll, Ablauf einer Meldung |
| Tests | Vertragstests gegen die Beschreibung in der CI |
So läuft ein Auftrag mit mir ab
Sie schicken mir einen kurzen Absatz: wer die Schnittstelle nutzt, welche Daten sie liefert, welcher Stack schon steht. Ich stelle meine Fragen schriftlich und liefere einen schriftlichen Umfang mit Annahmen und Ausschlüssen. Danach schreibe ich die Beschreibung, Sie und Ihre Partner lesen sie, und erst dann entsteht Code. Gebaut wird auf einer Staging-Umgebung, die Abnahme ist schriftlich. Oberflächen, die diese Schnittstelle nutzen, kommen mit Gestaltung und Wireframes von Ihnen, ich setze sie um. Wartung ist ein Zusatz: getestete Updates, Backups außerhalb des Hostings, Monitoring und ein monatlicher schriftlicher Bericht, Stunden verfallen am Monatsende.
Was ich von Ihnen brauche
- Wer die Schnittstelle nutzen soll und wie viele Aufrufe Sie erwarten.
- Zugang zum bestehenden Repository oder die Beschreibung des Systems, an das angebunden wird.
- Beispieldaten ohne Personenbezug, oder die Zusage, dass ich mit anonymisierten Kopien arbeite.
- Den Termin, auf den sich Partner oder App verlassen.
Häufige Fragen
Brauche ich OpenAPI, wenn nur die eigene App die Schnittstelle nutzt?
Es lohnt sich auch dann, weil die Beschreibung die einzige Stelle ist, an der Front- und Backend-Seite dasselbe nachlesen. Bei einer internen Schnittstelle mit wenigen Endpunkten reicht eine knappe Beschreibung mit den Pflichtfeldern und den Fehlerfällen. Sie wächst mit der Schnittstelle.
Laravel oder API Platform?
Das entscheide ich nach Ihrem bestehenden Stack und danach, wer die Beschreibung pflegt. Laravel mit Resource-Klassen passt zu einer Anwendung, die ohnehin in Laravel läuft. API Platform erzeugt die Beschreibung aus Attributen und liefert Fehler als application/problem+json mit.
Welche OpenAPI-Version sollte es sein?
Die, die alle Ihre Werkzeuge lesen. Die Spezifikation führt 3.2.1, 3.1.2 und 3.0.4 als jeweils neueste Fassung ihrer Reihe. Die PHP-Bibliotheken für Vertragstests nennen in ihren Beschreibungen die Reihe 3.0. Ich kläre die Werkzeugkette vor dem ersten Endpunkt schriftlich.
Muss ich Fehler nach RFC 9457 liefern?
Nein, der RFC verpflichtet niemanden. Er erspart Ihnen und Ihren Partnern ein eigenes Fehlerformat, und API Platform liefert es ohnehin. Wichtig ist, dass alle Endpunkte dasselbe Format nutzen.
Darf ich die Mannheimer Open-Data-Schnittstelle kommerziell nutzen?
Die beiden Datensätze, die ich am 11.11.2026 geprüft habe, stehen unter dl-de/by-2-0. Die Lizenz erlaubt die kommerzielle Nutzung und verlangt einen Quellenvermerk mit Bereitsteller, Lizenzhinweis samt Link und Verweis auf den Datensatz. Jeder Datensatz trägt seine eigene Lizenz, ich lese sie vor der Anbindung.
Wie fange ich an?
Schreiben Sie mir über das Kontaktformular: wer die Schnittstelle nutzen soll, welche Daten sie liefert, Ihren Termin und den bestehenden Stack. Ich antworte schriftlich an Werktagen. Die erste Einschätzung zu Umfang und Weg ist kostenlos.
Schreiben Sie mir
Schicken Sie mir über das Kontaktformular die Adresse Ihres Systems, das Ziel der Schnittstelle, Ihren Termin und den aktuellen Stack. Aus Ihrem Absatz entsteht eine schriftliche Einschätzung, die erste ist kostenlos. Wie man eine fremde Schnittstelle sauber anbindet, statt eine eigene zu bauen, zeige ich auf der Seite PHP-Entwickler Bonn.
Ausgewählte Projekte
Beispiele aus meiner Arbeit.
Tech Platform: car-mechanic-huntington.co.uk
car-mechanic-huntington.co.uk ist eine WordPress-Website für eine lokale Kfz-Werkstatt, mit klarem Leistungsangebot, Kontaktwegen und technischer Wartung.
Tech Platform: fermentum-mobile.pl
Die Website fermentum-mobile.pl ist eine dedizierte Plattform, die für Fermentationsliebhaber entwickelt wurde, die die Geheimnisse traditioneller Verarbeitu...
Tech Platform: sportostroda.pl
Sportostroda.pl ist eines der interessanten Projekte in meinem Portfolio als WordPress-Entwickler. Es wurde als lokales Sportportal realisiert, das sich an d...
WordPress Support & Entwicklung in Mannheim
Brauchen Sie die Leistung: PHP-Entwickler in Mannheim?
Beschreiben Sie Ihr Projekt per E-Mail. Antwort innerhalb von 48 Stunden.
Projekt beschreibenWeitere WordPress-Dienste und Wissensbasis entdecken
Individuelle WordPress-Entwicklung und Architektur.
Shops, Checkout-Prozesse und Verkaufslogik.
Shopify-Themes, Liquid und WooCommerce → Shopify-Migrationen.
Headless WordPress, Sanity, Strapi und Contentful mit Astro oder Next.js.
Claude, OpenAI und RAG in WordPress mit BYOK und EU-Residenz.
Geschäftsprozessautomatisierung rund um WordPress und Firmensysteme.
Bibliothek konkreter Automatisierungsfälle.
NIS2- und DORA-Scoping, Lieferantenregister, Incident-Runbook.
Verwandte Kategorien
Unterstützende Artikel

Ein Leitfaden aus der Praxis für eine WordPress-Website, die 2026 rankt. Technisches SEO, Core Web Vitals, Schema, AEO, GEO, hreflang und die Reihenfolge, mit der es beim ersten Mal klappt.

Migration von Shopify zu WooCommerce ohne Datenverlust, Kundenverlust oder SEO-Ranking-Einbußen. Umfasst Produkttransfer, 301-Weiterleitungen, URL-Mapping, WP-CLI-Automatisierung und Checkliste nach der Migration.

Die vollständige Checkliste nach der WordPress-Installation. 50 Schritte zu Sicherheit, Performance, SEO und Backups. Eine professionelle Konfiguration ab dem ersten Tag.