AstroサイトをWP Rest APIでCMS化

⚠この記事が公開されたのは 2023年7月9日で、内容が古く、間違っている可能性があります。

きっかけ

Astroで静的サイトを制作したがブログのような記事(コンテンツ)の更新でmdファイルを更新するのは、一般ユーザーにはハードルが高いと感じた。
netlifyなどのCMSも検討したが、国内ユーザーはWordpressの管理画面に慣れ親しんでおり、フロントは静的化してもコンテンツはこれまでどおりWordpressを使用したいというケースもあると考えたため。

前提

Astroで静的サイトを構築済み、Github Actionsを使用してPushをトリガーに手動でビルド&デプロイできる状態

必要なもの

  • Astroで制作した静的サイト
  • ヘッドレスCMSとして運用するWordpressサイト
  • Githubリポジトリ(公開/プライベート問わず)

手順

WordPressをヘッドレスCMS化

管理画面にログインし、メニューの「設定」-「表示設定」を選択

1ページに表示する最大投稿数: 1~100(APIの仕様は最大100件までです)

検索エンジンでの表示: 「検索エンジンがサイトをインデックスしないようにする」にチェック(ローカルや非公開の開発環境であれば不要)

メニューの「ユーザー」のプロフィールを選択

新しいアプリケーションパスワード名:任意

新しいアプリケーションパスワードを追加ボタンを押す

表示されるアプリケーションパスワードをコピーしておく

ヘッドレスCMS化用のオリジナルテーマを作成する

テーマに必要最低限ファイルをテーマフォルダ(フォルダ名は任意)内に作成

sytle.css
/*
Theme Name: headlesswp
Author: bytedesign
Version: 1.0
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: headlesswp
*/
/* 内容は不要 */
index.php
<?php
/* 内容は不要 */
functions.php
<?php
function read_enqueue_styles() {
  wp_enqueue_style( 'main-style', get_stylesheet_uri() );
}

/* アイキャッチを使用する場合は追加 */
add_action( 'wp_enqueue_scripts', 'read_enqueue_styles' );
add_theme_support('post-thumbnails');

/* WP Rest APIで使わないエンドポイントは無効にしておく 以下は投稿ページ一覧と単一の投稿ページのみ取得する例 */
function filter_rest_endpoints( $endpoints ) {
    /* 投稿ページ一覧 */
    /*
    if (isset($endpoints['/wp/v2/posts'])) {
        unset($endpoints['/wp/v2/posts']);
    }
    */
    /* 単一の投稿ページ */
    /*
    if ( isset( $endpoints['/wp/v2/posts/(?P<id>[\d]+)'] ) ) {
      unset( $endpoints['/wp/v2/posts/(?P<id>[\d]+)'] );
    }
    */
    /* 固定ページ一覧 */
    if (isset($endpoints['/wp/v2/pages'])) {
      unset($endpoints['/wp/v2/pages']);
    }
    /* 単一の固定ページ */
    if (isset($endpoints['/wp/v2/pages/(?P<id>[\d]+)'])) {
      unset($endpoints['/wp/v2/pages/(?P<id>[\d]+)']);
    }
    /* ユーザー情報 */
    if ( isset( $endpoints['/wp/v2/users'] ) ) {
        unset( $endpoints['/wp/v2/users'] );
    }
    if ( isset( $endpoints['/wp/v2/users/(?P<id>[\d]+)'] ) ) {
        unset( $endpoints['/wp/v2/users/(?P<id>[\d]+)'] );
    }
    return $endpoints;
}
add_filter( 'rest_endpoints', 'filter_rest_endpoints', 10, 1 );

/* カスタムフィールドを使用する場合は追加 */
add_action( 'rest_api_init', 'create_api_posts_meta_field' ); //REST API の初期化フック
function create_api_posts_meta_field() 
{
 	register_rest_field( 
		'post', //投稿タイプ
		'customfield', //任意のキー名
		array(
 			'get_callback' => 'get_post_meta_for_api',
			'update_callback' => 'update_post_meta_for_api',
 			'schema' => null,
 		)
 	);
}

参考: WP REST API から記事やユーザー情報を取得できないようにする | WordPressカスタマイズ事例【100ウェブ】 (100webdesign.jp)

テーマを有効にし、ブラウザでhttps://example.com/wp-json/wp/v2/postsにアクセスし、jsonファイルにアクセスし、投稿ページの情報が見れるか確認(https://example.comはWordpressサイトのドメイン)

Astroサイト

投稿一覧を表示するテンプレートのastroファイルで以下を参考に編集する

src/pages/***.astro(任意のページ)

---
const res = await fetch("https://example.com/wp-json/wp/v2/posts?_embed", {
  headers: {
    Authorization: `Basic ${window.btoa(
      "ユーザー名:コピーしたアプリケーションキー"
    )}`,
  },
});
//example.comの部分はWP Rest APIを設定したサイトのドメイン。アイキャッチが不要であればhttps://example.com/wp-json/wp/v2/postsでOK

const projects = await res.json();
import { getCollection } from "astro:content";
import { Image, Picture } from "@astrojs/image/components";
---
{
projects.map(project => (
<li>
<!-- 記事タイトル -->
<h2 set:html={project.title.rendered} />
<!-- 記事本文 -->
<div set:html={project.content.rendered} />
<!-- アイキャッチ(AstroのImageコンポーネントを使用した例) -->
<Image
src={
project._embedded["wp:featuredmedia"][0].media_details
.sizes.full.source_url
}
width={500}
aspectRatio={1 / 1}
format="webp"
quality={100}
loading="lazy"
decoding="async"
alt=""
/>
</li>
))
}

src/pages/posts/[id].astro

---
export async function getStaticPaths() {
let data = await fetch(
"https://example.com/wp-json/wp/v2/posts?_embed&page=1&per_page=100"
);
let posts = await data.json();

return posts.map(post => ({
params: { id: post.id },
props: { post: post },
}));
}
---

参考: Astro.jsとWP REST APIを使ったブログの作成 | CodeCode (codecodeweb.com)

記事の反映を確認

> npm run dev

または

> npm run build

確認し問題なければビルドを行う

手動でビルドするのが面倒な場合は自動でビルドする記事もご覧ください