WordPressをヘッドレスCMS化するときにfunctions.phpで対応したこと

フロントエンドエンジニアのハコザキです。

今回、コーポレートサイトのリニューアルにあたり
WordPressで構築されたサイトをNuxtでリニューアルすることになりました。

Wappalyzer

技術構成としては以下のような形です。
WordPressをヘッドレスCMSとして使用し、
Nuxtと組み合わせてJamstackなコーポレートサイトになっております。
その他ページ遷移などのアニメーションはGSAPを導入して実装しております。

フロントエンドVue.js/Nuxt
ヘッドレスCMSWordPress
ホスティングサービスAWS Amplify
画像管理AWS S3
コード管理GitHub
コーポレートサイトの技術構成

今回はWordPressをヘッドレスCMSとして利用するにあたり、
WordPress側で対応した以下の対応方法についてご紹介したいと思います!
※ 3つともよく対応する内容です!

  • 前後記事の取得
  • 記事著者の最新記事情報取得
  • ACFで入力した情報の取得

全体の実装についてはこちらの記事を見ていただければと思います!

はじめに

今回は、WordPressを改造してヘッドレスCMSとして利用するのですが、
可能な限り、新たにヘッドレスCMSを利用して構築する方が
全体の作業工数は少なくなると思います。

代表的なヘッドレスCMSサービス

今回はリニューアル前の記事をそのまま再利用し、
今後もWPのブロックエディタで記事を投稿するためにWPを残しました。

WordPressのヘッドレスCMS化

WordPressをヘッドレスCMS化するにあたり、
WP REST APIの利用はほぼ必須です。

WP REST APIについて

WP REST APIは、投稿、ページ、タクソノミ、およびその他のWordPress組み込みデータ型を表すRESTエンドポイント(URL)を提供したものです。

アプリケーションは、これらのエンドポイントにJSONデータを送受信して、
サイトのコンテンツを取得や変更、作成することができます。

https://{WPドメイン}/wp-json/wp/v2/

例えば、カスタム投稿タイプからコンテンツを取得する場合は、
このようなエンドポイントを作成します。

https://{WPドメイン}/wp-json/wp/v2/{カスタム投稿タイプ名}

以下のようなjson形式で返ってきます。

詳しくはこちら

基本的には用意されているリソースを利用してコンテンツの取得などは可能ですが、
追加で対応したことについて一部ご紹介します。

前後記事の取得

お知らせやブログなどの詳細ページで、
前後記事へのリンクを追加する必要がありました。

https://ma-vericks.com/blog/nuxt-study-report/
nuxt-study-report をslugとして、以下のエンドポイントを作成し記事の取得を行います。

# 配列として返ってくることに注意
https://{WPドメイン}/wp-json/wp/v2/blog?_embed&slug=nuxt-study-report

このエンドポイントのレスポンスでは、前後記事の情報は取得できないため
自分でレスポンスを追加して上げる必要があります。

今回はこちらの記事を参考に、
WPの使用テーマのfunctions.phpに以下の記述を行いました。

...

// REST APIのレスポンスの編集
add_action('rest_api_init', function() {

  /**
   * ニュースの前後記事を取得しレスポンスに追加
   */
  // 前
  register_rest_field(
    'news', // 投稿タイプ
    'prev', // レスポンスのフィールド名
    [
      'get_callback' => 'register_prev_post',
      'update_callback' => null,
      'schema' => null,
    ]
  );
  // 次
  register_rest_field(
    'news', // 投稿タイプ
    'next', // レスポンスのフィールド名
    [
      'get_callback' => 'register_next_post',
      'update_callback' => null,
      'schema' => null,
    ]
  );
});


/**
 * 前の記事を取得し、配列生成
 */
function register_prev_post() {
  global $post;
  $prev_post = get_previous_post();
  $result = [];

  if (!$prev_post) {
    return null;
  }

  $result['id'] = $prev_post->ID;
  $result['slug'] = $prev_post->post_name;

  return $result;
}

/**
 * 次の記事を取得し、配列生成
 */
function register_next_post() {
  global $post;
  $next_post = get_next_post();
  $result = [];

  if (!$next_post) {
    return null;
  }

  $result['id'] = $next_post->ID;
  $result['slug'] = $next_post->post_name;

  return $result;
}

記事詳細のレスポンスにprev, nextを追加することができました。

idは伏せてます
前後ない場合はnull

記事著者の最新記事情報取得

ブログ詳細の下部にある、
著者の最新記事一覧は 記事取得のエンドポイントでは取得できません…
こちらも自分でレスポンスを追加してあげる必要があります。

著者の最新記事一覧

先ほどと同様に使用テーマのfunctions.phpに以下の記述を行います。

...

// REST APIのレスポンスの編集
add_action('rest_api_init', function() {

  ...

  // 投稿ユーザーの最新記事一覧(3件)
  register_rest_field(
    'blog', // 投稿タイプ
    'author', // レスポンスのフィールド名
    [
      'get_callback' => 'register_blog_relate_posts',
      'update_callback' => null,
      'schema' => null,
    ]
  );
});


function register_blog_relate_posts() {
  global $post;
  $args = [
    'post_type' => 'blog', // カスタム投稿タイプ
    'author' => get_the_author_meta('ID'), // 表示中の記事の著者ID
    'numberposts' => 3, // 取得件数
    'exclude' => get_the_ID() // 表示中の記事は除外
  ];

  return [
    'posts' => get_posts($args), // 記事一覧情報
    'profile' => get_the_author_meta('description'), // 著者情報
    'nick_name' => get_the_author_meta('nickname'),
    'slug' => get_the_author_meta('user_login'), // 著者のslug
    'profile_img' => wp_get_attachment_image_url(get_the_author_meta('profile_image'),'thumbnail') // 著者の設定中アイコン
  ];
}

author に必要な情報を追加することができました!

ACFで入力した情報の取得

ブログカテゴリーなどのターム情報については?_embed をつけることで取得することができますが、階層が非常に深くなっており、わかりにくいです。
(また、静的出力後なぜかターム情報が取得されていない..などの問題も発生してしまいました..)

今回は親子関係があるタームも存在するため、
ACFを使い、親カテゴリーかどうか判別するチェックボックスを用意します。
また、子カテゴリのソートも行いたいため、 数値を入れることができるようにしました。

続いて使用テーマのfunctions.phpに以下の記述を行います。

...

// REST APIのレスポンスの編集
add_action('rest_api_init', function() {

  ...

  // カテゴリー情報用のフォールドを作成
  register_rest_field(
    'blog', // 投稿タイプ
    'category', // レスポンスのフィールド名
    [
      'get_callback' => 'register_blog_category',
      'update_callback' => null,
      'schema' => null,
    ]
  );
});



/**
 * ブログにカテゴリー情報を追加
 */
function register_blog_category() {
  global $post;
  $terms = get_the_terms($post->ID,'blog_category');

  foreach ($terms as $term) {
    // ACFで設定したチェックボックスの値を返す
    $is_parent = get_field('is_parent', 'blog_category'.'_'.$term->term_id);
    // 設定なしの場合、nullが返ってくるのでfalseに上書き
    $term->is_parent = $is_parent ?: false;
  }
  return $terms;
}

acf にカスタムフィールドで設定した値を返すことができました。