Astro&WordPressで記事一覧(ページネーション)と記事詳細ページの実装

2025/03/14 (金) - 09:00 JavaScriptPHP&CMS

以前に副業でWordPressとAstroでヘッドレスCMSでブログを実装しましたのでそのメモです。取り急ぎ記事一覧と記事詳細のみでファイル構成は最低限のものだけ。

src
├─ components
│    └─ Pagination.astro
├─ layouts
│    └─ Layout.astro
└─ pages
     ├─ [slug].astro
     ├─ index.astro
     └─ page
         └─ [paged].astro

WordPressの記事の呼び出しは、WordPressのREST APIを使います。

WordPress連携実装例

REST APIのエンドポイントは.envに記載しておきます。ついでにブログ名も設定しておくと一括で変更できます。

BLOG_TITLE=ひなちゃんの日記
API_JSON=https://example.com/wp-json/wp/v2/posts/

レイアウトを定義するにLayout.astroに大枠のHTMLとブラウザに表示されるタイトルのtitle要素の中身を取得するコードを記載します。必要最低限の記載のみです。

---
const {meta} = Astro.props;
---
<!doctype html>
<html lang="ja">
 <head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width">
  <title>{meta.title}</title>
 </head>
 <body>
  <slot />
 </body>
</html>

トップページの記事一覧をindex.astroに実装します。ブラウザに表示されるタイトルは[トップページ – ブログ名]となります。

---
import { format } from 'date-fns';
import Layout from '../layouts/Layout.astro';
import Pagination from '../components/Pagination.astro';
const res = await fetch(`${import.meta.env.API_JSON}`);
const posts = await res.json();
const total = await fetch(import.meta.env.API_JSON).then((res) => {return res.headers.get('X-WP-TotalPages')});
const page: {
 current: number,
 total: number 
} = {
 current: 1,
 total: Number(total)
}
const meta: {
 title: string
} = {
 title: `トップページ - ${import.meta.env.BLOG_TITLE}`
}
---
<Layout meta={meta}>
 <main>
 {posts.map((post: { slug: string; title: { rendered: string }; content: { rendered: string }; date: string }) => (
 <article><a href={`/${post.slug}`}>
  <h2>{post.title.rendered}</h2>
  <p>{format(new Date(post.date), 'yyyy年MM月dd日')}</p>
 </a></article>
 ))}
 <Pagination page={page} />
</main>
</Layout>

ページネーションの記事一覧は/page/[paged].astroで動的パスで取得し、getStaticPathsで生成します。ブラウザに表示されるタイトルは[nページ目 – ブログ名]となります。

---
import { format } from 'date-fns';
import Layout from '../../layouts/Layout.astro';
import Pagination from '../../components/Pagination.astro';
export async function getStaticPaths(){
 const total = await fetch(import.meta.env.API_JSON).
 then((res) => {return Number(res.headers.get('X-WP-TotalPages'))});
 return Array.from({ length: total }, (num,i) => ({
  params: { paged: `${i + 1}` }
 }))
}
const {paged} = Astro.params;
const res = await fetch(`${import.meta.env.API_JSON}?page=${paged}`);
const posts = await res.json();
const total = await fetch(import.meta.env.API_JSON).then((res) => {return res.headers.get('X-WP-TotalPages')});
const page: {
 current: number,
 total: number 
} = {
 current: Number(paged),
 total: Number(total)
}
const meta: {
 title: string
} = {
 title: `${paged}ページ目 - ${import.meta.env.BLOG_TITLE}`
}
---
<Layout meta={meta}>
 <main>
 {posts.map((post: { slug: string; title: { rendered: string }; content: { rendered: string }; date: string }) => (
  <article><a href={`/${post.slug}`}>
   <h2>{post.title.rendered}</h2>
   <p>{format(new Date(post.date), 'yyyy年MM月dd日')}</p>
  </a></article>
 ))}
 <Pagination page={page} />
</main>
</Layout>

ページネーション部分は別コンポーネントで管理しました。components/Pagination.astroで実装し呼び出します。

---
const { page } = Astro.props;
const prev = page.current-1;
const next = page.current+1;
---
<p>{page.current} / {page.total}</p>
<p>
{page.current!=1 && (
 <a href={`/page/${String(prev)}`}>前のページへ</a>
)}
{page.current!=page.total && (
 <a href={`/page/${String(next)}`}>次のページへ</a>
)}
</p>

記事詳細は[slug].astroで動的パスで取得し、getStaticPathsで生成します。ブラウザに表示されるタイトルは[記事タイトル – ブログ名]となります。

---
import { format } from 'date-fns';
import Layout from '../layouts/Layout.astro';
export async function getStaticPaths(){
 const res = await fetch(import.meta.env.API_JSON);
 const posts = await res.json();
 const paths = posts.map((post: { slug: string }) => ({
  params: { slug: post.slug }
 }));
 return paths;
}
const {slug} = Astro.params;
const post_res = await fetch(`${import.meta.env.API_JSON}?slug=${slug}`);
const [post] = await post_res.json();
const meta: {
 title: string
} = {
 title: `${post.title.rendered} - ${import.meta.env.BLOG_TITLE}`
}
---
<Layout meta={meta}>
 <main>
  <h1>{post.title.rendered}</h1>
  <p>{format(new Date(post.date), 'yyyy年MM月dd日')}</p>
  <div set:html={post.content.rendered} />
 </main>
</Layout>

実装し終わったらプレビューしてテストします。

$ npm run dev

CSSでのデザイン実装や、metaタグ、フロント周りのマークアップで整えれば出来上がり。

関連記事

おしまい

タグ:

記事をシェアする

  • facebookでシェアする
  • twitter(X)でシェアする
  • LINEでシェアする
  • はてなブックマークでシェアする
  • Threadsでシェアする
  • Pocketでシェアする
  • Pinterestでシェアする

おすすめ記事

トラックバック & ピンバック

この記事へのトラックバックURI
https://weblog.walk-life.me/astro_wordpress_cms/trackback/

コメント

コメントは下記からどうぞ

ページの先頭へ