WP REST APIをシングルページアプリケーションで使うためにいろいろカスタマイズしてみた

WP REST APIをシングルページアプリケーションで使うためにいろいろカスタマイズしてみた

いなば

いなば

先日、「他のフレームワークとの比較 – Vue.js」を読んでVue.jsを触ってみたくなった、フロントエンドエンジニアのいなばです。

なにかいい遊び場所がないか探していたら、WordPressで実装されたLIGの制作実績サイトがあったので、WP REST APIを使ってVue.jsで遊んでみることにしました。

WP REST APIとは
WordPress4.7でプラグインからWordPressのコアに組み込まれた機能でエンドポイントから記事やタグ、カテゴリなどのデータをjsonで取得することができます。

 

記事一覧の取得

さっそく記事一覧を /wp-json/wp/v2/posts から取得してみます。 長いのでほぼ省略しましたが、こんなJSONを取得することができました。

[
    {
        "id": 1531,
        "date": "2017-04-26T16:50:56",
        "date_gmt": "2017-04-26T07:50:56",
        "guid": {
            "rendered": "http://creative.liginc.co.jp/?p=1531"
        },
        "modified": "2017-05-16T16:26:47",
        "modified_gmt": "2017-05-16T07:26:47",
        "slug": "funplex",
        "status": "publish",
        "type": "post",
        "link": "http://localhost/1531",
        "title": {
            "rendered": "funplex"
        },
        "content": {
            "rendered": "",
            "protected": false
        },
        "excerpt": {
            "rendered": "",
            "protected": false
        },
        "author": 3,
        "featured_media": 1542,
        "comment_status": "open",
        "ping_status": "open",
        "sticky": false,
        "template": "",
        "format": "standard",
        "meta": [],
        "categories": [
            3
        ],
        "tags": [
            8,
            9
        ],
        "_links": {
            // 省略
        }
    },
    // 省略
]

LIGの制作実績サイトでは、記事の一覧にはタイトルとサムネイル、クライアント名とキャッチコピー(ホバーした時に出てくる)の4つがあればよさそうです。上記のJSONだと、ほしいものがタイトルしか入っていませんね。

記事のアイキャッチの取得

WP REST APIをそのままで使うと、記事一覧のJSON(/wp-json/wp/v2/posts)の中にアイキャッチ画像が含まれていません。

/wp-json/wp/v2/posts?_embed のように、_embed パラメータを付与する方法でも記事にアイキャッチ画像を含めることができますが、余計なデータが増えるのが嫌だったのと、構造が深く使いづらそうだったので、今回はアクションフックでアイキャッチ画像を追加する方法を採用しました。

functions.phpに下記のコードを追加することで、記事にアイキャッチ画像を追加することができます。 クライアント側の都合で画像のサイズも欲しかったので、widthとheightも一緒に返すようにしています。

add_action('rest_api_init', 'lig_wp_add_thumbnail_to_JSON');
function lig_wp_add_thumbnail_to_JSON() {
//Add featured image
  register_rest_field('post',
    'featured_image', //NAME OF THE NEW FIELD TO BE ADDED - you can call this anything
    array(
      'get_callback' => 'lig_wp_get_image',
      'update_callback' => null,
      'schema' => null,
    )
  );
}

function lig_wp_get_image($object, $field_name, $request) {
  $feat_img_array = wp_get_attachment_image_src($object['featured_media'], 'large', true);
  return [
    'src' => $feat_img_array[0],
    'width' => $feat_img_array[1],
    'height' => $feat_img_array[2],
  ];
}

 

再度記事一覧を取得すると、追加したアイキャッチ画像のデータを取得できることが確認できました。

[
    {
        "id": 1531,
        "date": "2017-04-26T16:50:56",
        "date_gmt": "2017-04-26T07:50:56",
        "guid": {
            "rendered": "http://creative.liginc.co.jp/?p=1531"
        },
        "modified": "2017-05-16T16:26:47",
        "modified_gmt": "2017-05-16T07:26:47",
        "slug": "funplex",
        // 省略
        "featured_image": {
            "src": "https://s3-ap-northeast-1.amazonaws.com/production.lig-portfolio/wp-content/uploads/2017/04/16162503/funplex-eye-1776-11861-888x593.png",
            "width": 888,
            "height": 593
        },
        // 省略
    },
    // 省略
]

Advanced Custom Fieldsで追加された情報の取得

クライアント名とキャッチコピーはAdvanced Custom Fieldsで追加されたものなので、こちらもWP REST APIをそのまま使うと取得することができません。 こちらはとても簡単で ACF to REST API というプラグインを導入するだけで解決します。

プラグインをインストールして有効化したあと、再度記事一覧を取得すると、 acf というkeyが追加されているのが確認できました。

[
    {
        "id": 1531,
        "date": "2017-04-26T16:50:56",
        "date_gmt": "2017-04-26T07:50:56",
        "guid": {
            "rendered": "http://creative.liginc.co.jp/?p=1531"
        },
        "modified": "2017-05-16T16:26:47",
        "modified_gmt": "2017-05-16T07:26:47",
        "slug": "funplex",
        // 省略
        "featured_image": {
            // 省略
        },
        "acf": {
            "client": "ファンプレックス株式会社",
            "copy": "CHANGE  THE  GAME",
            // そこそこ長かったので省略
        },
    },
    // 省略
]

記事詳細の取得

続いて、記事詳細を /wp-json/wp/v2/posts/:id から取得してみましょう。 先ほど記事一覧で追加したアイキャッチ画像とAdvanced Custom Fieldsは、記事の単体取得時にも追加されていますね。

LIGの制作実績サイトでは、さらに、記事に紐付いたカテゴリとタグ、前後の記事のデータが必要になるので、こちらも必要なデータを追加するためにカスタマイズしていきます。

{
    "id": 1531,
    "date": "2017-04-26T16:50:56",
    "date_gmt": "2017-04-26T07:50:56",
    "guid": {
        "rendered": "http://creative.liginc.co.jp/?p=1531"
    },
    "modified": "2017-05-16T16:26:47",
    "modified_gmt": "2017-05-16T07:26:47",
    "slug": "funplex",
    "status": "publish",
    "type": "post",
    "link": "http://localhost/1531",
    "title": {
        "rendered": "funplex"
    },
    "content": {
        "rendered": "",
        "protected": false
    },
    "excerpt": {
        "rendered": "",
        "protected": false
    },
    "author": 3,
    "featured_media": 1542,
    "comment_status": "open",
    "ping_status": "open",
    "sticky": false,
    "template": "",
    "format": "standard",
    "meta": [],
    "categories": [
        3
    ],
    "tags": [
        8,
        9
    ],
    "featured_image": {
        "src": "https://s3-ap-northeast-1.amazonaws.com/production.lig-portfolio/wp-content/uploads/2017/04/16162503/funplex-eye-1776-11861-888x593.png",
        "width": 888,
        "height": 593
    },
    "acf": {
        "client": "ファンプレックス株式会社",
        "copy": "CHANGE  THE  GAME",
        // 省略
    },
    "_links": {
        // 省略
    }
}

記事に紐付いたカテゴリとタグの取得

カテゴリもタグも表示用の名前が欲しいですが、idしか取れていませんね。

"categories": [
    3
],
"tags": [
    8,
    9
],

 

クライアント側で記事取得のあとにカテゴリの単体取得をするのは面倒です。API側であらかじめ記事に紐付けた状態で返すようにしてしまいましょう。

functions.phpに下記のコードを追加することで、記事に好きなデータを追加することができます。

function lig_wp_rest_prepare_single_post( $data, $item, $request ) {
  $prams = $request->get_params();

  if (isset($prams['id'])) {    // リクエストのパラメータにidがある === 記事単体取得時
    $data->data['tags'] = get_the_tags();
    $data->data['categories'] = get_the_category();
  }
  return $data;
}
add_filter( 'rest_prepare_post', 'lig_wp_rest_prepare_single_post', 10, 3 );

 

タグとカテゴリは記事詳細だけに追加したいので、フィルターフックでリクエストのパラメータにidがあるろきだけデータを追加するようにしています。これで、一回のリクエストで、表示側でほしかったカテゴリやタグのnameやslugを取得することができるようになりました。

{
    "id": 1531,
    // 省略
    "categories": [
        {
            "term_id": 3,
            "name": "Corporate",
            "slug": "corporate",
            "term_group": 0,
            "term_taxonomy_id": 3,
            "taxonomy": "category",
            "description": "",
            "parent": 0,
            "count": 16,
            "filter": "raw",
            "term_order": "0",
            "cat_ID": 3,
            "category_count": 16,
            "category_description": "",
            "cat_name": "Corporate",
            "category_nicename": "corporate",
            "category_parent": 0
        }
    ],
    // 省略
    "tags": [
        {
            "term_id": 8,
            "name": "PC",
            "slug": "pc",
            "term_group": 0,
            "term_taxonomy_id": 8,
            "taxonomy": "post_tag",
            "description": "",
            "parent": 0,
            "count": 51,
            "filter": "raw",
            "term_order": "0"
        },
        {
            "term_id": 9,
            "name": "SP",
            "slug": "sp",
            "term_group": 0,
            "term_taxonomy_id": 9,
            "taxonomy": "post_tag",
            "description": "",
            "parent": 0,
            "count": 42,
            "filter": "raw",
            "term_order": "0"
        }
    ],
    // 省略
}

前後の記事

続いて前後の記事のデータを追加します。 lig_wp_get_previous_postとlig_wp_get_next_postはそれぞれ前後の記事を返す関数になっています。

関数内でget_previous_postやget_next_postを呼んでいますが、ここで取れる記事は先ほどのカスタマイズの影響を全く受けません。 前後の記事のアイキャッチやAdvanced Custom Fieldsがほしい場合は、それぞれ取得する記述が必要になります。

function lig_wp_rest_prepare_single_post( $data, $item, $request ) {
  $prams = $request->get_params();

  if (isset($prams['id'])) {
    $data->data['tags'] = get_the_tags();
    $data->data['categories'] = get_the_category();
    $data->data['prev'] = lig_wp_get_previous_post();  // 前の記事
    $data->data['next'] = lig_wp_get_next_post();      // 次の記事
  }
  return $data;
}
add_filter( 'rest_prepare_post', 'lig_wp_rest_prepare_single_post', 10, 3 );

function lig_wp_get_previous_post() {
  $prev = get_previous_post();
  // 前の記事がない場合、最初の記事を取得する
  if(empty($prev)) {
    $prev = get_posts(array('order' => 'DESC', 'posts_per_page' => 1));
    if(!empty($prev[0])) {
      $prev = $prev[0];
    }
  }
  // サムネイルを追加
  $prev->featured_image_src = get_the_post_thumbnail_url($prev->ID);

  return $prev;
}

カテゴリやタグのslugと期間指定で記事一覧の取得

ここまでで、新着記事一覧と記事詳細のJSONの取得はできるようになりました。 続いてアーカイブの記事一覧のJSONを取得してみます。

記事一覧をカテゴリやタグのslugで絞り込む

WP REST APIをそのまま使うと、カテゴリやタグ指定での記事一覧の取得は

  • /wp-json/wp/v2/posts?categories=3
  • /wp-json/wp/v2/posts?tags=8

のように、idで指定する形式になっています。

LIGの制作実績サイトでは、アーカイブページが下記のようなURLになっており、そのままでは素直に記事の一覧を取得することができません。

export default new VueRouter({
  mode: 'history',
  base: __dirname,
  routes: [
    {
      path: '/category/:slug',    // http://creative.liginc.co.jp/category/campaign など
       // 省略
    },
    // 省略
  ]
};

 

クライアント側では、ページにアクセスされたときにslugだけしか分からないので、あらかじめカテゴリやタグを全件取得した状態じゃないとidを知ることができません。

WP REST API filter parameterというプラグインを導入すると

  • /wp-json/wp/v2/posts?filter=campaign
  • /wp-json/wp/v2/posts?filter=pc

のように、カテゴリやタグのslugで記事一覧を取得できるようになるので、面倒なことをせずに済みます。

期間を指定した記事一覧の取得

/wp-json/wp/v2/postsbeforeafter パラメータで、期間を指定して取得することができます。

たとえば、2017年に投稿された記事のみ取得したい場合は、

wp-json/wp/v2/posts?after=2017-01-01T00:00:00&before=2017-12-31T23:59:59

のようにして期間指定をすることができます。

LIGの制作実績サイトでは下記のようなルーティングになりますが、若干クライアント側でごにょごにょする必要があるものの問題なく対応できそうです。

export default new VueRouter({
  mode: 'history',
  base: __dirname,
  routes: [
    {
      path: '/date/:year(20[0-9]{2})',     // http://creative.liginc.co.jp/date/2017 など
      // 省略
    },
    // 省略
  ]
};

独自のエンドポイントの追加

独自のエンドポイントを追加したい場合も簡単にできます。 functions.phpに下記のようにコードを追加します。

add_action('rest_api_init', function() {
  register_rest_route( 'myplugin/v1', '/hoge', array(
    'methods' => 'GET',
    'callback' => 'get_hoge',
  ) );
});
function get_hoge(  ) {
  // なにかデータを返す
}

 

これで /wp-json/myplugin/v1/hoge を叩くと、 callback に指定した関数が返すデータを取得できるようになります。

おわりに

いかがでしたか?

WP REST APIをそのまま使うとなると、ほしい情報が不足している感が否めませんが、アクションフックやフィルターフック、プラグインなどで簡単にカスタマイズすることができました。

SPAの練習台にもちょうといいと思うので、興味があればぜひチャレンジしてみてください。

LIGはWebサイト制作を支援しています。ご興味のある方は事業ぺージをぜひご覧ください。

Webサイト制作の実績・料金を見る

この記事のシェア数

フロントエンドエンジニアのいなばです。 LIGではAngularやVueなどのフレームワークを使った中~大規模のWebアプリケーション開発、フロントエンドエンジニアの育成などを担当しています。 好きなものはカフェインとカプサイシン。 趣味はランニングと一眼レフです。

このメンバーの記事をもっと読む
それいけ!フロントエンド | 213 articles