WordPress CMS統合ガイド¶
このドキュメントは、Next.js StorefrontとWordPress CMSの統合方法、アーキテクチャ、実装パターンを説明します。
概要¶
このプロジェクトでは、WordPressをHeadless CMSとして使用し、以下のコンテンツを管理します:
- お知らせ(Announcements): サイト全体のお知らせ、重要なお知らせの固定表示
- キャンペーン(Campaigns): プロモーションキャンペーン情報
- Heroスライド(Hero Slides): ホームページのヒーローセクション用スライド
Next.js Storefrontは、WordPressのGraphQL API(WPGraphQL)を通じてコンテンツを取得し、サーバーサイドレンダリング(SSR)で表示します。
アーキテクチャ¶
┌─────────────────┐
│ WordPress CMS │
│ (Headless) │
│ │
│ - Announcements │
│ - Campaigns │
│ - Hero Slides │
└────────┬────────┘
│
│ GraphQL API
│ (WPGraphQL)
│
▼
┌─────────────────┐
│ Next.js │
│ Storefront │
│ │
│ - SSR Fetch │
│ - Components │
│ - Display │
└─────────────────┘
データフロー¶
- コンテンツ作成: WordPress管理画面でコンテンツを作成・編集
- GraphQL API: WPGraphQLプラグインがGraphQLエンドポイントを提供
- Next.js Fetch: StorefrontがサーバーサイドでGraphQL APIを呼び出し
- 表示: 取得したデータをReactコンポーネントで表示
設定¶
環境変数¶
Next.js Storefrontでは以下のルールでエンドポイントを解決します。
- サーバー実行文脈(SSR/Route Handler等):
WORDPRESS_GRAPHQL_ENDPOINT(例:https://wp.example.com/graphql)を最優先で参照し、WordPress本番ドメインへ直接アクセスする。 - クライアント実行文脈: WordPress の実ドメインを公開しないためプロキシ
/api/wordpress/graphqlを使用する。プロキシはapps/storefront/src/app/api/wordpress/graphql/route.tsで実装されており、storefrontConfigからはsiteUrl + /api/wordpress/graphqlの絶対URLとして参照される。
結果として、秘密情報は環境変数に閉じ込めつつ、クライアントは統一したパスでアクセスできます。
設定ファイル¶
設定は apps/storefront/src/lib/config.ts で管理されています:
export const storefrontConfig = {
wordpressGraphqlEndpoint:
typeof window === 'undefined'
? (process.env.WORDPRESS_GRAPHQL_ENDPOINT ??
new URL('/api/wordpress/graphql', siteUrl).toString())
: new URL('/api/wordpress/graphql', siteUrl).toString(),
// ...(Vendure関連設定など)
};
※実装は apps/storefront/src/lib/config.ts
にあり、プロキシ/直接アクセスの切り替えが自動化されています。
実装パターン¶
GraphQLクライアント¶
WordPress GraphQL APIへのリクエストは
apps/storefront/src/lib/wordpress/client.ts の fetchWordPressGraphQL
関数を使用します。
import { fetchWordPressGraphQL } from '@/lib/wordpress/client';
const data = await fetchWordPressGraphQL<QueryResult>({
query: MY_QUERY,
variables: { first: 10 },
cache: 'no-store', // キャッシュ設定
allowPartialData: true, // エラーがあってもdataを返す
});
コンテンツタイプ別の実装¶
お知らせ(Announcements)¶
ファイル: apps/storefront/src/lib/wordpress/announcements.ts
主な機能:
fetchAnnouncements(): お知らせ一覧を取得fetchFeaturedAnnouncements(): フィーチャー済み(isFeatured: true)のお知らせを取得
使用例:
import {
fetchAnnouncements,
fetchFeaturedAnnouncements,
} from '@/lib/wordpress/announcements';
// 通常のお知らせ一覧
const announcements = await fetchAnnouncements({ limit: 10 });
// フィーチャー済みお知らせ(サイト上部に固定表示)
const featured = await fetchFeaturedAnnouncements({ limit: 5 });
コンポーネント:
-
FeaturedAnnouncementBanner: フィーチャー済みお知らせをサイト上部に表示 -
AnnouncementSection: お知らせ一覧セクション
キャンペーン(Campaigns)¶
ファイル: apps/storefront/src/lib/wordpress/campaigns.ts
主な機能:
fetchCampaigns(): キャンペーン一覧を取得(ACFのorderフィールドでソート)
使用例:
import { fetchCampaigns } from '@/lib/wordpress/campaigns';
const campaigns = await fetchCampaigns({ limit: 10 });
コンポーネント:
CampaignBannerSection: キャンペーンバナー一覧表示
Heroスライド(Hero Slides)¶
ファイル: apps/storefront/src/lib/wordpress/hero-slides.ts
主な機能:
fetchHeroSlides(): Heroスライド一覧を取得(ACFのorderフィールドでソート)
使用例:
import { fetchHeroSlides } from '@/lib/wordpress/hero-slides';
const heroSlides = await fetchHeroSlides({ limit: 10 });
コンポーネント:
HomeHero: ホームページのHeroセクション(カルーセル表示)
エラーハンドリング¶
フォールバッククエリ¶
各コンテンツタイプは、メインクエリが失敗した場合にフォールバッククエリを実行します:
// メインクエリ(announcements)
try {
const data = await fetchWordPressGraphQL({ query: ANNOUNCEMENT_QUERY });
// ...
} catch (error) {
// フォールバッククエリ(contentNodes)
const fallback = await fetchWordPressGraphQL({
query: ANNOUNCEMENT_FALLBACK_QUERY,
});
// ...
}
部分データの許可¶
allowPartialData: true
を設定すると、GraphQLエラーがあってもdataが存在する場合はデータを返します:
const data = await fetchWordPressGraphQL({
query: MY_QUERY,
allowPartialData: true, // エラーがあってもdataを返す
});
サーバーサイドレンダリング(SSR)¶
すべてのWordPressコンテンツはサーバーサイドで取得されます:
ページコンポーネント¶
// app/page.tsx
export default async function HomePage() {
const announcements = await fetchAnnouncements({ limit: 10 });
const heroSlides = await fetchHeroSlides({ limit: 10 });
const campaigns = await fetchCampaigns({ limit: 10 });
return (
<HomePageClient
initialAnnouncements={announcements}
initialHeroSlides={heroSlides}
initialCampaigns={campaigns}
/>
);
}
レイアウトコンポーネント¶
// app/layout.tsx
export default async function RootLayout({ children }: RootLayoutProps) {
const featuredAnnouncements = await fetchFeaturedAnnouncements({ limit: 5 });
return (
<html>
<body>
{featuredAnnouncements.length > 0 && (
<FeaturedAnnouncementBanner announcements={featuredAnnouncements} />
)}
{/* ... */}
</body>
</html>
);
}
キャッシュ戦略¶
現時点では、WordPressコンテンツはキャッシュしない設定(cache: 'no-store')になっています:
- 理由: コンテンツ更新を即座に反映するため
- 将来の改善: ISR(Incremental Static Regeneration)やrevalidate設定を検討
コンテンツモデル¶
お知らせ(Announcement)¶
WordPress投稿タイプ: announcement
標準フィールド:
title: タイトル-
date: 公開日 -
slug: スラッグ link: リンクURL
ACFフィールド (announcementMeta):
-
isFeatured: フィーチャー済みフラグ(boolean) -
relatedLink: 関連リンク(string)
キャンペーン(Campaign)¶
WordPress投稿タイプ: campaign
標準フィールド:
title: タイトルdate: 公開日slug: スラッグlink: リンクURLfeaturedImage: アイキャッチ画像
ACFフィールド (campaignMeta):
order: 表示順序(number)image: キャンペーン画像(MediaItem)
Heroスライド(Hero Slide)¶
WordPress投稿タイプ: hero_slide
標準フィールド:
title: タイトルdate: 公開日slug: スラッグlink: リンクURL
ACFフィールド (heroSlideMeta):
order: 表示順序(number)media: メディア(image/video)type: メディアタイプ('image' | 'video')image: 画像(desktop/mobile対応)video: 動画(desktop/mobile対応)alt: altテキストlink: リンク先(Campaign/Announcement)
トラブルシューティング¶
GraphQLエラーが発生する¶
- エンドポイントが正しいか確認
curl http://localhost:8181/graphql -X POST -H "Content-Type: application/json" -d '{"query":"{ __typename }"}'
- WPGraphQLプラグインが有効化されているか確認
docker compose run --rm wp-cli plugin list
- ACFフィールドがGraphQLに公開されているか確認
- WordPress管理画面 → Custom Fields → フィールドグループ → GraphQL設定
コンテンツが表示されない¶
- 投稿が公開状態か確認
- GraphQLスキーマに投稿タイプが登録されているか確認
query {
__schema {
types {
name
}
}
}
- ブラウザの開発者ツールでネットワークエラーを確認
- サーバーログでエラーを確認
画像が表示されない¶
- Next.jsの画像設定を確認(
next.config.js) - remotePatternsにWordPressドメインが登録されているか確認
- 画像URLが正しいか確認