2026年10月16日

2026年10月16日

WordPressとAstroでサイトを作る方法:REST APIで記事を表示する基本構成

Astro は、ビルド時に HTML を生成する静的サイトを得意とする JavaScript のフレームワークです。WordPress と組み合わせる場合、Astro を WordPress のテーマとして wp-content/themes に置くのではなく、WordPress を記事の管理だけに使い(ヘッドレス CMS)、Astro のサイトが WordPress の REST API から記事を読み込んでページを作る、という構成になります。

この記事では、Astro のプロジェクトを作り、WordPress の記事一覧と記事ページを静的に生成して公開するまでの基本の手順を説明します。

この構成の仕組みと向き・不向き

役割は次のように分かれます。

役割 担当 内容
記事の作成・管理 WordPress 管理画面で記事を書き、REST API で記事を返す
ページの生成 Astro ビルド時に REST API から記事を取得し、HTML を書き出す
配信 静的ホスティング Astro が書き出した HTML・CSS・画像を配信する

訪問者が見るのは Astro が書き出した静的なファイルなので、表示は軽く、WordPress 本体を公開サーバーに置かない構成も取れます。

その代わり、次の点が WordPress のテーマで作るサイトと変わります。

  • 記事を公開・更新しても、Astro のサイトをビルドし直すまで表示は変わらない
  • WordPress のテーマ、ウィジェット、テーマの見た目を変えるプラグインは使われない。デザインは Astro 側で作る
  • コメント、問い合わせフォーム、サイト内検索など、サーバーで処理する機能は別の方法で用意する必要がある

更新が1日に数回程度のブログやコーポレートサイトに向いています。会員ごとに表示が変わるサイトや、数分おきに更新するサイトには、WordPress のテーマのままか、Astro でサーバー側描画を使う構成のほうが合います。

WordPress側の準備

REST API で記事を取得できるか確認します。ブラウザで次の URL を開き、JSON が表示されれば準備はできています(cms.example.com は自分の WordPress のドメインに置き換えます)。

https://cms.example.com/wp-json/wp/v2/posts?_fields=id,slug,title

表示されない場合は、次の点を確認します。

  • 管理画面の「設定」→「パーマリンク」が「基本」になっていると、/wp-json/ の URL は使えません。「投稿名」など別の形式にします。
  • セキュリティ系のプラグインやサーバーの設定で REST API を止めていないか確認します。

あわせて、投稿のスラッグは英数字とハイフンで付ける運用にしておきます。日本語のスラッグは REST API で URL エンコードされた文字列として返るため、Astro 側のページの URL が読みにくくなります。

Astroのプロジェクトを作る

Node.js をインストールした環境で、次のコマンドを実行します。対応する Node.js のバージョンは Astro の公式インストールガイドで確認してください。

npm create astro@latest -- --template minimal

質問に答えるとプロジェクトのフォルダーができます。作成したフォルダーに移動し、開発サーバーを起動します。

cd プロジェクト名
npm run dev

ターミナルに表示される URL(既定では http://localhost:4321/)を開くと、Astro の初期ページが表示されます。

続いて、プロジェクトの直下に .env ファイルを作り、WordPress の URL を書きます。

WP_URL=https://cms.example.com

PUBLIC_ で始まらない環境変数は、ビルド時のサーバー側の処理だけで読み込まれ、ブラウザに送られる JavaScript には含まれません。

記事を取得する関数を作る

src/lib/wp.ts を作り、記事を取得する処理をまとめます。

// src/lib/wp.ts
const WP_URL = import.meta.env.WP_URL;

export type WPPost = {
  id: number;
  slug: string;
  date: string;
  title: { rendered: string };
  excerpt: { rendered: string };
  content: { rendered: string };
};

export async function getPosts(): Promise<WPPost[]> {
  const res = await fetch(
    `${WP_URL}/wp-json/wp/v2/posts?per_page=100&_fields=id,slug,date,title,excerpt,content`
  );
  if (!res.ok) {
    throw new Error(`WordPress API error: ${res.status}`);
  }
  return res.json();
}

_fields で必要な項目だけを指定すると、レスポンスが小さくなります。per_page の上限は100なので、記事が100件を超える場合は、レスポンスヘッダー X-WP-TotalPages を見ながら page を増やして全件を取得します(全件取得の書き方は関連記事で説明しています)。

取得に失敗したときに例外を投げているのは、WordPress に接続できないときに記事が0件のサイトをビルドして公開してしまうのを防ぐためです。

記事一覧ページを作る

src/pages/index.astro を次の内容に書き換えます。

---
// src/pages/index.astro
import { getPosts } from '../lib/wp';

const posts = await getPosts();
---
<html lang="ja">
  <head>
    <meta charset="utf-8" />
    <title>ブログ</title>
  </head>
  <body>
    <h1>記事一覧</h1>
    <ul>
      {posts.map((post) => (
        <li>
          <a href={`/blog/${post.slug}/`} set:html={post.title.rendered} />
        </li>
      ))}
    </ul>
  </body>
</html>

WordPress の題名は &#8217; のような文字参照を含むことがあるため、set:html で HTML として出力しています。

記事ページを作る

記事ごとのページは、src/pages/blog/[slug].astro に getStaticPaths() を書いて生成します。静的サイトとしてビルドする場合、動的なルートにはこの関数が必要です。

---
// src/pages/blog/[slug].astro
import { getPosts } from '../../lib/wp';

export async function getStaticPaths() {
  const posts = await getPosts();
  return posts.map((post) => ({
    params: { slug: post.slug },
    props: { post },
  }));
}

const { post } = Astro.props;
---
<html lang="ja">
  <head>
    <meta charset="utf-8" />
    <title set:html={post.title.rendered} />
  </head>
  <body>
    <article>
      <h1 set:html={post.title.rendered} />
      <time datetime={post.date}>{new Date(post.date).toLocaleDateString('ja-JP')}</time>
      <Fragment set:html={post.content.rendered} />
    </article>
    <p><a href="/">記事一覧へ戻る</a></p>
  </body>
</html>

set:html は HTML をエスケープせずに挿入します。WordPress の本文は HTML なのでこの方法で表示しますが、記事を投稿できるのが信頼できるユーザーだけであることを確認してください。

開発サーバーで一覧のリンクをたどり、記事ページが表示されれば取得の設定は完了です。

ビルドして公開する

次のコマンドで静的ファイルを書き出します。既定では dist フォルダーに出力されます。

npm run build
npm run preview

npm run preview で、書き出したファイルを手元で確認できます。問題がなければ dist フォルダーの中身を静的ホスティング(Netlify、Cloudflare Pages、GitHub Pages など)で公開します。多くのホスティングは Git のリポジトリと連携でき、ビルドコマンドに npm run build、公開するフォルダーに dist を指定すれば、push のたびにビルドされます。その場合は .env をリポジトリに含めず、ホスティングの管理画面で環境変数 WP_URL を設定します。

運用で気をつけること

記事の更新とビルド:WordPress で記事を公開しても、ビルドし直すまでサイトには反映されません。ホスティングのデプロイフック(特定の URL に POST するとビルドが始まる機能)を、WordPress の記事公開時に呼ぶ仕組みを作ると自動化できます。

下書きとプレビュー:REST API で認証なしに取得できるのは公開済みの記事だけです。WordPress のプレビューボタンは WordPress のテーマで表示する仕組みなので、Astro での見た目は公開前には確認できません。

ブロックの見た目:本文の HTML にはブロックエディターのクラス名が付いていますが、そのスタイルは Astro 側にはありません。使っているブロックのスタイルを Astro 側の CSS で用意します。

プラグインの機能:ショートコードは展開済みの HTML として content.rendered に入りますが、プラグインが読み込む CSS や JavaScript は付いてきません。フォームやコメントは外部のサービスか Astro 側の実装に置き換えます。

画像:本文中の画像は WordPress のメディアの URL のまま表示されます。WordPress を非公開にする場合は、画像の配信方法も決めておく必要があります。

まとめ

  • Astro は WordPress のテーマではなく、REST API から記事を読み込んでページを作る別のサイトとして構成する
  • WordPress 側はパーマリンクを「基本」以外にし、/wp-json/wp/v2/posts が JSON を返すことを確認する
  • 記事の取得処理をまとめ、取得に失敗したときはビルドを止める
  • 記事ページは getStaticPaths() で生成し、本文は set:html で出力する
  • 記事を更新したらビルドし直す必要があり、プレビュー、ブロックのスタイル、フォームなどの扱いを事前に決めておく

お気軽にご相談ください

お見積りへ お問い合わせへ
▲