Files
Obsidian/Arkstory/wordpress-headless-nextjs.md
2025-03-26 18:16:46 +09:00

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. 점진적 마이그레이션 접근법

  1. 분석 및 계획:

    • 가장 중요한 페이지 식별
    • URL 구조 및 리디렉션 계획 수립
  2. 핵심 페이지부터 구현:

    • 홈페이지, 주요 랜딩 페이지
    • 인기 블로그 포스트
  3. 프록시 설정:

    • Next.js로 마이그레이션된 경로는 새 애플리케이션으로
    • 나머지 경로는 기존 WordPress 사이트로 리디렉션
  4. 점진적 롤아웃:

    • 트래픽이 적은 페이지로 시작
    • 모니터링 및 이슈 수정
    • 성공적으로 검증된 후 주요 페이지로 확장

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 기반 사이트를 점진적으로 현대화하고, 더 나은 성능과 사용자 경험을 제공하는 효과적인 전략입니다.

특히 개발 리소스가 제한적이거나, 콘텐츠 편집자들에게 익숙한 환경을 유지해야 하는 경우, 또는 대규모 콘텐츠 마이그레이션의 위험을 줄이고자 할 때 이상적인 선택이 될 수 있습니다.