134
102

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

AstroでWordPressを爆速Headless化してみる

Last updated at Posted at 2023-02-14

最近流行りのAstroフレームワークで、WordPressの静的Headless化がかなりお手軽にできたのでまとめてみました。

開発環境

Astroとは?

Astroは、コンテンツにフォーカスした高速なWebサイトを構築するためのオールインワンWebフレームワークです。

(公式ドキュメントより)

LocalでWordPressを構築

まずLocalを使って、ローカル環境にWordPressを構築します。
local.png

サイト名
Astro Blog(お好みで)
サイトドメイン
astro-blog.local

WordPressの設定

WP AdminでWordPressのダッシュボードを立ち上げ、いくつかの設定を行います。
wp-setting1.png

サイトアドレスを、Astro上の構造に合わせてサブディレクトリを足します(Astroでもサイト直下に展開する場合は、WordPressアドレスと同じでかまいません)。
ここでは、/blogを追加しました。

その他の設定は、通常のWordPressと同じくお好みで。

WordPressテーマを適用

最終的にフロントエンド側はAstroで構築するので、テーマはなんでも良いのですが、スタイリングしやすい文書構造だったり、機能的なブロックエディタを持つテーマを選択すると良いと思います。

ここでは、シンプルで使いやすい「Arkhe」テーマをインストールして適用しました。

テーマをインストールしたら、テスト用にいくつか記事を作成して公開しておきます。
wp-page.png

公開するときのURLパーマリンクが、AstroでHeadless化したときのファイル名になるため、英数字で構成しておきましょう。
wp-url.png

ひとまずWordPress側は一旦完了です。Localを起動したまま、Astroの構築に移ります。

Astroをインストールする

Astroは日本語のドキュメントが充実しているので、迷ったらドキュメントを見ましょう。

まず、Localで構築したWordPressブログのフォルダー(以下astro-blog)にアクセスできるようにします。
(Localのメニュー[Go to site folder]でフォルダーが開きます)
wp-folder.png

Macの場合、

[ユーザー] > Local Sites > [構築したWordPressのフォルダー]

にあります。

次に、ターミナルを開き、「astro-blog」に移動し、以下のコマンドでAstroをインストールします。

npm create astro@latest

いくつか質問されるので、以下を参考に入力・選択してください。

Where should we create your new project?

Astroがインストールされるフォルダ名を入力します(後述しますが、最終的にフォルダから外に出すのでなんでも良いです)。astroと入力します。

How would you like to start your new project?

Astroに慣れている人ならどれでも良いですが、ここではInclude sample filesを選択します。

Install dependencies?

お好みで。

Initialize a new git repository?

gitを使うかどうか。お好みで。

Do you plan to write TypeScript?

TypeScriptを使うかどうか。お好みで。

How strict should TypeScript be?

お好みで。

問題なければ、「astro」フォルダーの中にAstro一式が展開されていると思います。

astro-blog/
├── app
├── astro
│    ├── astro.config.mjs
│    ├── node_modules
│    ├── package.json
│    ├── public
│    ├── README.md
│    ├── src
│    └── tsconfig.json
├── conf
└── logs

次に、せっかく「astro」フォルダーにまとまっていますが、中のファイルを全て選択し、「astro-blog」直下に移動して、「astro」フォルダーは削除します。
(AstroからWordPress関連のファイルにアクセスするため)

astro-blog/
├── app
├── astro.config.mjs
├── conf
├── logs
├── node_modules
├── package.json
├── public
├── README.md
├── src
└── tsconfig.json

ここからVisual Studio Codeでコーディングしていきます。
事前にAstroプラグインをインストールしておきましょう。

エディタを立ち上げて、「astro-blog」を開き、

npm run dev

を実行して、Astroのサンプルページが立ち上がることを確認しましょう。
astro-dev.png

AstroとWordPressをつなげる

一旦npm run devを停止し、「astro-blog」直下に.envファイルを作成し、以下のようにWordPress Rest APIのURLを記述しておきます。

PUBLIC_API_URL = http://astro-blog.local/wp-json/wp/v2/

http://astro-blog.localの部分は、Localで作成したWordPressのURLになります)

次に、src/pages/index.astroを開き、コードをいくつか追加します。

---
import Layout from '../layouts/Layout.astro'
import Card from '../components/Card.astro'


+ const res = await fetch(`${import.meta.env.PUBLIC_API_URL}posts`);
+ const posts = await res.json();
---

<Layout title="Welcome to Astro.">
  <main>
    <h1>Welcome to <span class="text-gradient">Astro</span></h1>
+   {
+     posts.map((post:any) => (
+       <p><a href={`/blog/${post.slug}`} set:html={post.title.rendered} /></p>
+     ))
+   }
    <p class="instructions">
      To get started, open the directory <code>src/pages</code> in your project.<br />
      <strong>Code Challenge:</strong> Tweak the "Welcome to Astro" message above.
    </p>
// 以下略

再びnpm run devを実行すると、先ほどのAstroのサンプルページにWordPressで作成したページのタイトルがリンクとして追加されていると思います。
astro-dev2.png

このままだとまだリンク先が存在しないので、各ページを構築していきます。

src/pages/blog/[slug].astroファイルを作成します。

src/
├─ pages
│   ├── blog
│   │     └─ [slug].astro
│   └─ index.astro

[slug].astroファイルに以下の記述をします。

---
import Layout from '../../layouts/Layout.astro'

const { slug } = Astro.params;
const res = await fetch(`${import.meta.env.PUBLIC_API_URL}posts?_embed&slug=${slug}`);
const [post] = await res.json();
const renderedContent = post.content.rendered;

export async function getStaticPaths() {
  const data = await fetch(`${import.meta.env.PUBLIC_API_URL}posts`);
  const posts = await data.json();

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

<Layout title={post.title.rendered}>
  <a href="/">Astro Blog</a>
  <h1 set:html={post.title.rendered} />
  <Fragment set:html={renderedContent} />
</Layout>

ちなみにこのへんの情報もすべて公式ドキュメントにも載っています。

[slug].astroのコードを記述したら、先ほどのトップページのリンクから各ページにアクセスしてみましょう。
astro-page.png

WordPressで作成したページがAstroの静的HTMLとして構築されています。
しかし、WordPressから持ってきたのはHTML構造だけなので、Astroで少しスタイリングを行います。

Astroでページをスタイリングする

今回WordPressには、「Arkhe」テーマを適用しているので、このテーマを活かしたスタイリングを行います。

---
import Layout from '../../layouts/Layout.astro'
+ import '../../../app/public/wp-includes/css/dist/block-library/style.min.css'
+ import '../../../app/public/wp-content/themes/arkhe/dist/css/main.css'

const { slug } = Astro.params;
const res = await fetch(`${import.meta.env.PUBLIC_API_URL}posts?_embed&slug=${slug}`);
const [post] = await res.json();
const renderedContent = post.content.rendered;

export async function getStaticPaths() {
  const data = await fetch(`${import.meta.env.PUBLIC_API_URL}posts`)
  const posts = await data.json();

  return posts.map((post:any) => ({
    params: { slug: post.slug },
    props: { post: post },
  }));
}
---
<Layout title={post.title.rendered}>
+  <div class="l-content__body l-container">
+    <a href="/">Astro Blog</a>
+
+    <main class="l-main">
+      <article class="l-main__body">
+        <h1 class="c-pageTitle__main" set:html={post.title.rendered} />
+        <div class="c-postContent">
+          <Fragment set:html={renderedContent} />
+        </div>
+      </article>
+    </main>
+  </div>
</Layout>

Local内にあるWordPressのblock-libraryのCSSと、「Arkhe」テーマのメインCSSを直接importしています。
これによって、WordPress側でテーマのアップデートによってCSSの変更があった場合も、Astro側に自動的に適用されます。

そして、<Layout title={post.title.rendered}>内の文書構造を、「Arkhe」テーマで生成される文書構造と合わせます(最小限のclassのみ)。

ここまで変更したら、もう一度devでビルドされたページを見ると、
astro-page2.png

ほぼWordPress上と同じような見た目にスタイリングできました。
(実際はインラインで生成されるstyleなどもあるため、WordPress上とは異なる場合もあります)

Localのリンクを修正する

あともう少しだけ修正です。

見た目はほぼ再現できているように見えますが、ページ上の画像はLocalで生成された絶対パスのままになっています。
(例:http://astro-blog.local/wp-content/uploads/2023/02/hoge.png)

このままだとHeadless化で公開できないので、すべての画像をWordPressからAstro側にコピーすることにします。
手動でやるととても面倒なので、NPMスクリプトに任せましょう。

事前準備として、fs-extraをインストールしておきます。

npm install fs-extra

fs-extraをインストールしたら、package.jsonに、WordPressでアップロードした画像が入っているフォルダーを、Astroのpublicフォルダーにコピーするスクリプトを追加します。

"scripts": {
+ "copy": "node -e \"require('fs-extra').copySync('./app/public/wp-content/uploads', './public/wp-content/uploads')\"",
  "dev": "astro dev",
  "start": "astro dev",
  "build": "astro build",
  "preview": "astro preview",
  "astro": "astro"
},

これで、

npm run copy

を実行すると、WordPressの画像フォルダーがAstro用にコピーされます。
ついでに、devとbuildしたときに最初にcopyが実行されるようにしておきます。

"scripts": {
  "copy": "node -e \"require('fs-extra').copySync('./app/public/wp-content/uploads', './public/wp-content/uploads')\"",
  "dev": "npm run copy && astro dev",
  "build": "npm run copy && astro build",
  "preview": "astro preview",
  "astro": "astro"
},

最後に、[slug].astroファイルで、WordPressのコンテンツを流し込むときに、正規表現ですべてのhttp://astro-blog.localを置換(削除)して、絶対パスをルートパスに変更します。

const renderedContent = post.content.rendered.replace(/http:\/\/astro-blog.local/g, '');

これにより、

src="http://astro-blog.local/wp-content/uploads/2023/02/hoge.jpeg"

みたいなコードが

src="/wp-content/uploads/2023/02/hoge.jpeg"

に置き換わります。
(サイト内リンクのhrefなども同様)

最後に、

npm run build

をすると、distフォルダーに静的HTMLファイル一式が出力されるので、サーバーにアップロードすれば完成です。

最終的にはCSSやJSに諸々の調整が必要だと思いますが、このように、Astroフレームワークを使うことで、ローカル環境だけでWordPressの静的Headless化がお手軽に行えるので、試してみてください。

おしまい。

134
102
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
134
102

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?