WordPressをヘッドレスCMSとして利用して、ReactやNext.jsなどでクライアントレンダリングをする際に問題になる点としてプレビューをどのように実現するかということがあります。
Next.jsの公式ではPreview Modeの解説が用意されているのですがAPI Routesを利用しておりVercel以外の環境だと動作が難しいです。
今回はVercel環境以外でプレビューを実現する方法について解説を行います。
まずは/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を使わずに実現することができます。