この記事をおすすめしたい人
- WordPressのREST APIから「_links」を削除したい人
- 少しでもREST APIを軽量化したい人
- つまりオレ
今回はWordPressのREST APIから、何に使うのかよく分からない「_links」を削除します。
前回、「context=embed」を指定して、記事一覧取得時のサイズを激減させる話をしました。
PageSpeed Insights対策もそうですが、通信サイズ減少のことを考え出すとキリがなくてですね。 「_links」は1記事あたりせいぜい1KB程度なんですが、10記事取得すれば10KBですからね。
使ってないデータで10KBも増加されるのは(僕は)無視できません。
というわけでばっさり削除します。
最後にコピペ用コードを置いているので、原理とかに興味ない人はまとめへ飛んでください。
このページの目次
「_links」というのがすげー邪魔
記事取得時に「context=embed」を指定することでAPIのレスポンスサイズは激減しました。
前回の記事を例にすると、
view指定(デフォルト)の場合15.4KB。
embed指定の場合1.8KBです。
9割弱減らせています。
で、embedの中身を覗いてみると、
{
"id": 102,
"date": "2020-08-14T15:05:03",
"slug": "wp-rest-embed",
"type": "post",
"link": "https://dev.ore-shika.com/wp-rest-embed/",
"title": {
"rendered": "WordPressのREST APIで記事一覧取得に「embed」を指定すると9割以上サイズを減らせた"
},
"excerpt": {
"rendered": "<p>この記事をおすすめしたい人 WordPressのREST APIから記事一覧取得時に「embed」を使っていない人 ページ内の複数の記事一覧をREST APIから取得している人 つまりオレ WordPressのREST […]</p>\n",
"protected": false
},
"author": 1,
"featured_media": 0,
"_links": {
"self": [
{
"href": "https://dev.ore-shika.com/wp-json/wp/v2/posts/102"
}
],
"collection": [
{
"href": "https://dev.ore-shika.com/wp-json/wp/v2/posts"
}
],
"about": [
{
"href": "https://dev.ore-shika.com/wp-json/wp/v2/types/post"
}
],
"author": [
{
"embeddable": true,
"href": "https://dev.ore-shika.com/wp-json/wp/v2/users/1"
}
],
"replies": [
{
"embeddable": true,
"href": "https://dev.ore-shika.com/wp-json/wp/v2/comments?post=102"
}
],
"version-history": [
{
"count": 0,
"href": "https://dev.ore-shika.com/wp-json/wp/v2/posts/102/revisions"
}
],
"wp:attachment": [
{
"href": "https://dev.ore-shika.com/wp-json/wp/v2/media?parent=102"
}
],
"wp:term": [
{
"taxonomy": "category",
"embeddable": true,
"href": "https://dev.ore-shika.com/wp-json/wp/v2/categories?post=102"
},
{
"taxonomy": "post_tag",
"embeddable": true,
"href": "https://dev.ore-shika.com/wp-json/wp/v2/tags?post=102"
}
],
"curies": [
{
"name": "wp",
"href": "https://api.w.org/{rel}",
"templated": true
}
]
}
}
後半に「_links」という項目がずらずらずらっと並んでます。
embed指定でせっかく1.8KBにまで減らしたのに、この_linksが1KBも占有してます。 半分以上です。
内容的にはあったら便利そうなのもありますが、必要な時には自分で生成できる内容ばかりなので、
フヨウラ!
REST API内の「_links」を削除する
「_links」を削除するにはrest_prepare_{$this->post_type}というアクションフックを使います。
何やら分かりにくい名前になっていますが、「{$this->post_type}」には対象とする投稿タイプのスラッグが入るので、投稿ページの場合は「rest_prepare_post」、固定ページの場合は「rest_prepare_page」になります。
今回は投稿ページから「_links」を削除するので「rest_prepare_post」を使います。
以下、functions.phpに追加するコードです。
まずはアクションフックの設定
rest_prepare_postのアクションフックを追加します。
add_action('rest_prepare_post', 'remove_post_links', 10, 3);
コールバック(削除の際に使用する関数)は「remove_post_links」としました。 ここは好きに決めて大丈夫です。
rest_prepare_postの引数
公式の説明によると、引数は3つ。
- 第1引数:
WP_REST_Responseオブジェクトで、今回削除する「_links」はここに入っています - 第2引数:
WP_Postオブジェクトで、よく使う記事情報です - 第3引数:
WP_REST_Requestオブジェクトで、GETのパラメータなどが入っていました
コールバック関数の追加
コールバック関数の基本はこの↓ような形になります。
function remove_post_links($response, $post, $request) {
return $response;
}
WP_REST_Responseである「$response」に削除対象があるので、$responseを操作した後、それを返します。
削除したい「_links」は「$response」の中の「links」というプロパティの中に入っていますが、「protected」に設定されているためそのままではアクセスできません。
ですがWP_REST_Responseには「links」の中身を操作する関数が用意されているので、今回は削除用の「remove_link」を使います。
function remove_post_links($response, $post, $request) {
$response->remove_link('self');
$response->remove_link('collection');
$response->remove_link('about');
$response->remove_link('author');
$response->remove_link('replies');
$response->remove_link('version-history');
$response->remove_link('wp:attachment');
$response->remove_link('wp:term');
$response->remove_link('curies');
return $response;
}
何を削除するのかあらかじめ把握できていたので、全部のキーを削除指定にしてみました(不細工)。
出力結果↓。
"_links": {
"wp:attachment": [
{
"href": "https://dev.ore-shika.com/wp-json/wp/v2/media?parent=102"
}
],
"wp:term": [
{
"taxonomy": "category",
"embeddable": true,
"href": "https://dev.ore-shika.com/wp-json/wp/v2/categories?post=102"
},
{
"taxonomy": "post_tag",
"embeddable": true,
"href": "https://dev.ore-shika.com/wp-json/wp/v2/tags?post=102"
}
],
"curies": [
{
"name": "wp",
"href": "https://api.w.org/{rel}",
"templated": true
}
]
}
…って、あれ?
「wp:attachment」「wp:term」「curies」の3つが消えてません。
「wp:」から始まる2つは名前が特徴的なのと、「curies」は明らかに内容が異質なので、何か別の指定が必要なのかもしれません。
get_links()で全キー取得して根こそぎ削除
WP_REST_Responseにはlinksに含まれる要素を全て取得する関数「get_links()」が用意されていました。
全要素を取得して、foreachで根こそぎ削除してみます。
function remove_post_links($response, $post, $request) {
$links = $response->get_links();
foreach ( $links as $key => $value) {
$response->remove_link($key);
}
return $response;
}
これで無事に全要素を削除することができました。
というか、中身が空になったせいで「_links」自体が消えてますね。
ついでに、上記ループで$keyを確認したところ、「wp:attachment」は「https://api.w.org/attachment」、「wp:term」は「https://api.w.org/term」になっていました。
「curies」は見つかりませんでしたが、「_linksがひとつでも要素を持っていたら自動で追加」とかそんな感じなのかな。
「_links」削除でさらに50%ほどサイズ減少した
_links削除の効果を、当サイトを例に調べました。
この記事まで公開されている状態で、最新の記事10件を取得。 このAPIレスポンスのサイズを次の3パターンで比較します。
- 「context=view」
- 「context=embed」
- 「context=embed」+「_links」の削除
結果↓。
- 「context=view」
=254KB - 「context=embed」
=17.6KB - 「context=embed」+「_links」の削除
=8.26KB
半分未満になっています。
素晴らしいですね。
「_links」は本当に不要なのか?
どうなんでしょうねぇ。
WordPressがデフォルトで追加しているということは「あったら便利」みたいな位置づけなのではないかと思います。
ですが、僕は自分でREST APIを使うために最適化しています。
つまり「僕が使わないもの」。
それ即ち。
フヨウラ!
番外編:削除できそうで出来なかった方法
REST APIにカスタムフィールドやアイキャッチを追加するコードを書いている時に思いついた方法です。
REST APIに項目を追加するには次のようなコードを追加します。
add_action( 'rest_api_init', 'api_add_fields' );
function api_add_fields() {
register_rest_field( 'post',
'XXXXXXXXX',
array(
'get_callback' => 'register_fields',
'update_callback' => null,
'schema' => null,
)
);
}
function register_fields( $post, $name ) {
return YYYYYYYYY
}
上のコードの場合、出力結果はこう↓なります。
{
(略)
categories: [],
tags: [],
XXXXXXXXX: YYYYYYYYY,
(略)
}
XXXXXXXXXに既存のキーを指定したらどうなんの?
という方法です。
「content」を上書きしてみた
この方法は「context=embed」を知らなかった時に「content」(記事本文)を削除してやろうと考えていた方法なので「content」で試してみます。
add_action( 'rest_api_init', 'api_add_fields' );
function api_add_fields() {
register_rest_field( 'post',
'content',
array(
'get_callback' => 'register_fields',
'update_callback' => null,
'schema' => null,
)
);
}
function register_fields( $post, $name ) {
return null;
}
追加するAPIのキーに既存の「content」を指定し、コールバック関数でnullを返します。
出力結果↓。
"content": null,
無事に既存キーの内容を上書きできました。
「_links」も上書きできるのか?
同様に、キーを「_links」にして上書きしてみます。
add_action( 'rest_api_init', 'api_add_fields' );
function api_add_fields() {
register_rest_field( 'post',
'_links',
array(
'get_callback' => 'register_fields',
'update_callback' => null,
'schema' => null,
)
);
}
function register_fields( $post, $name ) {
return null;
}
出力結果↓。
"_links": {
"self": [
(略)
上書きできていませんでした。
試しにアンダースコアのない「links」も試しましたがダメです。
この方法では「_links」を削除できないもよう。
コピペで使えるコードまとめ
WordPressのREST APIから「_links」を削除するコードまとめです。 functions.phpに追加してください。
//アクションフックの追加
add_action('rest_prepare_post', 'remove_post_links', 10, 3);
//コールバック関数を定義
function remove_post_links($response, $post, $request) {
//linksの全要素を取得
$links = $response->get_links();
//要素をforeachで全て削除
foreach ( $links as $key => $value) {
$response->remove_link($key);
}
return $response;
}
ここだけ見る人のために一応コメントを追加しましたが、不要なら削除してください。
以上、WordPressからお届けしました!
WP REST APIカスタマイズ編の目次