水曜日, 5月 21, 2025
ホームWordPresswordpress + astro.jsのヘッドレスCMS構築の道のり #8 ページネーションroyaltrux

wordpress + astro.jsのヘッドレスCMS構築の道のり #8 ページネーションroyaltrux

🧠 概要:

記事の概要

この記事では、WordPressとAstro.jsを利用してヘッドレスCMSの構築過程における「ページネーション」の実装方法について詳しく説明しています。具体的には、静的なページを生成し、取得したデータを使って複数のページに分けてコンテンツを表示する方法を示しています。

要約の箇条書き

  • 実装目標: ページネーションを実装し、静的ページとして出力する。
  • URL形式: /tags/[slug]/page/[page].astro
  • WordPress APIの使用: タグのIDとページ番号を使って、APIからデータを取得する。
  • ページ数の計算: getStaticPaths()を使って必要な静的ページを計算・生成。
  • ファイル構成: /pages/tags/[slug]/page/[page].astro という動的ルーティング構成。
  • コード実装:
    • getStaticPaths()内で、受け取ったタグからページ数を計算。
    • APIから投稿を取得し、エラー処理も実装。
  • HTML実装: 動的に生成したページで投稿の内容やナビゲーションを表示。
  • ページ番号のナビゲーション: 各ページに前後のリンクと現在のページ番号を表示する方法を提案。
  • ビルド結果: 正常にページネーションが動作することを確認。

このプロセスを通じて、Astro.jsの特性とWordPress APIとの連携がどのように活用されるかが解説されています。

wordpress + astro.jsのヘッドレスCMS構築の道のり #8 ページネーションroyaltrux

今回は、ページネーションを実装してみます。
ページネーションとコンテンツの表示部分だけ、Vueで組んでしまったりも出来ますが(Vue や React も利用できるのが Astro のいいとこですよね)、今回はがっつりと静的ページとして吐き出すようにします!

ページネーション実装の概要

  • URL形式:/tags/[slug]/page/[page].astro

  • WordPress APIでページ指定:?tags=ID&page=2&per_page=4

  • ページ数を計算して、getStaticPaths() で静的ページを複数生成

と、こんな感じになります!

ファイル構成

今回は /pages/tags/ の下に、タグとページ番号の2段階の動的ルーティングになる構成です。

src/pages/tags/[slug]/page/[page].astro

コード実装

そして実際のコードは、まずはスクリプトは

---
export async function getStaticPaths() {
  
  const tagRes = await fetch('http://headless.local/wp-json/wp/v2/tags');
  const tags = await tagRes.json();

  const paths = [];

  
  for (const tag of tags) {
    const count = tag.count;
    const totalPages = Math.ceil(count / 4);

    for (let page = 1; page params: {
          slug: tag.slug,
          page: page.toString(),
        },
        props: {
          tag,
          currentPage: page,
        },
      });
    }
  }

  return paths;
}

const { tag, currentPage } = Astro.props;


const offsetRes = await fetch(`http://headless.local/wp-json/wp/v2/posts?tags=${tag.id}&per_page=4&page=${currentPage}&_embed`);

let posts = [];
let fetchError = false;

try {
  if (!offsetRes.ok) throw new Error(`記事取得失敗: ${offsetRes.status}`);
  posts = await offsetRes.json();
} catch (err) {
  console.error("記事取得エラー:", err);
  fetchError = true;
}
---

投稿を取得する部分は、これまでやってきた実装と変わらないです。

今回の getStaticPaths() の中身を詳しく解説

ちと前にも getStaticPaths() 内の props の話しをしたんですが、今回は中身を細かく説明してみます!
params や props が何なのかが分かると思います。


const tagRes = await fetch('http:
const tags = await tagRes.json();

const paths = [];

この最初の3行は分かるとは思いますが…
const paths = [];
はこの後、for文で値を入れていく変数で、初期値として空の配列を入れています。

for (const tag of tags) {
  
  const count = tag.count;
  
  const totalPages = Math.ceil(count / 4);

fetchしてきたデータを tagRes.json() で

for (let page = 1; page 

page という変数を 1 から totalPages(そのタグに必要なページ数)まで繰り返します。
例:投稿が 9 件で 1ページ4件 → totalPages = 3 → page = 1, 2, 3

paths.push({
  params: {
    slug: tag.slug,
    page: page.toString(),
  },
  props: {
    tag,
    currentPage: page,
  },
});

paths.push({
paths というリストに、1つずつ「ビルドすべきページの情報」を追加します。

params: {
  slug: tag.slug,
  page: page.toString(),
},

params は URL の /tags/[slug]/page/[page]/ に対応しています。
たとえば:

のように、何のパラメーターにどの値が入るかをここで指定します。

props: {
  tag,
  currentPage: page,
},

各ページに「そのタグ」と「いま何ページ目か」の情報をprops で渡します。
そして Astro.props 経由で .astro ファイル内で使えるようになります。

実行結果のイメージ

たとえば tag.slug = ‘travel’, 投稿数 9件(1ページ4件)なら:

[
  {
    params: { slug: 'travel', page: '1' },
    props: { tag: {...}, currentPage: 1 }
  },
  {
    params: { slug: 'travel', page: '2' },
    props: { tag: {...}, currentPage: 2 }
  },
  {
    params: { slug: 'travel', page: '3' },
    props: { tag: {...}, currentPage: 3 }
  }
]

これにより、Astro は:

  • /tags/travel/page/1/

  • /tags/travel/page/2/

  • /tags/travel/page/3/

という 3つの静的HTMLページを生成してくれるわけです😄

変数 paths とは?

getStaticPaths() では、変数 paths を定義して、最後に return で値を返しています。
ん?この paths はどこで使うんですかい?という人もいるかも知れないのでが、 paths は Astro がビルドする際に参照するデータです。

Astro は getStaticPaths() から return された paths の情報を使って、
「どの URL に対して、どんなデータを渡してページを生成するか」 を判断しています。

たとえば getStaticPaths() が次のように返した場合

return [
  {
    params: { slug: 'travel', page: '1' },
    props: { tag: travelTagObject, currentPage: 1 }
  },
  {
    params: { slug: 'travel', page: '2' },
    props: { tag: travelTagObject, currentPage: 2 }
  }
];

Astro は
🔧 1. ビルド時にそれぞれの params を URL にマッピング

  • params ⇒  生成されるURL

  • { slug: ‘travel’, page: ‘1’ } ⇒  /tags/travel/page/1/

  • { slug: ‘travel’, page: ‘2’ } ⇒  /tags/travel/page/2/

🔧 2. それぞれのページに対して、props の内容を Astro.props 経由で注入

const { tag, currentPage } = Astro.props;

スクリプトのこの箇所で、それぞれのページで違うデータを使ってレンダリングされます。

🔧 3. 最終的に /dist に静的HTMLとして出力

/dist/tags/travel/page/1/index.html
/dist/tags/travel/page/2/index.html

のように、すべてのパターン分のファイルが生成されます😄

html実装

ちょっと長くなっちゃいましたね😅
んで、htmlですが、

"ja">
  
    "UTF-8" />
    {tag.name} の記事一覧 ページ {currentPage}
  
  
    

    {fetchError ? (
      

"color:red;">記事の取得に失敗しました。

) : posts.length === 0 ? (

このページには記事がありません。

) : ( )}

"/tags/">← タグ一覧に戻る

こんな感じになります!
ビルドして試しに
/tags/travel/page/1/
にアクセスしてみると…

バッチリです!
「次のページ」のリンク先に遷移すると

こちらもバッチリです!

おまけ:ページ番号ナビゲーション

ページ番号を表示させたい時は、まずスクリプトの
const { tag, currentPage } = Astro.props;
の下に

const totalPages = Math.ceil(tag.count / 4);

を追加します。
そしてhtmlに

を追加。
そして一番下にcssを

と追加しておきます。
そしてビルドすると

バッチリです!

/pages/tags/[slug]/page/[page].astro
のここまでのソースは下記になります!

---
export async function getStaticPaths() {

const tagRes = await fetch('http://headless.local/wp-json/wp/v2/tags');
const tags = await tagRes.json();

const paths = [];

  
  
  for (const tag of tags) {
    
    const count = tag.count;
    
    const totalPages = Math.ceil(count / 4);

    
    
    for (let page = 1; page // paramsは、URLのパラメータを指定する
        
        
        params: {
          slug: tag.slug,
          page: page.toString(),
        },
        
        
        
        
        props: {
          tag,
          currentPage: page,
        },
      });
    }
  }

  return paths;
}

const { tag, currentPage } = Astro.props;


const totalPages = Math.ceil(tag.count / 4);


const offsetRes = await fetch(`http:

let posts = [];
let fetchError = false;

try {
  if (!offsetRes.ok) throw new Error(`記事取得失敗: ${offsetRes.status}`);
  posts = await offsetRes.json();
} catch (err) {
  console.error("記事取得エラー:", err);
  fetchError = true;
}
---

"ja">
  
    "UTF-8" />
    {tag.name} の記事一覧 ページ {currentPage}
  
  
    

    {fetchError ? (
      

"color:red;">記事の取得に失敗しました。

) : posts.length === 0 ? (

このページには記事がありません。

) : ( )}

"/tags/">← タグ一覧に戻る

それではでは😊



続きをみる


Views: 2

RELATED ARTICLES

返事を書く

あなたのコメントを入力してください。
ここにあなたの名前を入力してください

- Advertisment -

インモビ転職