Next.jsを使用したサイトで記事を外部の人にプレビュー表示させたい

PowerCMS X Advent Calendar 2021」2日目の記事を準備したのですが、公開予約してある記事を外部の人にプレビュー表示してもらいたくなりました。つまり、「Advanced Features: Preview Mode | Next.js」に沿って実装はしてありシークレットトークンもあるけれど、そのトークンは見せたくないし管理画面にもアクセスできないという状況です。

そこで「Preview Tokens」というモデルを作成しました。カラムはtoken(テキスト50・プライマリ)とentry(数値・ダイアログで記事を選択)の2つです。オプションは以下にチェックを入れました。

  • APIを有効化
  • ユーザーをアサイン
  • 自動監査
  • ステータス対応
  • 有効期限対応
  • スペースに表示

自動監査にチェックを入れると誰がオブジェクトを用意したか分かりますし、有効期限対応にすれば指定の期日以降はプレビューさせない、ということが実現できます。

オブジェクトの編集画面ですが、新規作成時はプラグインのtemplate_outputコールバックでトークンを自動生成して入力フィールドに自動挿入するようにしました。
Preview Tokensオブジェクトの編集画面

public function template_output_edit( $cb, &$app, &$param, &$src, &$out ) {
    if ( $app->param('_model') === 'preview_token' ) {
        if ( $app->param('_type') === 'edit' && ! $app->param('id') ) {
            $token = bin2hex( random_bytes( 16 ) );
            $out = str_replace( 'name="token" value=""', "name=\"token\" value=\"$token\"", $out);
        }
    }
}

あとは以前「オブジェクトのプレビュー機能を実装」で紹介したNext.jsのpages/api/preview.jsの変更です。preview_tokenというクエリストリングがある場合はPowerCMS XのAPIを通じてPreview Tokensのオブジェクトを取得し、どの記事を表示すべきかの情報を得ます。Preview Tokensモデルもごく普通のモデルですので、PTRESTfulAPIgetObjectメソッドで取得できます。ただし、getエンドポイントでも認証が必要になるように設定をしてあります。(詳しくは「RESTful API ドキュメント (概説) | PowerCMS X」を参照してください。)

const options = {
  cols: 'entry',
};
const response = await client.getObject('preview_token', req.query.preview_token, 1, options, token);
if (response.status === 200) {
  const previewToken = await response.json();
  previewId = previewToken.entry.id;
} else {
  return res.status(401).json({ message: 'Invalid token' });
}

実装が完了するとhttps://example.com/api/preview?preview_token=abcdef1234のようなURLで外部ユーザーにプレビュー表示させることができるようになります。このように、PowerCMS Xではモデル作成とAPIを利用したフロントエンド実装により、Jamstackのサイトでも独自の機能を実現できます。