独自APIなど不要!WordPress REST APIの軽量化/カスタマイズまとめ

シェアする:

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

  • WordPress REST APIをカスタマイズしたい人
  • REST APIを軽量化したい人
  • REST APIをカスタマイズするために独自APIを考えている人
  • つまりオレ

WordPress REST APIの軽量化/最適化/カスタマイズを何回かに渡って行ってきたので、それのまとめです。

これで一通りREST APIでやりたかったことは終えました。

当初はカスタマイズのために独自APIでの実装を考えていたんですが、結果的には必要なかったです。
(あくまで今回の目的においては)

rest_api_initでREST APIのカスタマイズ

「rest_api_init」部分では次の4つを行っています。

コードはこの↓ようになります。


//アクションフックの追加
add_action('rest_api_init', 'api_add_fields');

//コールバック関数
function api_add_fields() {
  //REST APIで自動成形(wpautop)を無効化
  remove_filter('the_content', 'wpautop');
  
  //All In One SEO PackのSEOディスクリプションを追加
  register_rest_field('post',
    'description',
     array(
      'get_callback'    => 'register_fields_description',
      'update_callback' => null,
      'schema'          => null,
    )
  );
  
  //アイキャッチ画像を追加
  register_rest_field('post',
    'thumbnails',
     array(
      'get_callback'    => 'register_fields_thumbnails',
      'update_callback' => null,
      'schema'          => null,
    )
  );
  
  //前の記事を追加
  register_rest_field( 'post',
    'prev',
     array(
      'get_callback'    => 'register_fields_prev',
      'update_callback' => null,
      'schema'          => null,
    )
  );
  
  //次の記事を追加
  register_rest_field( 'post',
    'next',
     array(
      'get_callback'    => 'register_fields_next',
      'update_callback' => null,
      'schema'          => null,
    )
  );
  
  //カテゴリを追加
  register_rest_field( 'post',
    'category',
     array(
      'get_callback'    => 'register_fields_categories',
      'update_callback' => null,
      'schema'          => null,
    )
  );
}

それぞれのコールバックについては今から説明します。

All In One SEO PackのSEOディスクリプションを追加

カスタムフィールドからAll In One SEO PackのSEOディスクリプションを取得して返すだけです。


function register_fields_description($post) {
  return get_post_meta($post['id'], '_aioseop_description', true);
}

詳しい説明はカスタムフィールド追加の記事を見てください。

アイキャッチ画像を追加


function register_fields_thumbnails($post) {
  //APIに追加する連想配列
  $data = array();
  
  //記事のアイキャッチ画像のIDを取得
  $id = get_post_thumbnail_id($post['id']);
  
  //medium、largeなどのサイズ一覧を取得
  $sizes = get_intermediate_image_sizes();
  
  //サイズ一覧にfullが含まれていなかった場合は追加
  if ( !in_array('full', $sizes) ) {
    array_push($sizes, 'full');
  }
  
  //サイズ一覧のうち、APIに含めないもの
  $ignore = array(
    'thumbnail',
    'medium',
    'medium_large',
    'large',
    '1536x1536',
    '2048x2048',
  );
  
  foreach ( $sizes as $size ) {
    //除外リストに含まれていた場合は次へ
    if ( in_array($size, $ignore) ) {
      continue;
    }
    
    //アイキャッチ画像の情報を取得
    $info = wp_get_attachment_image_src($id, $size);
    
    //未指定の場合は登録しないようにするためにif
    if ( $info ) {
      //このサイズでのアイキャッチ情報
      $current = array();
      
      //アイキャッチ画像の情報の内訳
      $current['url'] = $info[0];
      $current['width'] = $info[1];
      $current['height'] = $info[2];
      
      //返す値にこの画像情報を追加
      $data[$size] = $current;
    }
  }
  
  return $data;
}

詳しくはアイキャッチ追加の記事でやっているので、更新点・追加点だけ説明します。

get_intermediate_image_sizes()で取得したサイズ一覧にfullが含まれていなかったので追加しました。

APIのサイズ削減のため、未使用のサイズは除外リストに入れてはじくようにしました。

wp_get_attachment_image_src()の戻り値が真の時だけ登録しないと、中身が空なのに構造だけズラズラと出力したので条件分岐を入れました。

前後の記事情報を追加


//前の記事の情報
function register_fields_prev() {
  global $post;
  
  $prev = get_previous_post();
  
  return convert_post($prev);
}
//次の記事の情報
function register_fields_next() {
  global $post;
  
  $next = get_next_post();
  
  return convert_post($next);
}
//前後の記事の共通処理部分
function convert_post($post) {
  if ( $post ) {
    $data = array();
    
    $data['id'] = $post->ID;
    $data['slug'] = $post->post_name;
    $data['title'] = $post->post_title;
    
    return $data;
  }
  return null;
}

詳しい説明は前後の記事追加の記事を見てください。

カテゴリ一覧の追加


function register_fields_categories($post) {
  //記事のカテゴリ一覧を取得
  $cats = get_the_category($post['id']);
  
  $data = array();
  
  foreach ( $cats as $cat ) {
    $current = array();
    
    $current['id'] = $cat->term_id;
    $current['slug'] = $cat->slug;
    $current['name'] = $cat->name;
    
    array_push($data, $current);
  }
  
  return $data;
}

詳細はカテゴリ追加の記事に書いていますが、新しく気付いた点について。

カテゴリ情報のキーを元のAPIと同様に「categories」にしようとしました。 ところが「categories」は「context=embed」の際に除外されるのが、自前で上書きした場合にも適用されるようでembedでは出力されませんでした。

なのでキーを「category」にしています。

rest_prepare_postでAPIの軽量化

不要な要素を削除してAPIを軽量化する部分です。


//アクションフックの追加
add_action('rest_prepare_post', 'remove_post_links', 10, 3);

//コールバック関数
function remove_post_links($response, $post, $request) {
  //context=embedに含まれる不要情報の削除
  unset($response->data['type']);
  unset($response->data['link']);
  unset($response->data['excerpt']);
  unset($response->data['author']);
  unset($response->data['featured_media']);
  
  //titleの文字列化
  $response->data['title'] = $response->data['title']['rendered'];
  
  //context=viewに含まれる不要情報の削除
  unset($response->data['date_gmt']);
  unset($response->data['guid']);
  unset($response->data['modified_gmt']);
  unset($response->data['status']);
  unset($response->data['parent']);
  unset($response->data['comment_status']);
  unset($response->data['ping_status']);
  unset($response->data['sticky']);
  unset($response->data['template']);
  unset($response->data['format']);
  unset($response->data['meta']);
  unset($response->data['categories']);
  unset($response->data['tags']);
  
  //contentの文字列化
  if ( isset($response->data['content']) ) {
    $response->data['content'] = $response->data['content']['rendered'];
  }
  
  //_linksに含まれる要素を取得
  $links = $response->get_links();
  
  //_linksに含まれる要素を削除
  foreach ( $links as $key => $value) {
    $response->remove_link($key);
  }
  
  //その他の不要な要素の削除
  unset($response->data['amp_validity']);
  
  //GETのパラメータを取得
  $params = $request->get_query_params();
  
  //embedの場合は、自分で追加した要素のうち不要なものを削除
  if ( isset($params['context']) && $params['context'] == 'embed' ) {
    unset($response->data['description']);
    unset($response->data['prev']);
    unset($response->data['next']);
    unset($response->data['category']);
  }
  
  return $response;
}

処理の内容は「_links」削除の記事不要な要素削除の記事に書いています。

更新点がひとつだけ。

context=embedで不要な要素の削除

context=embedではサイズ軽量化を第一にしているので、自分でregister_rest_field()で追加したにもかかわらず4つの要素を削除しています。

本当は登録の段階で処理を振り分けるべきかなと思うんですが、いっぺんに削除する方が管理がしやすかったので上のような不細工なコードになりました。

rest_post_queryでカスタムソートの追加

WP-PostViewsの「views」など、カスタムフィールドで並び替えできるようにする部分です。


//アクションフックの追加
add_action('rest_post_query', 'sortby_meta_key', 10, 2);

//コールバック関数
function sortby_meta_key($args, $request) {
  //meta_keyがセットされていた場合にはカスタムフィールドでソート
  if ( isset($request['meta_key']) ) {
    $args['meta_key'] = $request['meta_key'];
    $args['orderby'] = 'meta_value_num';
    
    //meta_value_num以外でソートする場合はmeta_orderbyで指定
    if ( isset($request['meta_orderby']) ) {
      $args['orderby'] = $request['meta_orderby'];
    }
    
    //orderはそのまま使える
  }
  return $args;
}

これはカスタムフィールドでソートの記事のまんまです。

実は独自APIでやろうとしていたが不要になった

WordPressはですね、自分の独自APIを実装するregister_rest_routeという関数が用意されています。

既存の「投稿」や「カテゴリ」「タグ」といったAPIがカスタマイズしにくかった場合には独自APIで必要な情報だけ追加しようと考えていました。

今となってはこの目的で独自APIを使う必要性は全く感じていません。

フヨウラ!!

WordPressの範囲内で自由に追加・削除できるし、カスタムフィールドでの並べ替えも実装できたし、context=embedで記事ページと一覧ページ用のAPIも切り替えできてます。

独自APIはREST APIにないものを作りたい時だけでいいんじゃないですかね。

まとめ

コードのまとめ…は量が多すぎるのでやめます!

これでREST APIに関する勉強は一通り終わったので、後はこれを利用してWordPressのNuxt.js化の方へ戻ります!

以上、WordPressからお届けしました!

シェアする: