0

%

Knowledge

【WordPressヘッドレス化】Vercelでプレビュー機能を作ってみた

コーディング

こんにちは!アルテガエンジニアのHarukichiです。

最近、弊社のコーポレートサイトをWordPressヘッドレス化 x Astroでリニューアルしました。
その時に右往左往したことをシリーズに分けてアウトプットしています。

今回は、VercelでWordPressの投稿プレビュー機能を作ってみたお話です。

経緯

実現したかったこと
ヘッドレス化してもWordPressの投稿プレビュー機能が使いたい
プレビューを他者にシェアできるように公開URLが欲しい

WordPress管理画面のプレビューはあくまでPHPテンプレート向けのため、Astroでは表示することができません。

弊社の旧WordPressサイトではプレビュー機能が効かず、社内で投稿前の確認がとても大変だったこともあり、新しいAstroサイトではどうしてもプレビュー機能を作りたかったです。

使用するサービス

WordPressのヘッドレス化をした弊サイトですが、メールサーバーの移管などの問題を避けるために、生成されたAstroの静的サイトはXサーバーに置いています。

AstroのSSRの機能を簡単に使うために、プレビュー機能の部分だけVercelを使用することにしました。

  • Astroの静的サイト: Xサーバー
  • WPのプレビュー機能: Vercel

WordPress側の準備

※WPGraphQLプラグインが入っていることが前提です。

Application Passwordの発行

後の認証付きfetchで使用するために、アプリケーションパスワードを発行します。
ユーザー > プロフィール > アプリケーションパスワードから行えます。

プレビューボタンのリンク先をVercelに変更する

functions.phpに追記します。今回は、通常のpostとカスタム投稿(case)に設定しました。


//knowledge, Caseのプレビューリンクを変更
add_filter('preview_post_link', function ($preview_link, $post) {
  $post_id = $post->ID;

  switch ($post->post_type) {
    case 'post':
      return "https://vercelのURL.vercel.app/knowledge/preview/?p={$post_id}&preview=true";

    case 'case':
      return "https://vercelのURL.vercel.app/case/preview/?p={$post_id}&preview=true";

    default:
      return $preview_link;
  }
}, 10, 2);

AstroのSSRルート作成

SSRを有効にし、プレビュー専用のページを表示できるようにします。

Vercelアダプタ

Astroが保守してくれているVercelのアダプタがあるのでインストールします。

npx astro add vercel

今回はpreviewという名前で新しいブランチを切り、その中でastro.config.mjsに追記することでSSRが機能するように設定しました。
(のちにこのブランチとVercelを繋ぐと更新が楽でした。)


//astro.config.mjs
import vercel from '@astrojs/vercel/serverless';
export default defineConfig({
  adapter: vercel(), //SSR
});

プレビュー用のSSRページの作成

プレビュー用に blog/preview/index.astroを作り、このページだけSSRにします。
Astroにはオンデマンドレンダリングという機能があります。
これは、指定したページだけSSRを有効にするものです。

https://docs.astro.build/ja/guides/on-demand-rendering/

prerender変数をfalseにすることで実現できました。
他のページはSSGのまま使用することができます。便利!


//blog/preview/index.astro
---
export const prerender = false;

import { getPostPreview } from '@/libs/getBlogPostPreview';
const url = new URL(Astro.request.url);
const postId = url.searchParams.get('p');
const isPreview = url.searchParams.get('preview') === 'true';

let post = null;
if (postId && isPreview) {
  post = await getPostPreview(postId);
}
---

//以下、省略(記事詳細のマークアップ)

VercelアカウントをGitHubと繋げる

ざっくり手順

1. Vercelに会員登録&ログインします。

https://vercel.com/

2. GitHubアカウントの連携を設定。

3. Add New…ボタンからProjectを選び、該当のGitHubリポジトリを選択して紐付けます。

Vercel側のブランチ設定

VercelにはProduction環境/Preview環境(正確にはローカルデプロイで使えるDevelopment環境もある)があり、それぞれ段階にあった運用をすることができます。
しかし、今回はPreview環境は使わず、Production環境のみで運用しました。
単純にPreview環境は使う理由がなかったのと、二重に自動デプロイが走るのを防ぐためです。

■方法
Production環境にはmainブランチを設定せず、GitHubで用意したpreviewブランチを設定します。
さらに、Preview環境の「Branch Tracking」は OFFにしておくことで、
GitHubにpushしたときにProduction環境のみに自動デプロイされるようになります。

認証付きfetchのjs

先ほど設定したWordPressのApplication Passwordを用いた Basic認証付きfetchのコードを用意します。
プレビュー記事の取得をします。


export async function getPostPreview(postId) {
  const WP_GRAPHQL_ENDPOINT = 'https://yoursite-endpoint/graphql';

  const PREVIEW_QUERY = `
    query GetPostPreview($id: ID!) {
      post(id: $id, idType: DATABASE_ID, asPreview: true) {
        title
        content(format: RENDERED)
        date
        status
        slug
        featuredImage {
          node {
            sourceUrl
          }
        }
      }
    }
  `;

  const authString = Buffer.from(`${process.env.WP_USER}:${process.env.WP_APP_PASSWORD}`).toString('base64');

  const res = await fetch(WP_GRAPHQL_ENDPOINT, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      Authorization: `Basic ${authString}`,
    },
    body: JSON.stringify({
      query: PREVIEW_QUERY,
      variables: { id: postId },
    }),
  });

  const json = await res.json();
  return json.data?.post;
}

asPreview: trueを指定することで、公開前の下書きや更新中のプレビュー記事も取得できます。

  query GetPostPreview($id: ID!) {
      post(id: $id, idType: DATABASE_ID, asPreview: true) {
        ...
      }
    }

WordPressの「ユーザー名」と「アプリケーションパスワード」を使ってBasic認証用の文字列を生成しています。

 const authString = Buffer.from(`${process.env.WP_USER}:${process.env.WP_APP_PASSWORD}`).toString('base64');

認証ヘッダーでWordPressにログインし、プレビュー用の記事データを取得します。


const res = await fetch(WP_GRAPHQL_ENDPOINT, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      Authorization: `Basic ${authString}`,
    },
    body: JSON.stringify({
      query: PREVIEW_QUERY,
      variables: { id: postId },
    }),
  });

noindexの設定

今回Vercelではproduction環境しか使っていないので、production環境の場合はnoindexのrobotsタグを追加するようにしました。

{import.meta.env.VERCEL_ENV === 'production' && <meta name="robots" content="noindex, nofollow">}

まとめ

以上、簡単ではありますが自作したプレビュー機能の概要でした。
WordPressの管理画面からいつものようにプレビューボタンを押すと、Vercelのプレビューが表示できるようになります。
弊社内では、現在便利に運用することができています。

※AstroやVercelで公式の情報がないため、ご利用の際は自己責任でお願いいたします🙇‍♀️