Verwandelt eine statische Astro-Vorlage mit dem astro-wordpress-Adapter in ein WordPress-Theme: Seiten unter src/pages/*.php.astro werden zu echten WordPress-Template-Dateien kompiliert (index.php, page-template-*.php, …), während npm run dev an eine echte lokale WordPress-Instanz weiterleitet, sodass das Theme jederzeit live in der Vorschau angezeigt wird.
Dies ist das verifizierte Rezept, keine Paraphrase der README des Adapters: Die folgenden Schritte wurden auf eine echte statische Astro-Vorlage angewendet und Ende-zu-Ende bestätigt – der Dev-Server leitet live durch WordPress weiter, npm run build erzeugt ein aktivierbares Theme, wp theme activate funktioniert.
Voraussetzungen
- Eine lokale WordPress-Installation, die über HTTP erreichbar ist. Zwei verifizierte Optionen:
- Docker Compose (empfohlen – kein lokales PHP/MySQL/wp-cli erforderlich, und
wp-cliist auf dem Host möglicherweise nicht installiert). Siehe Schritt 0. - Eine bereits laufende lokale WP-Installation (beliebiger PHP-Server + MySQL/MariaDB, auf den
devProxyTargetzeigt). Diese Fähigkeit konvertiert in beiden Fällen nur die Astro-Seite.
- Docker Compose (empfohlen – kein lokales PHP/MySQL/wp-cli erforderlich, und
- Node/npm für das Astro-Projekt.
wp-cliist während dieser gesamten Fähigkeit optional – jeder wp-cli-Befehl unten hat einen Fallback ohne wp-cli (Browser/curl-Formularübermittlung oder einen dockerisierten wp-cli-Beitrag). Fügen Sie es nicht als harte Anforderung hinzu.
0. (Docker-Option) Starten Sie WordPress mit Docker Compose
Diese exakte compose.yaml (aus dem astro-wordpress-Starter) funktioniert unverändert – verifiziert durch tatsächliches Ausführen:
services:
wordpress:
image: wordpress
restart: always
ports:
- 8088:80
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: exampleuser
WORDPRESS_DB_PASSWORD: examplepass
WORDPRESS_DB_NAME: exampledb
volumes:
- ./wp:/var/www/html
- ./public/:/var/www/html/public
db:
image: mysql:8.0
restart: always
environment:
MYSQL_DATABASE: exampledb
MYSQL_USER: exampleuser
MYSQL_PASSWORD: examplepass
MYSQL_RANDOM_ROOT_PASSWORD: "1"
volumes:
- db:/var/lib/mysql
volumes:
db:
docker compose up -d
Kein wp-cli im wordpress-Image standardmäßig – schließen Sie die Installation und alles andere entweder über den Browser (http://localhost:8088) oder mit einem einmaligen dockerisierten wp-cli-Container ab, der dasselbe Netzwerk + dieselben Volumes teilt (siehe Überprüfen/Häufige Fallstricke – dies ist das Muster, das Sie verwenden sollten, wenn ein Schritt unten wp ... sagt und kein lokales wp-cli installiert ist):
docker run --rm --network container:<wordpress-container-name> \
--volumes-from <wordpress-container-name> -w /var/www/html \
-e WORDPRESS_DB_HOST=db -e WORDPRESS_DB_USER=exampleuser \
-e WORDPRESS_DB_PASSWORD=examplepass -e WORDPRESS_DB_NAME=exampledb \
wordpress:cli <wp-cli-command>
(Die -e-Variablen müssen mit der Umgebung des wordpress-Dienstes übereinstimmen – der CLI-Container liest dieselbe wp-config.php, die sie über getenv() auflöst, erbt aber nicht die Umgebung des anderen Containers.)
Schritte
1. Installieren Sie den Adapter
npm install astro-wordpress
(passthroughImageService wird unten mit dem Astro-Kern ausgeliefert – kein zusätzliches Paket.)
2. Konfigurieren Sie astro.config.mjs
Bare-Metal-WP (Astro und WP auf demselben Host, keine Container-Grenze):
// @ts-check
import { defineConfig, fontProviders, passthroughImageService } from "astro/config";
import wordpress from "astro-wordpress";
export default defineConfig({
server: {
host: "127.0.0.1",
},
adapter: wordpress({
devProxyTarget: "http://localhost:7001", // Ihre lokale WP-URL
outDir: "./wp/wp-content/themes/<theme-name>", // Das erstellte Theme wird hier abgelegt
}),
image: {
service: passthroughImageService(), // erforderlich – WP serviert/optimiert Bilder selbst
},
});
Docker Compose WP (mit der obigen compose.yaml) benötigt drei weitere Optionen – jede wurde als notwendig verifiziert, indem sie tatsächlich ohne sie ausgeführt wurde (siehe Häufige Fallstricke):
export default defineConfig({
server: {
host: "0.0.0.0", // an allen Schnittstellen binden, damit der Container darauf zugreifen kann
allowedHosts: ["host.docker.internal"],
},
adapter: wordpress({
devProxyTarget: "http://localhost:8088",
outDir: "./wp/wp-content/themes/<theme-name>",
// Die eigene Sicht des WP-Containers auf das eingebundene public/-Verzeichnis –
// NICHT der Host-Pfad (siehe Häufige Fallstricke)
publicDirPath: "/var/www/html/public",
// Ermöglicht dem PHP-Entwicklungs-Template-Stub, der *innerhalb* des Containers läuft,
// eine Verbindung zum Astro-Entwicklungsserver auf dem Host herzustellen
devServerTarget: "http://host.docker.internal:4321",
}),
image: { service: passthroughImageService() },
});
devProxyTarget muss mit der Adresse übereinstimmen, auf der WordPress tatsächlich lauscht. outDir ist das Verzeichnis, in das npm run build das fertige Theme schreibt; es muss nicht innerhalb des Astro-Projekts liegen. Wenn es das tut (ein vollständiger lokaler WP-Checkout, der z. B. unter ./wp/ verschachtelt ist), fügen Sie dieses Verzeichnis zu .gitignore hinzu – der WordPress-Kern und seine Uploads gehören nicht in das Repository des Astro-Projekts.
3. Fügen Sie das Theme-Stylesheet hinzu
WordPress erkennt ein Theme-Verzeichnis nur, wenn es eine style.css mit diesem Header hat – erstellen Sie public/style.css (es wird vom Adapter automatisch in outDir symlinkiert/kopiert):
/*!
Theme Name: <Theme Name>
Version: 0.0.1
*/
4. Konvertieren Sie Seiten zu .php.astro
Benennen Sie jede src/pages/*.astro-Route, die Sie von WordPress bedienen lassen möchten, in src/pages/*.php.astro um – der Standard-Export der Datei rendert weiterhin durch Astro/Ihre vorhandenen Layouts und Komponenten unverändert; nur die Erweiterung und das endgültige Ausgabeformat ändern sich (index.astro → index.php). Für eine korrekte Erstellung und Bereitstellung einer Seite sind keine weiteren Codeänderungen erforderlich.
Nicht-Index-WP-Template-Dateien folgen demselben Muster: Das Präfix page-template- wird automatisch erkannt und in einen /* Template Name: ... */-Kommentar umgewandelt, den WordPress für benutzerdefinierte Seitenvorlagen erkennt, z. B. src/pages/page-template-landing.php.astro → eine auswählbare „Landing“-Vorlage. (In der README des Adapters dokumentiert; von diesem Rezept nicht getestet.)
Für Dateien, die rohes PHP ohne umgebendes HTML-Dokument ausgeben müssen (z. B. eine functions.php.astro, die zum Registrieren von Hooks/Fields verwendet wird – siehe die Fähigkeit astro-wordpress-acf), fügen Sie export const partial = true; im Frontmatter hinzu. Ohne dies stellt Astro automatisch <!DOCTYPE html> vor die Ausgabe und beschädigt die PHP-Datei.
5. Aktivieren Sie das Theme
Allgemein: WP-Admin → Design → Themes → Aktivieren. Mit wp-cli (lokal oder dockerisiert, siehe Schritt 0):
npm run build
wp theme activate <theme-name> --path=<wp-dir>
Überprüfen
# 1. Dev-Server und WP laufen beide? Jede Anfrage wird über devProxyTarget weitergeleitet,
# sodass selbst statische Assets 502 erhalten, wenn WP nicht erreichbar ist
npm run dev &
curl -o /dev/null -s -w "%{http_code}\n" http://127.0.0.1:4321/
# 2. Umgehen Sie den WP-Proxy, um die rohe Astro-gerenderte PHP-artige Ausgabe direkt
# vom Dev-Server zu sehen – nützlich, um zu isolieren: "Ist das ein Astro-Problem
# oder ein WordPress-Problem"
curl -s -H "by-pass-proxy: 1" http://127.0.0.1:4321/index.php | head -c 300
# 3. Produktions-Build legt echte, reines PHP in outDir ab
npm run build
grep -c '<?php' wp/wp-content/themes/<theme-name>/index.php
# 4. Theme ist aktiv – über wp-cli, oder laden Sie einfach die Startseite und prüfen Sie
# auf themenspezifisches Markup, falls wp-cli nicht verfügbar ist
wp theme list --path=<wp-dir> | grep <theme-name>
Keine lokale WP-Installation zum Testen und möchten bestätigen, dass die WP-Installation selbst headless funktioniert (kein wp-cli, kein Browser)? Der Installationsassistent ist ein einfaches Formular-POST – genau so wurde eine frische WP-Installation für diese Fähigkeit verifiziert:
curl "http://localhost:8088/wp-admin/install.php?step=2" \
--data-urlencode "weblog_title=My Site" \
--data-urlencode "user_name=admin" \
--data-urlencode "admin_password=<password>" \
--data-urlencode "admin_password2=<password>" \
--data-urlencode "pw_weak=1" \
--data-urlencode "[email protected]" \
--data-urlencode "Submit=Install WordPress"
# Dann auf die gleiche Weise anmelden (Cookie-Jar) für spätere Admin-Bildschirmprüfungen:
curl -c cookies.txt \
--data-urlencode "log=admin" --data-urlencode "pwd=<password>" \
--data-urlencode "wp-submit=Log In" \
--data-urlencode "redirect_to=http://localhost:8088/wp-admin/" \
--data-urlencode "testcookie=1" \
"http://localhost:8088/wp-login.php"
curl -b cookies.txt "http://localhost:8088/wp-admin/" | grep -o "<title>[^<]*</title>"
Häufige Fallstricke
- Jede Dev-Modus-Anfrage wird an
devProxyTargetweitergeleitet, nicht nur.php-Seiten –/src,/@,/node_modulesund alles mit einemby-pass-proxy-Header sind die einzigen Ausnahmen. Wenn WordPress nicht läuft, erhält die gesamte Site 502, einschließlich Bilder/Schriftarten unterpublic/. Überprüfen Sie, ob WP tatsächlich läuft, bevor Sie die Astro-Seite debuggen. - Astro 7s Dev-Server ist ein persistenter Hintergrund-Daemon. Ein zweites
npm run devbindet nicht neu oder verursacht keinen Fehler – es meldet nur die bereits laufende Instanz (npx astro dev status/stop/logszur direkten Verwaltung). export const partial = true;– siehe Schritt 4. Dies ist die mit Abstand am wenigsten offensichtliche Anforderung im gesamten Adapter; die Fehlerart (störendes<!DOCTYPE html>am Anfang einer PHP-Datei) scheint überhaupt nichts mit Astro zu tun zu haben.publicDirPathmuss der Pfad sein, wie der WP-Container ihn sieht, nicht der Host-Pfad. Der Adapter verlinkt jedepublic/-Datei mit dem von Ihnen angegebenenpublicDirPathin das Theme-Verzeichnis. Mit Docker geben Sie den Container-Pfad an (/var/www/html/public) – bestätigt durch Überprüfen des resultierenden Symlinks in beide Richtungen:readlink wp-content/themes/<theme>/style.css→/var/www/html/public/style.css, was überdocker exec <container> cat wp-content/themes/<theme>/style.csseinwandfrei aufgelöst wird, aber vom Host-Shell aus „No such file or directory" ist. Wenn SiepublicDirPathweglassen, fällt der Adapter auf den Host-Pfad zurück, der innerhalb des Containers ungültig ist.- Die Daemon-Sperre von
astro devgilt pro Projektverzeichnis, nicht pro Konfiguration/Port. Das Ausführen vonastro dev --config other.config.mjs --port 4325, während im selben Verzeichnis bereits ein einfachesastro devläuft, meldet nur „Dev server already running" auf dem ursprünglichen Port – es startet keine zweite Instanz. Verwenden Sie zuerstastro dev stop, um die vorhandene Instanz zu beenden, wenn Sie die Konfiguration (z. B. Bare-Metal vs. Docker) im selben Projekt wechseln müssen. - Diese Konvertierung allein bindet
wp_head()/wp_footer()nicht in das Layout ein, daher werden plugin-injizierte<script>/<style>-Tags, SEO-Plugin-Meta-Tags usw. nicht angezeigt. Die astro-wordpress-README zeigt das Hinzufügen von<Fragment set:html={} />/<?php wp_footer(); ?>zum Layout dafür. Wenn das Layout sein eigenes<head>unabhängig aufbaut (häufig beim Portieren einer vorhandenen statischen Vorlage), behandeln Sie das Einbinden dieser als bewusste Folgemaßnahme, nicht als etwas, das die Schritte dieser Fähigkeit bereits bieten. astro check(Teil vonnpm run build) kann abstürzen (OOM), wenn versucht wird, die WordPress-Kerndateien zu typüberprüfen, die in./wplanden, sobald der Container startet (Tausende von.js/.php-Dateien unterwp-includes/js/dist/usw.). Fügen Sie"exclude": ["dist", "wp"]zutsconfig.jsonhinzu, bevor Sie einen Build mit bereits laufendem Docker-WP ausführen – sonst sieht der Fehler wie ein nicht zusammenhängender Node-Heap-Absturz ohne offensichtliche Verbindung zum WordPress-Adapter aus.- Biome (oder jeder Linter/Formatter, der über das gesamte Repository läuft) wird auch versuchen,
./wpzu verarbeiten, sobald es existiert, aus demselben Grund – fügen Sie einen Ignore-Eintrag hinzu (z. B."files": { "ignore": ["wp/**"] }inbiome.json), bevor Sie den Lint/Format-Befehl des Projekts ausführen. - Dynamische Rest-Param-Routen werden nicht konvertiert.
src/pages/blog/[...slug].astro(oder jedes[...x].astro) kann nicht zu[...x].php.astrowerden – Astros Router lehnt es rundweg ab („rest parameter must be a standalone segment"), weil das.php-Suffix die Segmentgrenze durchbricht. Lassen Sie diese Routen als einfaches.astround außerhalb des WP-Themes, es sei denn, der Inhalt selbst wird in WP migriert.
Nächster Schritt
Sobald der Adapter eingerichtet ist:
astro-wordpress-acf– machen Sie bestimmte Abschnitte einer Seite über ACF im WP-Backend bearbeitbar.astro-wordpress-menus– verbinden Sie eine Kopf-/Fußzeilen-/Navigationskomponente mit einem von WordPress verwalteten Menü (Design → Menüs) anstelle von fest codierten Links.astro-wordpress-global-settings– fügen Sie eine siteweite „Theme Options"-Seite für Werte hinzu, die nicht an eine einzelne Seite gebunden sind (erfordert ACF Pro oder Secure Custom Fields).