こんにちは、渕上です。

みなさんGWはどこかに出かけましたか?私は息子を連れて大宮の鉄道博物館に行ってきました。
このブログにも登場しているT氏は、数日に分けて東海道を箱根過ぎまで歩いたそうです。
まったくどうかしてますね!

さて今回は、Wordpressのプラグイン「WP REST API」を使って遊んでみようと思います。

WP REST API

「WP REST API」プラグインは、Wordpressに投稿されている記事の一覧をJSONで取得したり、
記事の投稿、編集ができるAPIを追加するプラグインです。

下記にリファレンスが公開されていますので、興味のある方は是非使ってみてください。
http://wp-api.org/index-deprecated.html

現在バージョン1系と2系がリリースされており、1系が安定板、2系がβ版の状況のようです。
今回は安定板の1系を利用して、本ブログの記事の一覧を取得・表示してみたいと思います。

記事の一覧をJSONで取得する

プラグインを有効にすると、/wp-json/*にいくつかのエンドポイントが公開されます。
今回は記事の一覧を取得したいので、wp-json/postsエンドポイントに対してリクエストしてみます。

このブログにもプラグインを追加していますので、下記URLにアクセスして結果を参照してみてください。
/wp-json/posts

フィルタしてみる

とりあえず、記事の一覧が取得できました。
これで終わりではちょとさみしいので、絞り込みを試してみたいと思います。
filterパラメータに特定の値を渡してリクエストすると、一覧をフィルタリングすることが可能です。

リファレンスの下記ページに、詳細情報が公開されています。
http://wp-api.org/index-deprecated.html#posts_retrieve-posts
ざっと眺めてみると、Wordpress標準のget_posts()関数とほぼ同じことができるようです。

カテゴリ名でフィルタする

早速、カテゴリ名で絞り込みを行ってみたいと思います。

本ブログの中で私の大好きなロボピッチャ関連の記事が登録されている、「工作」カテゴリの一覧を取得してみましょう。
「工作」カテゴリの一覧を取得するにはfilter.category_nameパラメータの値に工作をセットします。

結果をご覧になりたい方は下記のURLにアクセスしてみてください。
/wp-json/posts?filter[category_name]=%E5%B7%A5%E4%BD%9C

件数を絞り込む

デフォルトの一覧件数は、Wordpress管理画面の設定値に依存しているようです。
取得する件数を変えるのにイチイチ管理画面で変更していては大変ですね。
何よりJSON API以外のところに影響が出てしまいます。

一度に取得する件数を変更するには、filter.posts_per_pageパラメータに任意の整数をセットします。
今回は、5件分取得するようにしてみました。

結果をご覧になりたい方は下記のURLにアクセスしてみてください。
/wp-json/posts?filter[posts_per_page]=5

Javascriptで読み込んでみる

ブラウザでJSONを眺めているだけではつまらないですね。

生粋のJSONマニアの諸兄はこれだけで丼飯3杯でも10杯でもいけるのかもしれませんが、
残念ながら私には無理です。

そこでJavascriptを使ってJSONを読み込み、HTMLに出力してみたいと思います。

最新の3件を読みこんで表示する

jQueryの$.ajaxメソッドで最新の3件を読み込み、表示するサンプルを作成してみました。

テンプレートエンジンには、jsViewsを使っています。
今回はjsViewsの使い方には触れませんが、Qiitaに投稿されているこの記事などが参考になると思います。

サンプルを開く

ソースコード

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" integrity="sha256-7s5uDGW3AHqw6xtJmNNtr+OBRJUlgkNJEo78P4b0yRw= sha512-nNo+yCHEyn0smMxSswnf/OnX6/KwJuZTlNZBjauKhTK0c+zT+q5JOCx0UFhXQ6rJR9jg6Es8gPuD2uZcYDLqSw==" crossorigin="anonymous">
  <!--[if lt IE 9]>
    <script src="https://oss.maxcdn.com/libs/html5shiv/3.7.2/html5shiv.js"></script>
    <script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
  <![endif]-->
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha256-KXn5puMvxCw+dAYznun+drMdG1IFl3agK0p/pqT9KAo= sha512-2e8qq0ETcfWRI4HJBzQiA3UoyFk6tbNyG+qSaIBZLyW9Xf3sWZHN/lxe9fTh1U45DpPf07yj94KsUHHWe4Yk1A==" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jsviews/0.9.75/jsviews.js"></script>
  <title></title>
</head>
<script>
$(function(){
  var $template = $.templates('#listTemplate');

  get_posts(
    '/wp-json/posts',
    {
      posts_per_page: 3
    },
    function(json) {
      $template.link('#list', {list: json});
    }
  );
});

function get_posts(url, filter/*, doneFunc, failFunc, alwaysFunc */) {
  var doneFunc   = arguments[2] || function(){};
  var failFunc   = arguments[3] || function(){};
  var alwaysFunc = arguments[4] || function(){};

  $.ajax({
    url: url,
    dataType: 'json',
    data: {
      filter: filter
    }   
  })
  .done(doneFunc)
  .fail(failFunc)
  .always(alwaysFunc);
}
</script>

<script id="listTemplate" type="text/x-jsrender">
  <div class="col-xs-12">
    <div class="list-group">
      {^{for list}}
      <a data-link="href{:link}" class="list-group-item" target="_rmrf">
        <h4 class="list-group-item-heading">{^{:title}}</h4>
        {^{:excerpt}}
      </a>
      {{/for}}
    </div>
  </div>
</script>

<body class="container">
  <header class="row">
    <div class="col-xs-12">
      <h1>sudo rm -rf / の最新記事<h1>
    </div>
  </header>
  <div id="list" class="row">
  </div>
  <footer class="row">
    <div class="col-xs-12">
      <p>&copy;2016 <a href="http://adjust.ne.jp" target="_adjust">株式会社アジャスト</a></p>
    </div>
  </footer>
</body>
</html>

ページネーションする

折角なので最新の3件だけでなく、3件ずつさかのぼれるようにページネーションを実装してみましょう。

ページネーションさせるにはいくつかの情報(総ページ数とか)が知りたくなりますが、
どうやらJSON REST APIが返すJSONには、記事の一覧が含まれるのみで、そういったメタ情報は含まれていません。
では、どうすればいいのでしょうか。
結論としては、ページ情報はレスポンスヘッダに含まれます。

実は最近これにハマり、Qiitaにメモしたことがあるので、よろしければご一読ください。
(そして今更、レスポンスヘッダの情報取得に同一ドメインポリシーの制限がかかることに気づきました。。Qiitaの記事にも追記しておきたいと思います。)

下記はページャを実装したサンプルになります。
「もっと見る」をクリックすると、3件ずつ記事をさかのぼっていくことができます。
サンプルを開く

ソースコード

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" integrity="sha256-7s5uDGW3AHqw6xtJmNNtr+OBRJUlgkNJEo78P4b0yRw= sha512-nNo+yCHEyn0smMxSswnf/OnX6/KwJuZTlNZBjauKhTK0c+zT+q5JOCx0UFhXQ6rJR9jg6Es8gPuD2uZcYDLqSw==" crossorigin="anonymous">
  <!--[if lt IE 9]>
    <script src="https://oss.maxcdn.com/libs/html5shiv/3.7.2/html5shiv.js"></script>
    <script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
  <![endif]-->
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha256-KXn5puMvxCw+dAYznun+drMdG1IFl3agK0p/pqT9KAo= sha512-2e8qq0ETcfWRI4HJBzQiA3UoyFk6tbNyG+qSaIBZLyW9Xf3sWZHN/lxe9fTh1U45DpPf07yj94KsUHHWe4Yk1A==" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jsviews/0.9.75/jsviews.js"></script>
  <title></title>
</head>
<script>
$(function(){
  var currentPage = 1;
  var endpoint    = '/wp-json/posts';
  var $template   = $.templates('#listTemplate');

  get_posts(
    endpoint,
    {
      posts_per_page: 3
    },
    currentPage,
    function(json, textStatus, request) {
      var datas = { list: json }

      $template.link('#list', datas)
      .on('click', '#list-more', function(e){
        e.preventDefault();

        get_posts(
          endpoint,
          { posts_per_page: 3},
          ++currentPage,
          function(json, textStatus, request){
            $.observable(datas.list).refresh(datas.list.concat(json));
            if (currentPage == request.getResponseHeader('X-WP-TotalPages')) {
              $('#list-more').hide();
            }
          }
        )
      });
    }
  );
});

function get_posts(url, filter/*, page, doneFunc, failFunc, alwaysFunc */) {
  var page       = arguments[2] || 1;
  var doneFunc   = arguments[3] || function(){};
  var failFunc   = arguments[4] || function(){};
  var alwaysFunc = arguments[5] || function(){};

  $.ajax({
    url: url,
    dataType: 'json',
    data: {
      page: page,
      filter: filter
    }   
  })
  .done(doneFunc)
  .fail(failFunc)
  .always(alwaysFunc);
}
</script>

<script id="listTemplate" type="text/x-jsrender">
  <div class="col-xs-12">
    <div class="list-group">
      {^{for list}}
      <a data-link="href{:link}" class="list-group-item" target="_rmrf">
        <h4 class="list-group-item-heading">{^{:title}}</h4>
        {^{:excerpt}}
      </a>
      {{/for}}
    </div>
  </div>
  <div class="col-xs-12">
    <a href="#" id="list-more" class="btn btn-primary btn-block">もっと見る</a>
  </div>
</script>

<body class="container">
  <header class="row">
    <div class="col-xs-12">
      <h1>sudo rm -rf / の最新記事<h1>
    </div>
  </header>
  <div id="list" class="row">
  </div>
  <footer class="row">
    <div class="col-xs-12">
      <p>&copy;2016 <a href="http://adjust.ne.jp" target="_adjust">株式会社アジャスト</a></p>
    </div>
  </footer>
</body>
</html>

感想

「WP REST API」を使うと簡単に記事の一覧が取得できることがわかりました。
次回は、APIの返却するJSONに独自の値を追加する方法をご紹介したいと思います。