この記事をおすすめしたい人
- WordPressのREST APIをカスタムフィールドでソートしたい人
- WP-PostViewsのPV順で人気記事一覧を作りたい人
- つまりオレ
今回はWordPressのREST APIをカスタムフィールドでソートします。
「人気の記事」とかでWP-PostViewsプラグインのPV順に並び替えたいこととかあると思うんですよね。 WP-PostViewsのPVは「views」というカスタムフィールドが使われているので、並び替えるにはカスタムフィールドでソートしてやる必要があります。
今回も最後にコピペ用コードを用意したので読むのがめんどくさい人は最後のまとめへ。
このページの目次
REST API側にカスタムフィールドでソートする機能はないのか?
たぶんないです。 なさそう。
ネットで調べてると「filter」とか使ってソートしてるっぽいのがあるんですが、動きませんでした。 V1時代のREST APIの書き方なんだろうか?
V2の仕様(投稿)を見ていると、「orderby」の項目は次のいずれかと書いてあります。
- author
- date
- id
- include
- modified
- parent
- relevance
- slug
- include_slugs
- title
これ以外を指定するとエラーを返します。 カスタムフィールドは指定できません。
WordPressと同じように指定してみる
投稿に関する基本のクエリは「/wp/v2/posts」です。 このサイトの場合だとこんな風になります。
ここへ「投稿」のPost一覧の引数から希望のものを追加していきます。
検索条件を追加する際は、一つ目は「?」で連結します。 2個目以上は「&」で繋ぎます。
項目と値は「=」で連結します。 値が複数ある場合は「+」で連結します。
例えば「更新日時で降順」の場合、この↓ようになります。
/wp/v2/posts?orderby=modified&order=desc
これはWordPressのWP_Queryでも同様で、WordPressの場合はさらにカスタムフィールドでソートすることができ、その場合は次のように指定します。
- orderby=meta_value_num
- meta_key=(カスタムフィールド名)
- order=desc
「meta_value_num」はカスタムフィールドを数値でソートするサインです。 文字列の場合は「meta_value」を指定します。
これを真似てカスタムフィールド名を「views」として次のようにAPIを叩いてみます。
(viewsはWP-PostViewsのPV数です)
/wp/v2/posts?orderby=meta_value_num&meta_key=views&order=desc
結果がこう↓。
orderby は author, date, id, include, modified, parent, relevance, slug, include_slugs, title, menu_order に当てはまりません。
「meta_key」は未知の要素なので怒られませんでしたが(無視するので)、「orderby」は決められた値じゃなかったのでエラーが出ました。
ここまでのことを踏まえてカスタムフィールドでのソートを実装してみます。
WordPress側で引数を変更すればカスタムフィールドでソート可能
WordPressにはREST APIで指定された引数をどう扱うかを変更するアクションフックがあります。 rest_{$this->post_type}_queryです。
変な名前になっていますが、{$this->post_type}の部分には対象の投稿タイプを入れます。 投稿なら「rest_post_query」、固定ページなら「rest_page_query」になります。
引数は2つあり、第1引数が実際に検索に使う引数の配列、第2引数がリクエストされた引数です。
つまり、リクエスト時に存在しない「meta_key」を指定してやり、「meta_key」の指定があった場合には実際にmeta_keyを使って検索させるよう指示してやるわけです。
カスタムフィールドでソートするコード
functions.phpに次のコードを追加すると、カスタムフィールドでのソートが可能になります。
add_action('rest_post_query', 'sortby_meta_key', 10, 2);
function sortby_meta_key($args, $request) {
if ( isset($request['meta_key']) ) {
$args['meta_key'] = $request['meta_key'];
$args['orderby'] = 'meta_value_num';
}
return $args;
}
APIリクエストの際にmeta_keyが指定されていると、実際に検索に使うクエリにmeta_keyをセット。
このままではリクエストで指定された「orderby」の項目でソートされてしまうので、orderbyを「meta_value_num」に設定しておきます。
「order」はそのまま指定されたクエリのものを使います。 デフォルトではdesc(降順)です。
これでカスタムフィールドでのソートが可能になりました。
実際に使う場合は、次のようにAPIを叩きます。
(WP-PostViewsの「view」を例に)
/wp/v2/posts?meta_key=views&order=desc
「views」のところに別のカスタムフィールドの名前を入れればそのカスタムフィールドでソートできます。
並び替え方法を指示できるように改良したコード
並び替える以上、基本は数値で並び替えだと思いますが、文字列で比較したいケースもあると思います。
なので「meta_value_num」でソートするのか「meta_value」でソートするのか指示できるようにします。
add_action('rest_post_query', 'sortby_meta_key', 10, 2);
function sortby_meta_key($args, $request) {
if ( isset($request['meta_key']) ) {
$args['meta_key'] = $request['meta_key'];
$args['orderby'] = 'meta_value_num';
if ( isset($request['meta_orderby']) ) {
$args['orderby'] = $request['meta_orderby'];
}
}
return $args;
}
「orderby」にそのまま「meta_value_num」やら「meta_value」を入れると先ほどと同様に怒られてしまうので、「meta_orderby」という専用のキーを用意しました。
「meta_orderby」の指定があった場合はそれでorderbyを上書きします。
APIを叩く場合はこの↓ように。
/wp/v2/posts?meta_key=views&meta_orderby=meta_value_num&order=desc
全件取得してフレームワーク側でソートは?
ダメです。
記事数が多いと1回の通信でものすごい量になってしまうのと、そもそもREST APIは最大100件までしか取得できないようです。
101番目に一番人気の記事があった場合には無視されます。
APIが結果を返し続ける限り100件ずつ取得していくことで擬似的には全件取得は可能だと思いますが、このように方法があるんだから無理に全件取得する必要はないと思います。
コピペで使えるまとめ
WordPressのREST APIをカスタムフィールドでソートするには、まずfunctions.phpに次のコードを追加します。
add_action('rest_post_query', 'sortby_meta_key', 10, 2);
function sortby_meta_key($args, $request) {
if ( isset($request['meta_key']) ) {
$args['meta_key'] = $request['meta_key'];
$args['orderby'] = 'meta_value_num';
if ( isset($request['meta_orderby']) ) {
$args['orderby'] = $request['meta_orderby'];
}
}
return $args;
}
APIのリクエスト時には次のように指示します。 viewsのところはソートしたいカスタムフィールド名を入れてください。
/wp/v2/posts?meta_key=views
以上、WordPressからお届けしました!
WP REST APIカスタマイズ編の目次
- 第1回 カスタムフィールドを追加
- 第2回 アイキャッチ画像を追加
- 第3回 前後の記事を追加
- 第4回 カテゴリ情報を追加
- 第5回 「_links」を削除
- 第6回 不要な要素を削除
- 第7回 自動成形を無効化
- 第8回 カスタムフィールドでソート(このページ)
- 第9回 カスタマイズまとめ
- 第10回 カテゴリAPIの軽量化