未分類
2025/03/29
2025/04/10

headless-wordpress (4) データフェッチ
~ 目次 ~
1 記事作成
まず新規投稿を2〜3作成、それぞれタイトル、本文、アイキャッチ画像を設定しておきます。
この時リンクにかなが含まれていると読み込み時にエラーとなるので、特にタイトルに全角文字が含まれている場合は気をつけましょう。
右サイドバーの投稿タブから、リンク部分をクリックして変更しておきます。
2 WPGraphqlインストール
wordpressのpluginから、wpgraphqlと検索してインストール。有効化したらサイドバーメニューからwpgraphqlのIDEを開いて以下を入力
query postsListQuery {
posts {
edges {
node {
date
excerpt
id
modified
slug
title
categories {
edges {
node {
name
slug
}
}
}
featuredImage {
node {
sourceUrl
}
}
}
}
}
}
左上のボタンを押してデータが取れていることを確認。
3 frontend-nextからデータフェッチ
まずはデータフェッチの流れを一度一つのファイルに並べてみました、あとでリファクタリング、別ファイルに分けます。
import Image from 'next/image'
// データフェッチ関数
async function fetchGraphQL(
query: string,
variables: Record<string, unknown> = {},
) {
try {
const res = await fetch('http://backend-wp/graphql', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query, variables }),
})
const json = await res.json()
return json.data
} catch (error) {
console.error('Fetch failed:', error)
return null
}
}
// 型
type postsListResponseType = {
posts: {
edges: {
node: {
date: string
excerpt: string
id: string
modified: string
slug: string
title: string
categories: {
edges: {
node: {
name: string
slug: string
}
}[]
}
featuredImage: {
node: {
sourceUrl: string
}
}
}
}[]
}
}
// データフェッチ関数の引数に渡すクエリ
const postsListQuery = `
query postsListQuery {
posts {
edges {
node {
date
excerpt
id
modified
slug
title
categories {
edges {
node {
name
slug
}
}
}
featuredImage {
node {
sourceUrl
}
}
}
}
}
}
`
// 入れ子になってるデータを取り出しやすく加工
async function getPostsList() {
try {
const res: postsListResponseType = await fetchGraphQL(postsListQuery)
return res.posts.edges.map((data) => {
const posts = {
date: data.node.date,
excerpt: data.node.excerpt,
id: data.node.id,
modified: data.node.modified,
slug: data.node.slug,
title: data.node.title,
categories: {
name: data.node.categories.edges[0].node.name,
slug: data.node.categories.edges[0].node.slug,
},
featuredImage: {
sourceUrl: data.node.featuredImage.node.sourceUrl,
},
}
return posts
})
} catch (error) {
console.error('Error in getPostsList:', error)
throw error
}
}
// 加工したデータを取得して表示
export default async function Home() {
const posts = await getPostsList()
return (
<div className="grid gap-3">
<h1 className="border border-red-500">headless-wordpress</h1>
<ul className="grid gap-3 border border-blue-500 p-3">
{posts.map((post) => {
return (
<li key={post.id} className="border border-yellow-500">
<h2>{post.title}</h2>
<div className="relative h-24 w-24">
<Image
priority
fill
className="object-cover"
src={post.featuredImage.sourceUrl}
alt="キャッチアップ画像"
unoptimized
/>
</div>
<div
dangerouslySetInnerHTML={{
__html: post.excerpt,
}}
></div>
</li>
)
})}
</ul>
</div>
)
}
リファクタリング、次のようにしてみました。
frontend-next/
├── .env
└── src/
├── api/
│ └── fetchGraphQL.ts
├── app/
│ └── page.tsx
├── query/
│ └── postsListQuery.ts
├── data/
│ └── getPostsList.ts
└── type/
└── postsListResponse.ts
.env
NEXT_PUBLIC_WPGRAPHQL_ENDPOINT=http://backend-wp/graphql
fetchGraphQL.ts
export async function fetchGraphQL(
query: string,
variables: Record<string, unknown> = {},
) {
try {
const res = await fetch(`${process.env.NEXT_PUBLIC_WPGRAPHQL_ENDPOINT}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query, variables }),
})
const json = await res.json()
return json.data
} catch (error) {
console.error('Fetch failed:', error)
return null
}
}
page.tsx
import Image from 'next/image'
import { getPostsList } from '../data/getPostsList'
export default async function Home() {
const posts = await getPostsList()
return (
<div className="grid gap-3">
<h1 className="border border-red-500">headless-wordpress</h1>
<ul className="grid gap-3 border border-blue-500 p-3">
{posts.map((post) => {
return (
<li key={post.id} className="border border-yellow-500">
<h2>{post.title}</h2>
<div className="relative h-24 w-24">
<Image
priority
fill
className="object-cover"
src={post.featuredImage.sourceUrl}
alt="キャッチアップ画像"
unoptimized
/>
</div>
<div
dangerouslySetInnerHTML={{
__html: post.excerpt,
}}
></div>
</li>
)
})}
</ul>
</div>
)
}
postsListQuery.ts
export const postsListQuery = `
query postsListQuery {
posts {
edges {
node {
date
excerpt
id
modified
slug
title
categories {
edges {
node {
name
slug
}
}
}
featuredImage {
node {
sourceUrl
}
}
}
}
}
}
`
getPostsList.ts
import { fetchGraphQL } from '../api/fetchGraphQL'
import { postsListResponseType } from '../type/postsListResponse'
import { postsListQuery } from '../query/postsListQuery'
export async function getPostsList() {
try {
const res: postsListResponseType = await fetchGraphQL(postsListQuery)
return res.posts.edges.map((data) => {
const posts = {
date: data.node.date,
excerpt: data.node.excerpt,
id: data.node.id,
modified: data.node.modified,
slug: data.node.slug,
title: data.node.title,
categories: {
name: data.node.categories.edges[0].node.name,
slug: data.node.categories.edges[0].node.slug,
},
featuredImage: {
sourceUrl: data.node.featuredImage.node.sourceUrl,
},
}
return posts
})
} catch (error) {
console.error('Error in getPostsList:', error)
throw error
}
}
postsListResponse.ts
export type postsListResponseType = {
posts: {
edges: {
node: {
date: string
excerpt: string
id: string
modified: string
slug: string
title: string
categories: {
edges: {
node: {
name: string
slug: string
}
}[]
}
featuredImage: {
node: {
sourceUrl: string
}
}
}
}[]
}
}