2026年5月17日
2026年5月17日
WordPressのGraphQL APIをWPGraphQLで実装する方法
はじめに
REST APIに代わるGraphQL APIをWordPressに追加するWPGraphQLプラグインは、フロントエンドが必要なデータだけを取得できるため通信量を削減し、型安全な開発を実現します。HeadlessなWordPress構成やNext.js・Gatsbyとの連携では特に威力を発揮します。本記事ではインストールからカスタムフィールドの公開・ミューテーションの実装まで5ステップで解説します。
症状・原因
- REST APIでは不要なデータまで取得してしまいパフォーマンスが低い
- 複数エンドポイントへのリクエストが増えてフロントエンドの実装が複雑になる
- カスタムフィールドをAPI経由でフロントエンドに公開する方法がわからない
解決手順
ステップ1:WPGraphQLプラグインをインストールしてGraphiQL IDEを確認する
# WP-CLIでWPGraphQLプラグインをインストールして有効化する
wp plugin install wp-graphql --activate
# インストール確認(バージョンを表示する)
wp plugin get wp-graphql --field=version
# GraphQLエンドポイントは以下のURLで利用可能になる
# https://yoursite.com/graphql
# GraphiQL IDEは管理画面の「GraphQL > GraphiQL IDE」からアクセスできる
# ブラウザ上でクエリを試してスキーマを探索できる
# GraphiQL IDEで試せる基本クエリ(投稿一覧を取得する)
query GetRecentPosts {
posts(first: 5, where: { status: PUBLISH }) {
nodes {
id
title
slug
date
excerpt
featuredImage {
node {
sourceUrl
altText
}
}
categories {
nodes {
name
slug
}
}
}
}
}
ステップ2:カーソルページネーションを使って投稿を取得する
# カーソルベースのページネーションで投稿を取得する
# REST APIのページ番号と異なり、カーソルは安定したページネーションを実現する
query GetPostsWithPagination($after: String, $first: Int = 10) {
posts(first: $first, after: $after, where: { status: PUBLISH }) {
pageInfo {
hasNextPage # 次のページがあるか
hasPreviousPage # 前のページがあるか
startCursor # 現在ページの開始カーソル
endCursor # 現在ページの終了カーソル(次ページのafterに使う)
}
edges {
cursor # 各記事のカーソル値
node {
id
title
slug
date
}
}
}
}
# 変数(Variables)パネルに入力する例
# {
# "after": "YXJyYXljb25uZWN0aW9uOjE=",
# "first": 10
# }
ステップ3:カスタムフィールドをGraphQLスキーマに追加する
<?php
// ACFや独自のカスタムフィールドをGraphQLに公開する
add_action( 'graphql_register_types', 'my_register_graphql_fields' );
function my_register_graphql_fields() {
// 「投稿」タイプに「author_profile」フィールドを追加する
register_graphql_field( 'Post', 'authorProfile', [
'type' => 'String', // GraphQLの型
'description' => '著者プロフィール文',
'resolve' => function( $post ) {
// WordPressのpost_metaから値を取得して返す
return get_post_meta( $post->databaseId, 'author_profile', true ) ?: null;
},
] );
// 「投稿」に「読了時間(分)」フィールドを追加する
register_graphql_field( 'Post', 'readingTimeMinutes', [
'type' => 'Int',
'description' => '推定読了時間(分)',
'resolve' => function( $post ) {
// 本文の単語数から読了時間を計算する(日本語は約500字/分)
$content = get_post_field( 'post_content', $post->databaseId );
$char_count = mb_strlen( strip_tags( $content ) );
return max( 1, (int) ceil( $char_count / 500 ) );
},
] );
// カスタムオブジェクト型を定義してネストしたデータを返す
register_graphql_object_type( 'ProductSpec', [
'description' => '商品スペック情報',
'fields' => [
'weight' => [ 'type' => 'String' ],
'size' => [ 'type' => 'String' ],
'material' => [ 'type' => 'String' ],
],
] );
register_graphql_field( 'Post', 'productSpec', [
'type' => 'ProductSpec',
'resolve' => function( $post ) {
$spec = get_post_meta( $post->databaseId, 'product_spec', true );
return is_array( $spec ) ? $spec : null;
},
] );
}
ステップ4:ミューテーションで投稿を作成・更新する
# JWT認証後に使用する投稿作成ミューテーション
# WPGraphQL JWT Authenticationプラグインが必要
mutation CreatePost($input: CreatePostInput!) {
createPost(input: $input) {
post {
id
title
slug
status
date
}
clientMutationId
}
}
# 変数例
# {
# "input": {
# "title": "新しい記事タイトル",
# "content": "<p>本文テキスト</p>",
# "status": "DRAFT",
# "categoryIds": ["dGVybTox"],
# "clientMutationId": "create-post-001"
# }
# }
// Next.js側でGraphQLミューテーションを実行する例(Apollo Client使用)
import { gql, useMutation } from '@apollo/client';
const CREATE_POST = gql`
mutation CreatePost($title: String!, $content: String!) {
createPost(input: {
title: $title
content: $content
status: DRAFT
clientMutationId: "create-from-frontend"
}) {
post {
id
slug
}
}
}
`;
export function useCreatePost() {
const [createPost, { loading, error }] = useMutation(CREATE_POST, {
// Authorizationヘッダーを付けてリクエストする
context: {
headers: {
Authorization: `Bearer ${localStorage.getItem('wp_token')}`,
},
},
});
return { createPost, loading, error };
}
ステップ5:WPGraphQL Smart Cacheとパーシステッドクエリで高速化する
<?php
// WPGraphQL Smart Cacheプラグインでレスポンスをキャッシュする設定
// まずプラグインをインストールする
// wp plugin install wp-graphql-smart-cache --activate
// パーシステッドクエリ(Persisted Queries)をWordPress側で有効化する
// 長いクエリ文字列をハッシュIDに短縮してURLの長さとセキュリティを改善する
add_filter( 'graphql_persisted_queries_enabled', '__return_true' );
// 特定のクエリのキャッシュ時間をカスタマイズする(秒単位)
add_filter( 'graphql_cache_max_age', 'my_graphql_cache_max_age', 10, 2 );
function my_graphql_cache_max_age( $max_age, $query_params ) {
// 記事一覧クエリは5分キャッシュする
if ( isset( $query_params['operationName'] ) &&
$query_params['operationName'] === 'GetRecentPosts' ) {
return 300; // 5分 = 300秒
}
// デフォルト(1時間)を返す
return $max_age;
}
// クライアント側でパーシステッドクエリを使用する(Apollo Client設定)
import { ApolloClient, InMemoryCache, HttpLink } from '@apollo/client';
import { createPersistedQueryLink } from '@apollo/client/link/persisted-queries';
import { sha256 } from 'crypto-hash';
// パーシステッドクエリリンクを作成する(APQ: Automatic Persisted Queries)
const persistedQueriesLink = createPersistedQueryLink({ sha256 });
const httpLink = new HttpLink({ uri: 'https://cms.yoursite.com/graphql' });
// クライアントを初期化する
export const client = new ApolloClient({
link: persistedQueriesLink.concat(httpLink),
cache: new InMemoryCache({
typePolicies: {
// Postタイプのキャッシュ設定
Post: {
keyFields: ['id'],
},
},
}),
// SSR時はSSRモードを有効にする
ssrMode: typeof window === 'undefined',
});
注意事項
- 認証: ミューテーション(書き込み操作)には必ずJWT認証(WPGraphQL JWT Authenticationプラグイン)を実装してください。公開GraphQLエンドポイントに認証なしで書き込みを許可しないでください。
- イントロスペクション: 本番環境では
graphql_introspection_enabledフィルターでfalseを返してスキーマの公開を制限することをお勧めします。 - N+1問題: リゾルバーが多数のデータベースクエリを発行する場合はDataLoaderパターンを実装してパフォーマンスを最適化してください。
まとめ
WPGraphQLを使うことでWordPressにGraphQL APIを追加し、フロントエンドが必要なデータだけを効率よく取得できる環境が整います。カスタムフィールドの公開・ミューテーション・Smart Cacheを組み合わせることで、高速で型安全なHeadless WordPress構成を実現できます。関連記事:WordPressをHeadless CMSとしてNext.jsフロントエンドと連携する方法