WP REST APIはWordPressに投稿した記事やデータにアクセスできるAPI機能のことです。WordPress 4.7以降より、標準で利用できるようになっています。
WP REST API 公式
https://ja.wp-api.org/
WordPressに標準で設定されているエンドポイントで十分な情報が取得できるのですが、アイキャッチ画像やカスタムフィールドの情報を取得するのにちょっと工夫が必要だったり、逆に必要ない情報がたくさん入っていたりします。
これは非常に面倒臭い!
自分でAPIのカスタマイズはできないものか!と調べたらけっこう情報がありました。
参考にさせてもらったのはこちらの記事。
WP REST API V2にてカスタムエンドポイントを追加するまとめ
http://kayakuguri.github.io/blog/2016/07/12/wp-rest-api-custom-endpoint/
自分なりに使いやすいようにまとめたので今回はその手順をメモ。
WP REST APIを扱うにあたって、WordPress側でいくつか設定とお作法的なものがあるのでそれを準備していきます。
/*-------------------------------------------*/
/* 独自エンドポイント登録
/*-------------------------------------------*/
function add_custom_endpoint()
{
register_rest_route(
//ネームスペース
'custom/v0',
//ベースURL
'/test',
//オプション
[
'methods' => WP_REST_Server::READABLE,
'permission_callback' => '__return_true',
'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
:GETWP_REST_Server::CREATABLE
:POSTWP_REST_Server::EDITABLE
:POST, PUT, PATCHWP_REST_Server::DELETABLE
:DELETEWP_REST_Server::ALLMETHODS
:GET, POST, PUT, PATCH, DELETEcallback
にはコールバック関数の名前を指定します。コールバック関数の名前は後述で自分で作る関数の名前になるのでなんでも構いません。
*(2020.09.04追記)
permission_callback
がWP5.5から必須になりました。
ここでは'__return_true'
として公開用のAPIとしてどこからでもアクセスできるようにしていますが、APIごとに権限などでアクセス制限したい場合は以下のように書きます。
function add_custom_endpoint()
{
register_rest_route(
//ネームスペース
'custom/v0',
//ベースURL
'/test',
//オプション
[
'methods' => WP_REST_Server::READABLE,
'permission_callback' => 'rest_permission', //関数名指定
'callback' => 'fetch_test_data'
]
);
}
add_action('rest_api_init', 'add_custom_endpoint');
//APIの権限をチェックする関数
function rest_permission(){
return current_user_can('publish_posts');
}
こうすると、publish_posts
の権限を持ったユーザーだけしかアクセスできないようにAPIを制限できます。プラグイン開発などで管理画面のみで扱うAPIを作るときや、何か特別なnonceやセッションなどをチェックしてアクセス制限させたいときなどに使えます。
続いてレスポンスを返却する際のお作法。
/*
* 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);
return $response;
}
//テストデータ取得
function fetch_test_data($param)
{
return rest_response('fetch-test-data', $param);
}
rest_response
という関数を作って、テーマ内にあるAPIの処理を書いたファイルからAPIで処理した内容を取得します。処理した内容はWP_REST_Response
という便利な関数を使って配列をJSONの形に整形して返却します。
*ここではひとまず動かすことを目的としていますので、全ての内容をstatus200として返すようにしていますが、実際にはWP_Error
クラスなどを使ってエラーハンドリングすることが必要になりますのでご注意ください。
先ほどコールバックに指定した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ページに表示しているブログリストを独自エンドポイントを作って表示して見たいと思います。
完成したのはこちら。
できるだけ簡単に済ませたいのでVue.js + axios
を使います。
最近のAPI連携はフレームワークを使った方が直感的で簡単ですね。もしjQuery
を使う場合でもAPIから情報を取得する部分についてはそんなに変わりありませんので応用できます。jQuery
使うのであればlodash.js
のテンプレートを使うと少し幸せになれそうです。
Lodash
https://lodash.com/
その他Vue.js
やaxios
の詳しい使い方については今回は省略します。
先ほど作った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_src
やget_eyecatch_src
という関数は独自で作った関数です。環境に合わせて情報取得の処理は書き換えてください。
<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内で扱うために変数にしておきます。
<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
でループさせて表示させる実際は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のクッキー認証を入れる_envelope
パラメータを付けるまずX-WP-Nonce
ですが、今回のようなGETメソッドのみのエンドポイントの場合は特に必要ないのですが、POSTメソッドを扱う場合は必須になります。
僕は忘れがちなのでAPIを扱う時は必ずセットで設定しておくようにしています。
次に_envelope
パラメータについて。
これは以前、独自のWP REST APIエンドポイントを作ったときに、なぜかカスタムフィールドの情報だけが取得できない!というトラブルが起き、このパラメータを付けることで解決した、ということがあったので付けるようになりました。レスポンスデータがbodyに入って、レスポンスとしても扱いやすいため必ず付けています。
どちらも付けないと表示されないってことはないと思いますので、必要ない方は外していただいて良いと思います。僕はWP REST APIの取得方法は統一しておきたいのでこの書き方に落ち着きました。
以上で完成です!
これまでwp-ajax.php
を使ってajax処理をしていましたが、新規で作るものはWP REST APIを使うようにしています。wp-ajax.php
と比べてレスポンスの速さが半分くらいになるのでそれだけでも使う価値があると思います。
ぜひ楽しいWP REST APIライフを!