透過 astro-wordpress 將靜態 Astro 模板轉換為 WordPress 主題:src/pages/*.php.astro 下的頁面會編譯成真正的 WordPress 模板檔案(index.php、page-template-*.php、……),而 npm run dev 則會代理到本機的 WordPress 實例,以便主題能隨時與其進行即時預覽。
這是經過驗證的準則,並非對適配器 README 的改寫:下列步驟已套用於一個真實的靜態 Astro 模板,並從頭到尾確認有效 — 開發伺服器代理能即時通往 WordPress,npm run build 能產出真正的可啟用主題,wp theme activate 也能成功執行。
先決條件
- 一個可透過 HTTP 存取的本機 WordPress 安裝。兩個經過驗證的選項:
- Docker Compose(推薦 — 完全不需要本機 PHP/MySQL/wp-cli,且主機上可能根本沒安裝
wp-cli)。請參閱步驟 0。 - 一個正在執行的本機 WP 安裝(任何 PHP 伺服器 + MySQL/MariaDB,並由
devProxyTarget指向)。無論如何,此技能僅轉換 Astro 端。
- Docker Compose(推薦 — 完全不需要本機 PHP/MySQL/wp-cli,且主機上可能根本沒安裝
- 用於 Astro 專案的 Node/npm。
wp-cli在此技能中完全為選用 — 下方每個 wp-cli 指令都有無 wp-cli 的替代方案(瀏覽器/curl 表單提交,或容器化的 wp-cli 輔助容器)。請勿將其設為硬性需求。
0. (Docker 選項) 使用 Docker Compose 啟動 WordPress
這個來自 astro-wordpress 起手版的 compose.yaml 可直接使用且無需修改 — 經過實際執行驗證:
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
wordpress 映像檔預設沒有 wp-cli — 請透過瀏覽器 (http://localhost:8088) 完成安裝及其他所有操作,或使用一次性容器化的 wp-cli 容器,該容器共用相同的網路和磁碟區(請參閱驗證/注意事項 — 每當下方步驟提到 wp ... 且本機未安裝 wp-cli 時,都應採用此模式):
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>
(-e 變數必須與 wordpress 服務的環境變數相符 — CLI 容器會讀取同一個 wp-config.php,後者透過 getenv() 解析這些變數,但不會繼承另一個容器的環境變數。)
步驟
1. 安裝適配器
npm install astro-wordpress
(下方使用的 passthroughImageService 隨 Astro 核心一同提供 — 不需額外套件。)
2. 設定 astro.config.mjs
裸機 WP(Astro 和 WP 在同一台主機上,無容器邊界):
// @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", // 你的本機 WP URL
outDir: "./wp/wp-content/themes/<theme-name>", // 建置的主題會放在這裡
}),
image: {
service: passthroughImageService(), // 必要 — WP 自行提供/最佳化圖片
},
});
Docker Compose WP(使用上述 compose.yaml)需要額外三個選項 — 每個都經實際測試,不設定就會失敗(請參閱注意事項):
export default defineConfig({
server: {
host: "0.0.0.0", // 綁定所有介面,讓容器可以連入
allowedHosts: ["host.docker.internal"],
},
adapter: wordpress({
devProxyTarget: "http://localhost:8088",
outDir: "./wp/wp-content/themes/<theme-name>",
// WP 容器自身看到的 bind-mounted public/ 目錄路徑 —
// 不是主機路徑(請參閱注意事項)
publicDirPath: "/var/www/html/public",
// 讓執行在容器內部的 PHP 開發模板樁能夠
// 連回主機上執行的 Astro 開發伺服器
devServerTarget: "http://host.docker.internal:4321",
}),
image: { service: passthroughImageService() },
});
devProxyTarget 必須與 WordPress 實際監聽的位置相符。outDir 是 npm run build 寫入完成的主題的位置;它不需要位於 Astro 專案內。如果它位於專案內(例如在 ./wp/ 下的本機 WP checkout),請將該目錄加入 .gitignore — WordPress 核心及其上傳檔案不屬於 Astro 專案的儲存庫。
3. 加入主題樣式表
WordPress 只有在主題目錄中包含帶有以下標頭的 style.css 時才會識別該主題 — 建立 public/style.css(適配器會自動將其符號連結/複製到 outDir):
/*!
Theme Name: <Theme Name>
Version: 0.0.1
*/
4. 將頁面轉換為 .php.astro
將你想要由 WordPress 提供的每個 src/pages/*.astro 路由重新命名為 src/pages/*.php.astro — 檔案的預設匯出仍會透過 Astro/你現有的佈局和元件進行渲染,無需更改;只有副檔名和最終的輸出格式會改變(index.astro → index.php)。頁面要能正確建置和提供,不需要其他程式碼變更。
非索引的 WP 模板檔案遵循相同的模式:page-template- 前綴會被自動偵測,並轉換為 WordPress 識別的 /* Template Name: ... */ 註解,用於自訂頁面模板,例如 src/pages/page-template-landing.php.astro → 一個可選擇的「Landing」模板。(記錄在適配器的 README 中;本準則未實際使用。)
對於那些必須輸出原始 PHP 且不包含 Surrounding HTML 文件的檔案(例如用於註冊鉤子/欄位的 functions.php.astro — 請參閱 astro-wordpress-acf 技能),請在前言中加入 export const partial = true;。若不加入,Astro 會自動在輸出前綴加上 <!DOCTYPE html>,從而破壞 PHP 檔案。
5. 啟用主題
通用方法:WP 管理後台 → 外觀 → 主題 → 啟用。使用 wp-cli(本機或容器化,請參閱步驟 0):
npm run build
wp theme activate <theme-name> --path=<wp-dir>
驗證
# 1. 開發伺服器和 WP 都啟動了?每個請求都會代理到 devProxyTarget,
# 因此如果 WP 無法連線,即使是靜態資源也會回傳 502
npm run dev &
curl -o /dev/null -s -w "%{http_code}\n" http://127.0.0.1:4321/
# 2. 繞過 WP 代理,直接從開發伺服器查看原始的 Astro 渲染的 PHP 風格輸出
# — 有助於隔離「這是 Astro 的問題還是 WordPress 的問題」
curl -s -H "by-pass-proxy: 1" http://127.0.0.1:4321/index.php | head -c 300
# 3. 正式環境建置會將真正的純 PHP 檔案放入 outDir
npm run build
grep -c '<?php' wp/wp-content/themes/<theme-name>/index.php
# 4. 主題已啟用 — 透過 wp-cli,或者如果 wp-cli 不可用,直接載入首頁並檢查是否有主題特定的標記
wp theme list --path=<wp-dir> | grep <theme-name>
還沒有本機 WP 安裝可以測試,想以無頭方式(無 wp-cli,無瀏覽器)確認 WP 安裝本身能正常工作?安裝精靈只是一個純文字的表單 POST — 這正是此技能驗證全新 WP 安裝的方式:
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"
# 然後以相同方式登入(使用 cookie jar)以進行後續的管理畫面檢查:
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>"
注意事項
- 每個開發模式的請求都會代理到
devProxyTarget,而不僅僅是.php頁面 —/src、/@、/node_modules,以及任何帶有by-pass-proxy標頭的請求是唯一的例外。如果 WordPress 沒有執行,整個網站(包括public/下的圖片/字型)都會回傳 502。在除錯 Astro 端之前,請先檢查 WP 是否確實已啟動。 - Astro 7 的開發伺服器是一個持續的背景精靈。 第二次執行
npm run dev不會重新綁定或報錯 — 它只會回報已正在執行的實例(可直接使用npx astro dev status/stop/logs來管理)。 export const partial = true;— 請參閱步驟 4。這是整個適配器中最不明顯的需求;其失敗模式(PHP 檔案頂部出現多餘的<!DOCTYPE html>)看起來與 Astro 完全無關。publicDirPath必須是 WP 容器所見的路徑,而不是主機路徑。 適配器會使用你給定的publicDirPath將每個public/檔案符號連結到主題目錄。使用 Docker 時,請給予容器路徑(/var/www/html/public)— 透過雙向檢查結果符號連結來確認:readlink wp-content/themes/<theme>/style.css→/var/www/html/public/style.css,這個路徑在docker exec <container> cat wp-content/themes/<theme>/style.css中可以正常解析,但在主機 shell 中會顯示No such file or directory。如果你省略publicDirPath,適配器會回退到主機路徑,這在容器內是無效的。astro dev的精靈鎖定是針對每個專案目錄,而不是每個設定/埠口。 在相同目錄中,當一個普通的astro dev已在執行時執行astro dev --config other.config.mjs --port 4325,只會回報「Dev server already running」在原始埠口上 — 它並不會啟動第二個實例。如果你需要在同一個專案中切換設定(例如裸機 vs. Docker),請先使用astro dev stop停止現有的實例。- 此轉換本身不會將
wp_head()/wp_footer()加入佈局,因此外掛注入的<script>/<style>標籤、SEO 外掛的 meta 標籤等不會出現。astro-wordpress README 顯示了在佈局中加入<Fragment set:html={} />/<?php wp_footer(); ?>的方法。如果佈局獨立建構自己的<head>(在移植現有靜態模板時很常見),請將連線這些視為刻意進行的後續步驟,而不是此技能的步驟已經提供的功能。 astro check(npm run build的一部分)可能會因記憶體不足而崩潰,當嘗試對容器啟動後落在./wp中的 WordPress 核心檔案(wp-includes/js/dist/等目錄下成千上萬個.js/.php檔案)進行型別檢查時。在 Docker WP 已啟動的情況下執行建置之前,請先將"exclude": ["dist", "wp"]加入tsconfig.json— 否則失敗訊息看起來像是無關的 Node 堆積崩潰,與 WordPress 適配器沒有明顯關聯。- Biome(或任何在整個儲存庫上執行的 linter/formatter)也會嘗試處理
./wp,一旦它存在,原因相同 — 在執行專案的 lint/format 命令之前,請加入忽略項目(例如在biome.json中加入"files": { "ignore": ["wp/**"] })。 - 動態 rest-param 路由無法轉換。
src/pages/blog/[...slug].astro(或任何[...x].astro)無法變成[...x].php.astro— Astro 的路由器會直接拒絕它(「rest parameter must be a standalone segment」),因為.php後綴破壞了區段邊界。將這些路由保留為純.astro並排除在 WP 主題之外,除非內容本身正在遷移到 WP。
下一步
一旦適配器連接好:
astro-wordpress-acf— 透過 ACF 使頁面的特定區段可從 WP 後台編輯。astro-wordpress-menus— 將頁首/頁尾/導覽元件連接到 WordPress 管理的選單(外觀 → 選單),而不是使用硬編碼的連結。astro-wordpress-global-settings— 為不局限於任何單一頁面的值加入全站范围的「主題選項」頁面(需要 ACF Pro 或 Secure Custom Fields)。