WordPressのREST APIから「_links」を削除する

シェアする:

この記事をおすすめしたい人

  • 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  [&hellip;]</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つ。

コールバック関数の追加

コールバック関数の基本はこの↓ような形になります。


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からお届けしました!

シェアする: