정적 Astro 템플릿을
astro-wordpress를 통해 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 설치 (
devProxyTarget이 가리키는 모든 PHP 서버 + MySQL/MariaDB). 이 스킬은 어느 쪽이든 Astro 쪽만 변환합니다.
- Docker Compose (권장 — 로컬 PHP/MySQL/wp-cli가 전혀 필요 없으며,
- Astro 프로젝트를 위한 Node/npm.
- 이 스킬 전반에 걸쳐
wp-cli는 선택 사항입니다. — 아래 모든 wp-cli 명령어는 wp-cli 없는 대체 방법(브라우저/curl 양식 제출 또는 docker화된 wp-cli 사이드카)이 있습니다. 하드 요구 사항으로 추가하지 마세요.
0. (Docker 옵션) Docker Compose로 WordPress 시작
이 정확한 compose.yaml(astro-wordpress 스타터에서 가져옴)은 수정 없이 작동합니다.
— 실제 실행을 통해 확인됨:
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)를 통해 완료하거나,
같은 네트워크 + 볼륨을 공유하는 일회용 docker화된 wp-cli 컨테이너로 완료하세요.
(Verify/Gotchas 참조 — 아래 단계에서 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 사용)에는 세 가지 추가 옵션이 필요합니다.
— 각각 실제로 없으면 깨지는 것을 확인했습니다 (Gotchas 참조):
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 컨테이너 자체가 보는 바인드 마운트된 public/ 디렉토리의 경로 —
// 호스트 경로가 아님 (Gotchas 참조)
publicDirPath: "/var/www/html/public",
// WP 컨테이너 *내부*에서 실행되는 PHP 개발 템플릿 스텁이
// 호스트에서 실행 중인 Astro 개발 서버에 다시 접근할 수 있도록 함
devServerTarget: "http://host.docker.internal:4321",
}),
image: { service: passthroughImageService() },
});
devProxyTarget은 WordPress가 실제로 수신 대기 중인 주소와 일치해야 합니다.
outDir은 npm run build가 완성된 테마를 쓰는 위치입니다.
Astro 프로젝트 내에 있을 필요는 없습니다. 만약 그렇다면 (예: ./wp/ 아래에 중첩된 전체 로컬 WP 체크아웃),
해당 디렉토리를 .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에 문서화되어 있음, 이 레시피에서는 테스트되지 않음.)
주변 HTML 문서 없이 원시 PHP를 출력해야 하는 파일
(예: 훅/필드를 등록하는 데 사용되는 functions.php.astro —
astro-wordpress-acf 스킬 참조)의 경우, 프론트매터에
export const partial = true;를 추가하세요. 없으면 Astro가 출력 앞에
<!DOCTYPE html>을 자동으로 추가하여 PHP 파일을 손상시킵니다.
5. 테마 활성화
공통: WP 관리자 → 외모 → 테마 → 활성화. wp-cli 사용 시 (로컬 또는 docker화, 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. 프로덕션 빌드가 outDir에 실제 일반 PHP 파일을 생성하는지 확인합니다.
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"
# 그런 다음 동일한 방식(쿠키 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로는 정상 확인되지만 호스트 셸에서는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 플러그인 메타 태그 등이 나타나지 않습니다. astro-wordpress README는 레이아웃에<Fragment set:html={} />/<?php wp_footer(); ?>를 추가하는 방법을 보여줍니다. 레이아웃이 독립적으로 자체<head>를 빌드하는 경우(기존 정적 템플릿을 포팅할 때 일반적), 해당 연결을 의도적인 후속 작업으로 취급하고 이 스킬의 단계가 이미 제공하는 것으로 간주하지 마세요. astro check(npm run build의 일부)는 OOM으로 충돌할 수 있습니다. 컨테이너가 시작되면./wp에 배치되는 WordPress 코어 파일 (wp-includes/js/dist/아래의 수천 개.js/.php파일 등)을 타입 검사하려고 하기 때문입니다. Docker WP가 이미 실행 중인 상태에서 빌드를 실행하기 전에tsconfig.json에"exclude": ["dist", "wp"]를 추가하세요. — 그렇지 않으면 충돌이 WordPress 어댑터와 명백한 관련이 없는 관련 없는 Node 힙 충돌처럼 보입니다.- Biome (또는 전체 저장소를 대상으로 하는 모든 linter/formatter)도
./wp를 처리하려고 시도합니다. 같은 이유로, 프로젝트의 lint/format 명령을 실행하기 전에 무시 항목(예:biome.json의"files": { "ignore": ["wp/**"] })을 추가하세요. - 동적 rest-param 라우트는 변환되지 않습니다.
src/pages/blog/[...slug].astro(또는 모든[...x].astro)는[...x].php.astro가 될 수 없습니다. — Astro의 라우터가 이를 완전히 거부합니다 (".php" 접미사가 세그먼트 경계를 깨뜨리기 때문에 "rest parameter must be a standalone segment"). 해당 라우트는 일반.astro로 남겨두고 WP 테마에서 제외하거나, 콘텐츠 자체가 WP로 마이그레이션되는 경우에만 처리하세요.
다음 단계
어댑터가 설정되면:
astro-wordpress-acf— ACF를 통해 페이지의 특정 섹션을 WP 백오피스에서 편집 가능하게 만듭니다.astro-wordpress-menus— 헤더/푸터/네비게이션 컴포넌트를 하드코딩된 링크 대신 WordPress 관리 메뉴(외모 → 메뉴)에 연결합니다.astro-wordpress-global-settings— 특정 페이지에 국한되지 않는 사이트 전체 "테마 옵션" 페이지를 추가합니다 (ACF Pro 또는 Secure Custom Fields 필요).