headless WordPressを利用したNext.jsのプレビューをVercelを使わずに実現する

headless WordPressを利用したNext.jsのプレビューをVercelを使わずに実現する

WordPressをヘッドレスCMSとして利用して、ReactやNext.jsなどでクライアントレンダリングをする際に問題になる点としてプレビューをどのように実現するかということがあります。

Next.jsの公式ではPreview Modeの解説が用意されているのですがAPI Routesを利用しておりVercel以外の環境だと動作が難しいです。

今回はVercel環境以外でプレビューを実現する方法について解説を行います。

アプリケーションパスワード認証とNext.js(App Router)

WordPressのの認証方法はいくつかありますが今回はクッキー認証を前提に解説を進めていきます。クッキー認証はWordPressの管理画面とプレビュー画面のURLが同一である必要でありますので注意してください。

異なるURLでも対応可能なアプリケーションパスワード認証はApp Routerでの表示と合わせて解説しておりますので必要な方はそちらを参考にしてください。。

Next.js(App Router)でWordPressのプレビュー機能を実装する – to-R Media

まずは/preview/index.jsx というプレビュー用のページを作成します。プレビュー用のページではAjaxを利用してWordPressのRest APIよりプレビュー用のデータを取得します。

const Preview = () => {
  if (typeof window === 'undefined') return null

  const router = useRouter()
  const [post, changePost] = useState(null)
  const { id, nonce } = router.query

  useEffect(() => {
    if (!id || !nonce) return
    const post_url =
      'https://www.xxx.yyy/wp-json/wp/v2/posts/' +
      id +
      '?_embed&status=draft'

    axios
      .get(post_url, { headers: { 'X-WP-Nonce': nonce } })
      .then((response) => {
        const article = response.data
        changePost(article)
      })
  }, [id, nonce])

  return post ? <Post post={post} /> : null
}

下書き情報を取得するにはリクエストパラーメーターの最後にstatus=draftを追加する必要があります。またRequest Headerに X-WP-NonceというWordPressが発行する認証用のtoken情報を設定する必要があります。

プレビューと記事ページで共通のコンポーネントを使いませるようにコンポーネント設計は行っておきましょう。

WordPress側では functions.phpに以下のコードを追加して、プレビューリンクが押された際に表示する記事IDとtoken情報を付与して先程作成したプレビュー用のページに遷移するように設定します。

add_action("template_redirect", function () {
  if (!is_admin() && isset($_GET["preview"]) && $_GET["preview"] == true) {
    $redirect = add_query_arg(
      [
        "id" => $_GET["preview_id"] ? $_GET["preview_id"] : $_GET["p"],
        "nonce" => wp_create_nonce( 'wp_rest' )
      ],
      "https://www.xxx.yyy/preview"
    );
    wp_redirect($redirect);
  }
});

これにより、ヘッドレスCMSとしてWordPressを利用した際のNext.jsのプレビューをVercelを使わずに実現することができます。