15 KiB
WordPress 헤드리스와 Next.js 조합 아키텍처
개요
이 문서는 WordPress를 헤드리스 CMS로 활용하고 Next.js로 프론트엔드를 구축하는 아키텍처에 대해 설명합니다. 이 접근법은 WordPress의 강력한 콘텐츠 관리 기능과 Next.js의 현대적인 프론트엔드 개발 경험을 결합하여, 기존 WordPress 사이트를 점진적으로 현대화할 수 있는 방법을 제공합니다.
아키텍처 다이어그램
┌─────────────────────────────────────────────────────────────┐
│ Client (Browser/Mobile) │
└───────────────────────────┬─────────────────────────────────┘
│
┌───────────────────────────▼─────────────────────────────────┐
│ Next.js Frontend │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Pages │ │ UI │ │ API │ │ State │ │
│ │ │ │Components│ │ Routes │ │ Management│ │
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
└───────────────────────────┬─────────────────────────────────┘
│
┌───────────────────────────▼─────────────────────────────────┐
│ WordPress REST API / GraphQL │
└───────────────────────────┬─────────────────────────────────┘
│
┌───────────────────────────▼─────────────────────────────────┐
│ WordPress Backend │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Posts │ │ Pages │ │ Custom │ │ Media │ │
│ │ │ │ │ │Post Types│ │ Library │ │
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Plugins │ │ Users │ │ Comments│ │ Settings│ │
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
└─────────────────────────────────────────────────────────────┘
헤드리스 WordPress + Next.js의 장점
WordPress의 강점 활용
- 친숙한 관리자 경험: 콘텐츠 편집자들에게 익숙한 편집 환경 제공
- 풍부한 플러그인 생태계: 수천 개의 플러그인을 통한 기능 확장
- 성숙한 사용자 관리: 역할 및 권한 관리 시스템
- 다양한 콘텐츠 타입: 포스트, 페이지, 사용자 정의 포스트 타입, 분류 등
- 기존 콘텐츠 보존: 기존 WordPress 사이트의 콘텐츠를 그대로 활용
Next.js의 강점 활용
- 우수한 성능: 서버 사이드 렌더링(SSR) 및 정적 사이트 생성(SSG)
- SEO 최적화: 검색 엔진 친화적인 페이지 제공
- 개발자 경험: React 기반의 현대적인 개발 환경
- API 라우트: 서버리스 함수를 통한 백엔드 기능 구현
- 증분 정적 재생성(ISR): 동적 콘텐츠의 정적 이점 활용
구현 방법
1. WordPress 설정
- REST API 활성화: WordPress의 내장 REST API 활용
- 필수 플러그인 설치:
- JWT Authentication: 안전한 API 인증
- ACF to REST API: Advanced Custom Fields 데이터를 API에 노출
- WPGraphQL: GraphQL 지원 (선택사항)
- CORS 설정: Next.js 애플리케이션의 API 접근 허용
- 커스텀 엔드포인트 생성: 필요한 데이터 형식에 맞는 API 엔드포인트 추가
2. Next.js 프로젝트 구성
- 프로젝트 초기화:
npx create-next-app my-headless-wp cd my-headless-wp - 필요 패키지 설치:
npm install swr axios @wordpress/block-serialization-default-parser - 환경 변수 설정:
WORDPRESS_API_URL=https://your-wordpress-site.com/wp-json
3. 데이터 페칭 구현
WordPress API 클라이언트 설정:
// lib/api.js
const API_URL = process.env.WORDPRESS_API_URL;
async function fetchAPI(endpoint, params = {}) {
const res = await fetch(`${API_URL}${endpoint}`, params);
if (!res.ok) {
throw new Error(`API error: ${res.status} ${res.statusText}`);
}
return await res.json();
}
export async function getAllPosts() {
return fetchAPI('/wp/v2/posts?_embed&per_page=100');
}
export async function getPostBySlug(slug) {
const posts = await fetchAPI(
`/wp/v2/posts?slug=${slug}&_embed`
);
return posts[0];
}
// 기타 필요한 API 함수들...
4. 페이지 생성
블로그 포스트 페이지 예시:
// pages/posts/[slug].js
import { useRouter } from 'next/router';
import { getPostBySlug, getAllPosts } from '../../lib/api';
import Head from 'next/head';
import PostBody from '../../components/post-body';
export default function Post({ post }) {
const router = useRouter();
if (router.isFallback) {
return <div>Loading...</div>;
}
return (
<article>
<Head>
<title>{post.title.rendered}</title>
</Head>
<h1 dangerouslySetInnerHTML={{ __html: post.title.rendered }} />
<PostBody content={post.content.rendered} />
</article>
);
}
export async function getStaticProps({ params }) {
const post = await getPostBySlug(params.slug);
return {
props: { post },
revalidate: 60 // ISR: 60초마다 재생성
};
}
export async function getStaticPaths() {
const posts = await getAllPosts();
return {
paths: posts.map((post) => ({
params: { slug: post.slug },
})),
fallback: 'blocking',
};
}
콘텐츠 렌더링 전략
1. WordPress 블록(Gutenberg) 처리 방법
WordPress 5.0 이후 도입된 Gutenberg 블록 에디터의 콘텐츠를 Next.js에서 렌더링하는 세 가지 접근법:
a) HTML 직접 렌더링
<div dangerouslySetInnerHTML={{ __html: post.content.rendered }} />
- 장점: 구현 간단
- 단점: React 컴포넌트의 이점 활용 불가
b) HTML 파싱 및 React 컴포넌트로 변환
import parse from 'html-react-parser';
const PostContent = ({ content }) => {
return <div>{parse(content)}</div>;
};
- 장점: 일부 React 이점 활용
- 단점: 복잡한 인터랙션 구현 어려움
c) 블록 데이터 파싱 및 커스텀 컴포넌트 매핑
import { parse } from '@wordpress/block-serialization-default-parser';
const BlockRenderer = ({ blocks }) => {
return blocks.map((block, index) => {
switch (block.blockName) {
case 'core/paragraph':
return <p key={index}>{block.attrs.content}</p>;
case 'core/heading':
return <h2 key={index}>{block.attrs.content}</h2>;
// 다른 블록 타입들...
default:
return null;
}
});
};
const PostContent = ({ rawContent }) => {
const blocks = parse(rawContent);
return <BlockRenderer blocks={blocks} />;
};
- 장점: 완벽한 맞춤형 경험, 최적의 SEO
- 단점: 구현 복잡성, 모든 블록 타입 지원 필요
2. 이미지 최적화
Next.js의 Image 컴포넌트를 활용하여 WordPress 미디어 최적화:
import Image from 'next/image';
const PostImage = ({ mediaItem }) => {
return (
<Image
src={mediaItem.source_url}
width={mediaItem.media_details.width}
height={mediaItem.media_details.height}
alt={mediaItem.alt_text}
layout="responsive"
/>
);
};
인증 및 미리보기 기능
1. 인증 구현
JWT 인증을 통한 보호된 콘텐츠 접근:
// lib/auth.js
export async function login(username, password) {
const response = await fetch(`${process.env.WORDPRESS_API_URL}/jwt-auth/v1/token`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password })
});
const data = await response.json();
if (response.ok) {
// 토큰 저장
localStorage.setItem('wpToken', data.token);
return true;
}
return false;
}
export function getAuthHeader() {
const token = typeof window !== 'undefined' ? localStorage.getItem('wpToken') : null;
return token ? { 'Authorization': `Bearer ${token}` } : {};
}
2. 드래프트 및 미리보기
비공개 콘텐츠 미리보기 구현:
// pages/api/preview.js
export default async function preview(req, res) {
const { secret, slug, id } = req.query;
// 시크릿 검증
if (secret !== process.env.WORDPRESS_PREVIEW_SECRET || !slug) {
return res.status(401).json({ message: '유효하지 않은 토큰' });
}
// 미리보기 모드 활성화
res.setPreviewData({});
// 해당 포스트로 리디렉션
res.redirect(`/posts/${slug}`);
}
SEO 최적화
1. 메타데이터 처리
import Head from 'next/head';
const SEO = ({ title, description, ogImage, canonicalUrl }) => {
return (
<Head>
<title>{title}</title>
<meta name="description" content={description} />
<link rel="canonical" href={canonicalUrl} />
<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
<meta property="og:image" content={ogImage} />
<meta property="og:type" content="article" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content={title} />
<meta name="twitter:description" content={description} />
<meta name="twitter:image" content={ogImage} />
</Head>
);
};
2. Yoast SEO 통합
WordPress의 Yoast SEO 메타데이터를 Next.js에서 활용:
export async function getPostSEOData(slug) {
const post = await getPostBySlug(slug);
const yoastData = post.yoast_head_json || {};
return {
title: yoastData.title || post.title.rendered,
description: yoastData.description || post.excerpt.rendered,
ogImage: yoastData.og_image?.[0]?.url ||
post._embedded?.['wp:featuredmedia']?.[0]?.source_url,
canonical: yoastData.canonical || `https://your-site.com/posts/${slug}`
};
}
배포 및 캐싱 전략
1. 배포 옵션
- Vercel/Netlify: Next.js 애플리케이션 배포에 가장 적합
- Self-hosted: 커스텀 서버 설정이 필요한 경우
2. 캐싱 전략
- ISR(Incremental Static Regeneration): 대부분의 페이지에 적합
export async function getStaticProps() { // 데이터 가져오기 return { props: { data }, revalidate: 60 // 60초마다 재생성 }; } - 주기적인 완전 재빌드: 콘텐츠 업데이트가 빈번하지 않은 경우
- Vercel/Netlify webhook을 WordPress에 연결
- 콘텐츠 업데이트 시 빌드 트리거
3. WordPress 캐싱
- Redis 캐시 활용
- WordPress 캐싱 플러그인(WP Super Cache, W3 Total Cache) 설치
마이그레이션 전략
1. 점진적 마이그레이션 접근법
-
분석 및 계획:
- 가장 중요한 페이지 식별
- URL 구조 및 리디렉션 계획 수립
-
핵심 페이지부터 구현:
- 홈페이지, 주요 랜딩 페이지
- 인기 블로그 포스트
-
프록시 설정:
- Next.js로 마이그레이션된 경로는 새 애플리케이션으로
- 나머지 경로는 기존 WordPress 사이트로 리디렉션
-
점진적 롤아웃:
- 트래픽이 적은 페이지로 시작
- 모니터링 및 이슈 수정
- 성공적으로 검증된 후 주요 페이지로 확장
2. URL 구조 및 리디렉션
기존 WordPress URL 구조를 유지하거나 301 리디렉션 설정:
// next.config.js
module.exports = {
async redirects() {
return [
{
source: '/blog/:year/:month/:slug',
destination: '/posts/:slug',
permanent: true,
},
// 다른 리디렉션 규칙들...
];
},
};
성능 최적화
1. 코어 웹 바이탈(Core Web Vitals) 최적화
- LCP(Largest Contentful Paint): 이미지 최적화, 중요 CSS 인라인화
- FID(First Input Delay): 자바스크립트 청크 분할, 중요하지 않은 JS 지연 로드
- CLS(Cumulative Layout Shift): 이미지 크기 명시, 폰트 최적화
2. 이미지 및 폰트 최적화
- Next.js Image 컴포넌트 활용
- 폰트 preload 및 display: swap 적용
3. API 응답 최적화
- WordPress REST API 응답에서 필요한 필드만 요청
- API 응답 캐싱 구현
유지보수 및 워크플로우
1. 콘텐츠 편집 워크플로우
- WordPress 관리자 패널에서 콘텐츠 생성/편집
- 미리보기 기능을 통해 Next.js에서 변경사항 확인
- 게시 시 Next.js 페이지 자동 업데이트(ISR 또는 webhook 활용)
2. 개발자 워크플로우
- WordPress 플러그인 및 테마 업데이트 관리
- Next.js 애플리케이션 코드 업데이트
- API 변경사항 모니터링 및 대응
3. 모니터링 및 분석
- WordPress 및 Next.js 애플리케이션 모니터링
- API 응답 시간 및 성능 추적
- 사용자 분석 데이터 수집
주의사항 및 한계
- API 속도 제한: WordPress REST API의 속도 제한 고려
- 플러그인 호환성: 일부 WordPress 플러그인은 헤드리스 환경과 완벽하게 호환되지 않음
- 실시간 기능: 댓글, 양식 제출과 같은 양방향 기능 구현 복잡성
결론
WordPress를 헤드리스 CMS로 활용하고 Next.js로 프론트엔드를 구현하는 접근법은 기존 WordPress 사이트의 모든 콘텐츠 관리 기능을 유지하면서 현대적인 프론트엔드 개발 경험을 제공합니다. 이 아키텍처는 WordPress 기반 사이트를 점진적으로 현대화하고, 더 나은 성능과 사용자 경험을 제공하는 효과적인 전략입니다.
특히 개발 리소스가 제한적이거나, 콘텐츠 편집자들에게 익숙한 환경을 유지해야 하는 경우, 또는 대규모 콘텐츠 마이그레이션의 위험을 줄이고자 할 때 이상적인 선택이 될 수 있습니다.