MENU CLOSE

【WordPress】REST APIで独自エンドポイントの作り方

wordpress

WP REST APIとは

WP REST APIはWordPressに投稿した記事やデータにアクセスできるAPI機能のことです。WordPress 4.7以降より、標準で利用できるようになっています。

WP REST API 公式

https://ja.wp-api.org/

なぜ独自のエンドポイント?

標準で設定されているエンドポイントで十分な情報が取得できるのですが、アイキャッチ画像やカスタムフィールドの情報を取得するのにちょっと工夫が必要だったり、逆に必要ない情報がたくさん入っていたりします。

これは非常に面倒臭い!
自分でAPIのカスタマイズはできないものか!と調べたらけっこう情報がありました。

参考にさせてもらったのはこちらの記事。

WP REST API V2にてカスタムエンドポイントを追加するまとめ

http://kayakuguri.github.io/blog/2016/07/12/wp-rest-api-custom-endpoint/

自分なりに使いやすいようにまとめたので今回はその手順をメモ。

準備

REST APIを扱うにあたって、WordPress側でいくつか設定とお作法的なものがあるのでそれを準備していきます。

functions.php

独自エンドポイントの登録

/*-------------------------------------------*/
/* 独自エンドポイント登録
/*-------------------------------------------*/
function add_custom_endpoint()
{
  register_rest_route(
    //ネームスペース
    'custom/v0',
    //ベースURL
    '/test',
    //オプション
    array(
      'methods'  =>  WP_REST_Server::READABLE,
      'callback' => 'fetch_test_data'
    )
  );
}
add_action('rest_api_init', 'add_custom_endpoint');

rest_api_initというアクションフックでregister_rest_route関数を使ってエンドポイントの詳細を設定して登録します。ここではまずエンドポイントのURLを作ります。
第一引数のネームスペースにcustom/v0
第二引数のベースURLに/testとすると、
https://{ドメイン}/wp-json/custom/v0/testが新しいエンドポイントとして追加されます。
オプションはmethodsにWP_REST_Server::READABLEを指定します。
ここで指定できるメソッドは以下です。

  • WP_REST_Server::READABLE:GET
  • WP_REST_Server::CREATABLE:POST
  • WP_REST_Server::EDITABLE:POST, PUT, PATCH
  • WP_REST_Server::DELETABLE:DELETE
  • WP_REST_Server::ALLMETHODS:GET, POST, PUT, PATCH, DELETE

callbackにはコールバック関数の名前を指定します。コールバック関数の名前は後述で自分で作る関数の名前になるのでなんでも構いません。

続いてレスポンスを返却する際のお作法。

/*
* WP REST APIのレスポンス処理
* @param {String} $file_name ファイル名(拡張子なし)
* @param {Array} $param ajaxで受け取ったデータ
*/
function rest_response($file_name, $param = null) {
  $api_file = locate_template("api/${file_name}.php");
  $res      = !empty($api_file) ? include_once $api_file : [];
  $response = new WP_REST_Response($res);
  $response->set_status(200);
  $domain = (empty($_SERVER["HTTPS"]) ? "http://" : "https://") . $_SERVER["HTTP_HOST"];
  $response->header('Location', $domain);
  return $response;
}

//テストデータ取得
function fetch_test_data($param)
{
  return rest_response('fetch-test-data', $param);
}

rest_responseという関数を作って、テーマ内にあるAPIの処理を書いたファイルからAPIで処理した内容を取得します。処理した内容はWP_REST_Responseという便利な関数を使って配列をJSONの形に整形して返却します。

先ほどコールバックに指定したfetch_test_dataという関数はrest_response関数を通して、{テーマURL}/api/fetch-test-data.phpというファイルからのデータを返すだけの関数です。具体的な内容はfetch-test-data.phpというファイルに書いていきます。ファイルが見つからない場合は空の配列を返すようにしておきます。

好き嫌いがあると思いますが、functions.phpに直接処理を書いていくとものすごく長くなって見通しが悪くなるのでファイル分割しています。もちろんファイル分割せずに直接ここに関数や返却する値を書いても問題ありません。

fetch-test-data.phpの中身は、とりあえず確認のために簡単な配列を返すものにしてみます。

<?php
return [
  'id'      => 1,
  'test'    => true,
  'message' => 'テストデータを取得しました'
];
?>

ここまででAPIとして動くようになっていますのでhttps://{ドメイン}/wp-json/custom/v0/testにアクセスしてみます。

{"id":1,"test":true,"message":"\u30c6\u30b9\u30c8\u30c7\u30fc\u30bf\u3092\u53d6\u5f97\u3057\u307e\u3057\u305f"}

このように返却データが表示されます。JSONに変換され日本語はエスケープ処理されているのでわかりにくいですが、ちゃんと情報が返ってきていることが確認できました。

ここまでできれば、あとはこの中身を取得したいデータに変更するだけで自分だけの独自APIとして動かすことができます。

実装例

どこを調べても大体このあたりで説明は終わり、あとはご自由にどうぞ。というパターンが多いので、この記事では実際に独自APIを使って記事を取得・表示するところまで実装してみます。

今回はTOPページに表示しているブログリストを独自エンドポイントを作って表示して見たいと思います。
完成したのはこちら。

DEMO

できるだけ簡単に済ませたいのでVue.js + axiosを使います。
最近のAPI連携はフレームワークを使った方が直感的で簡単ですね。もしjQueryを使う場合でもAPIから情報を取得する部分についてはそんなに変わりありませんので応用できます。jQuery使うのであればlodash.jsのテンプレートを使うと少し幸せになれそうです。

Lodash

https://lodash.com/

その他Vue.jsaxiosの詳しい使い方については今回は省略します。

PHP(独自API)

先ほど作ったfetch-test-data.phpを編集し、記事に必要なデータのみを抽出した配列を返すように作ります。

<?php
$post_data = [];
$post_args = [
  'post_type'      => 'post',
  'posts_per_page' => 30,
  'post_status'    => 'publish',
  'orderby'        => 'date',
  'order'          => 'DESC'
];
$post_query = new WP_Query( $post_args );
if ( $post_query->have_posts() ) :
  while ( $post_query->have_posts() ) :
    $post_query->the_post();
    global $post;
    //著者情報
    $author          = get_userdata($post->post_author);
    $author_id       = $author->ID;
    $author_nicename = get_the_author_meta('user_nicename');
    //カスタムフィールドの画像を取得
    $avatar_src      = scf_auther_src($author_id, 'cf_writer_avatar', 'thumbnail');
    //カテゴリ取得
    $category   = get_the_category();
    $cat_name   = $category[0]->cat_name;
    $cat_slug   = $category[0]->slug;
    //タグ
    $tags       = get_the_tags();
    $tags_array = [];
    foreach ($tags as $tag) {
      $tags_array[] = [
        'tag_id'    => $tag->term_id,
        'tag_name'  => $tag->name
      ];
    }

    $post_data[] = [
      //記事ID
      'id'            => $post->ID,
      //公開日
      'time'          => get_the_time('Y.m.d'),
      //画像URL
      'image_src'     => !empty(get_eyecatch_src('medium')) ? get_eyecatch_src('medium') : get_theme_file_uri('assets/images/default-post.jpg'),
      //執筆者
      'author_name'   => $author_nicename,
      //執筆者の画像
      'avatar_src'    => $avatar_src,
      'title'         => wp_strip_all_tags(remove_two_space($post->post_title), true),
      'category'      => $cat_name,
      'category_slug' => $cat_slug,
      //タグ
      'tags'          => $tags_array,
      //リンク
      'link'          => get_the_permalink()
    ];
  endwhile;
  wp_reset_postdata();
endif;

return $post_data;
?>

これでAPIにhttps://{ドメイン}/wp-json/custom/v0/testにアクセスすると最大30記事分の最新記事の情報がJSONで取得できるようになりました。

scf_auther_srcget_eyecatch_srcという関数は独自で作った関数です。環境に合わせて情報取得の処理は書き換えてください。

HTML

<div>
  <section>
    <h2>POSTS by REST API</h2>
    <posts/></posts>
  </section>
</div>
<script>
    var WP_API_Settings = {
      root       : "<?php echo esc_url_raw(rest_url())?>",
      rest_nonce : "<?php echo wp_create_nonce('wp_rest')?>"
    };
</script>

htmlはこれだけ。CSSは長くなるので省略します。記事のループ部分はAPIから情報を受け取ってVue.jsのテンプレートで生成します。scriptタグにはREST APIのルートURLと、後述で扱うクッキー認証のためのnonceの2つを設定したオブジェクトをJS内で扱うために変数にしておきます。

Vueテンプレート

<template>
  <div class="group">
    <div class=list">
      <a class="item" v-for="post in posts" :href="post.link" :class="categoryClassName(post)" :key="post.id">
        <time class="date">{{post.time}}</time>
        <div class="pic">
          <img
          :src="post.image_src"
          :alt="post.title">
        </div>
        <!-- /.pic -->
        <div class="content">
          <div class="avatar">
            <span class="avatar-name">{{post.author_name}}</span>
            <div class="avatar-icon">
              <img
              :src="post.avatar_src"
              :alt="post.title"
              >
            </div>
            <!-- /.avatar-icon -->
          </div>
          <!-- /.avatar -->
          <span class="cat" :class="categoryClassName(post)">{{post.category}}</span>
          <p class="title">{{post.title}}</p>
          <ul class="tags">
            <li class="tag" v-for="tag in post.tags" :key="tag.tag_id">{{tag.tag_name}}</li>
          </ul>
          <!-- /.tags -->
        </div>
        <!-- /.content -->
      </a>
      <!-- /.item -->
    </div>
    <!-- /.list -->
  </div>
  <!-- /.group -->
</template>

ここでのポイントはv-forの使い方です。

  • すべての記事情報はpostsという値に配列で入れてv-forでループして表示する。
  • タグも配列なのでv-forでループさせて表示させる

JavaScript

実際はHTMLとJavaScriptをひとつのcomponentとして同じ.vueファイルにまとめて書きますが、説明の都合上分けて書いています。

<script>
  import axios from 'axios'
  const wp_rest = axios.create({
    baseURL: WP_API_Settings.root,
    headers: { 'X-WP-Nonce': WP_API_Settings.rest_nonce }
  });

  export default {
    data() {
      return {
        posts : null
      }
    },
    created() {
      wp_rest.get('custom/v0/test?_envelope')
      .then((res) => {
        if(Array.isArray(res.data.body) && res.data.body[0]){
          this.posts = res.data.body;
        }
      })
      .catch(res => {
        if('console' in window){
         console.error(res);
       }
     })
    },
    methods : {

      /*
      * カテゴリー名のClassを付ける
      * @param {Object} post 記事情報
      */
      categoryClassName(post) {
        if(('category_slug' in post) && post.category_slug){
          return post.category_slug;
        }
      }

    }
  }
</script>

JavaScriptはめちゃくちゃシンプルです。
axiosで先ほど作ったAPIにアクセスして、それをpostsにそのまま入れるだけです。これだけでVue.jsが自動的にv-forで表示させてくれます。

categoryClassNameメソッドはカテゴリースラッグをclass名として追加するだけのシンプルな関数です。これは記事の色分けに使っているだけなので特に必要なければ削除して大丈夫です。

ここでわかりにくいかなと思うのはajaxの設定です。
ポイントとしては、以下の2点。

  • ヘッダーにX-WP-NonceというWordPressのクッキー認証を入れる
  • リスエストURLに_envelopeパラメータを付ける

まずX-WP-Nonceですが、今回のようなGETメソッドのみのエンドポイントの場合は特に必要ないのですが、POSTメソッドを扱う場合は必須になります。
僕は忘れがちなのでAPIを扱う時は必ずセットで設定しておくようにしています。

次に_envelopeパラメータについて。
これは以前、独自のREST APIエンドポイントを作ったときに、なぜかカスタムフィールドの情報だけが取得できない!というトラブルが起き、このパラメータを付けることで解決した、ということがあったので付けるようになりました。レスポンスデータがbodyに入って、レスポンスとしても扱いやすいため必ず付けています。

どちらも付けないと表示されないってことはないと思いますので、必要ない方は外していただいて良いと思います。僕はREST APIの取得方法は統一しておきたいのでこの書き方に落ち着きました。

以上で完成です!

DEMO

さいごに

これまでwp-ajax.phpを使ってajax処理をしていましたが、新規で作るものはREST APIを使うようにしています。wp-ajax.phpと比べてレスポンスの速さが半分くらいになるのでそれだけでも使う価値があると思います。

ぜひ楽しいREST APIライフを!

記事一覧

Related

wordpress
inoue
inoue
TIPS

【WordPress】便利なアクションフック「template_redirect」

wordpress
inoue
inoue
TIPS

【WordPress】画像に自動付与されるsrcset属性を削除する

wordpress
inoue
inoue
TIPS

WordPressでよく使うプラグイン15選!

JavaScript
inoue
inoue
TIPS

スライダーといえばSwiper!

gulp+webpack
inoue
inoue
TIPS

gulp4 + webpack4でつくるフロント開発環境

SVG
inoue
inoue
TIPS

SVGで手書き風文字アニメーション

ブログ記事一覧
  • HOME
  • TIPS
  • 【WordPress】REST APIで独自エンドポイントの作り方