
WP REST APIで独自エンドポイントにパラメーターを使ってキーワード検索や個別記事を取得できるようにする
WordPressでは搭載されているCMS機能で投稿したデータをテーマと呼ばれるサイトテンプレートに含まれるページに出力されることが一般的ですが、最近はヘッドレスCMSという形で、APIを使うことで投稿データを非同期で取得しフロントエンド側で投稿データを展開するというケースも増えてきているようです。今回はそのようなケースで使える投稿データ取得用のエンドポイントのカスタマイズで、パラメーターの指定に対応させて、キーワード検索や個別記事を取得できるようにしていきたいと思います。
以前の記事でもエンドポイントのカスタマイズやパラメーターを使ったAPI経由での投稿データ取得についてまとめていますので合わせてご参考にどうぞ。
(参考記事)
・WP REST APIで独自エンドポイントのカスタマイズで投稿記事を全件取得できるようにする
・WP REST APIでクエリパラメーターを操作してWordPressの投稿データをリストで取得する
今回はWP REST APIのエンドポイントをカスタマイズして、キーワード検索や個別投稿とその前後の投稿を取得できるようにカスタマイズしてみました。ヘッドレスCMSで運用する場合、様々な検索条件をフロントエンド側で実装する必要がありますが、とりあえず全記事取得して、すべてフロントエンド側で検索したりするのはあまり効率良くありませんので、できるだけバックエンド側で済ませておきたいですね。
複数の投稿タイプで全投稿対象のキーワード検索APIのエンドポイント
まずはブログサイトやメディアサイトでよく見かけるキーワード検索です。WordPressでも専用のクエリが用意されており、APIではデフォルトのエンドポイントで下記の通り使えます。https://exapmle.com/wp-json/wp/v2/POST_TYPE?search=KEYWORDただし、これだと特定の投稿タイプに限定されるのと、取得できるデータが最大10件までという制限があります。そこで独自のエンドポイントを作成していきます。 まずは、register_rest_route()関数で、APIのエンドポイントを定義していきます。第一引数と第二引数でURLを指定するのですが、第二引数の方でパラメーターが入るように設定しています。今回はキーワード文字列が入る想定ですので「クエリ変数」を定義します。ここでは「keywords」という変数名を使えるようにして、正規表現で値を指定します。今回はWordPressの検索クエリを参考にしています。その他はこれまでのエンドポイントの作成方法と同じような感じで進めていきます。
function add_rest_endpoint_all_posts_search() {
register_rest_route(
'wp/api',
'/search/(?P<keywords>.*?("|$)|((?<=[\t ",+])|^)[^\t ",+]+)',
array(
'methods' => 'GET',
'callback' => 'get_all_posts_search',
'permission_callback' => function() { return true; }
)
);
}
function get_all_posts_search($parameter) {
$args = array(
'posts_per_page' => -1,
'post_type' => array( 'post', 'page', 'blog', 'news' ),
's' => urldecode($parameter['keywords']),
'post_status' => 'publish'
);
$query = new WP_Query($args);
$all_posts = $query->posts;
$result = array();
foreach($all_posts as $post) {
$category = '';
if($post->post_type === 'post') {
$category = get_the_terms($post->ID, 'category')[0]->name;
} else if($post->post_type === 'blog') {
$category = get_the_terms($post->ID, 'blog_category')[0]->name;
} else if($post->post_type === 'news') {
$category = get_the_terms($post->ID, 'news_category')[0]->name;
}
$data = array(
'ID' => $post->ID,
'thumbnail' => get_the_post_thumbnail_url($post->ID, 'full'),
'slug' => $post->post_name,
'date' => $post->post_date,
'modified' => $post->post_modified,
'title' => $post->post_title,
'excerpt' => $post->post_excerpt,
'content' => $post->post_content,
'category' => $category,
'post_type' => $post_type
);
array_push($result, $data);
};
return $result;
}
add_action('rest_api_init', 'add_rest_endpoint_all_posts_search');
続いてキーワード検索のクエリを作成していきます。コールバック関数の引数に先ほど定義したクエリ変数の値が入るようにしておきます。今回はget_posts()ではなく、キーワード検索のパラメーターが使えるWP_Query()の方で対応しています。キーワード検索用のパラメーターの値に先ほどの検索キーワード用のクエリ変数が格納されるようにします。ここで少しハマったのですが、全角文字が入る場合には文字列がエンコードされてしまい、正しく検索できないため「urldecode()」関数でデコードされた文字列が入るようにしておきます。
ここでは取得データを整理した上で配列にして返していますが、そのままの投稿データで取得する場合はクエリの結果をそのまま返してあげるだけでOKです。これで下記のURLにアクセス(GETメソッド)を実行すると、キーワードに対応したデータが返ってきます。
https://exapmle.com/wp-json/wp/api/search/KEYWORD続いてもう少しシンプルな形の、パラメーターにIDが入るパターンを見ていきます。
ID指定の個別投稿(&前後の投稿)取得APIのエンドポイント
先ほどのキーワード検索と同じ要領で、個別のIDで指定した投稿データを取得できるようにしていきます。個別記事ページをフロント側で作る場合には必要になってきます。もちろんデフォルトのAPIのエンドポイントにも下記のように用意されています。https://exapmle.com/wp-json/wp/v2/POST_TYPE/POST_IDデフォルトのエンドポイントでは取得できる最大件数が10件までという制約はありますが、ここでは個別で1件の投稿だけとなるので特に問題はなさそうです。ただし、要件によっては前後の投稿にアクセスできるようページャーの設置が求められる場面もあります。そのためやはり独自のエンドポイントを設定しておく方が良さそうですね。 同じようにエンドポイントの設定でクエリ変数を使って、コールバック関数である投稿取得のクエリ処理に、idという変数名のクエリ変数を定義してパラメーターを渡せるようにしておきます。その他は先ほどと同じようにクエリ処理を作成していきます。
function add_rest_endpoint_single_posts() {
register_rest_route(
'wp/api',
'/blog/(?P<id>[\d]+)',
array(
'methods' => 'GET',
'callback' => 'get_single_posts',
'permission_callback' => function() { return true; }
)
);
}
function get_single_posts($parameter) {
$args_all = array(
'posts_per_page' => -1,
'post_type' => 'blog',
'post_status' => 'publish',
'orderby' => 'date',
'order' => 'DESC',
);
$all_posts = get_posts($args_all);
$all_posts_ids = array();
foreach($all_posts as $post) {
array_push($all_posts_ids, $post->ID);
}
$args_single = array(
'posts_per_page' => 1,
'post_type' => 'blog',
'post_status' => 'publish',
'include' => $parameter[id]
);
$single_post = get_posts($args_single);
$single_post_index = !empty($single_post) ? array_search((int) $parameter[id], $all_posts_ids, true) : -2;
$prev_post_id = $single_post_index < count($all_posts_ids) - 1 ? $single_post_index + 1 : null;
$next_post_id = !is_null($single_post_index) && ($single_post_index > 0) ? $single_post_index - 1 : null;
$targets = array($all_posts[$next_post_id], $single_post[0], $all_posts[$prev_post_id]);
$result = array();
foreach($targets as $post) {
$data = array(
'ID' => $post->ID,
'thumbnail' => get_the_post_thumbnail_url($post->ID, 'full'),
'slug' => $post->post_name,
'date' => $post->post_date,
'modified' => $post->post_modified,
'title' => $post->post_title,
'excerpt' => $post->post_excerpt,
'content' => $post->post_content,
'category' => get_the_terms($post->ID, 'blog_category')[0]->name,
);
array_push($result, $data);
};
return $result;
}
add_action('rest_api_init', 'add_rest_endpoint_single_posts');
そして投稿データを取得していく処理を書いていきます。個別記事だけであればIDをもとに1件だけ取得する内容でOKですが、今回は前後の投稿記事も取得するため、一旦全部の記事も合わせて取得しておきます。このあたりについて詳しくは前回記事「WordPressでget_posts()などを使って配列に格納された投稿から特定の投稿とその前後の投稿を取得する」にまとめていますのでご参考に。
これで下記のURLにアクセスすると、パラメーターで指定したIDに対応する個別投稿データと、その前後に投稿された個別投稿データがそれぞれ取得できました。
https://exapmle.com/wp-json/wp/api/blog/POST_ID
今回はWP REST APIのエンドポイントをカスタマイズして、キーワード検索や個別投稿とその前後の投稿を取得できるようにカスタマイズしてみました。ヘッドレスCMSで運用する場合、様々な検索条件をフロントエンド側で実装する必要がありますが、とりあえず全記事取得して、すべてフロントエンド側で検索したりするのはあまり効率良くありませんので、できるだけバックエンド側で済ませておきたいですね。
categories
- WordPress(61)
- JavaScript(49)
- Vue.js(48)
- CSS(46)
- jQuery(34)
- Nuxt.js(22)
- Sass(21)
- Gulp(17)
- webpack(16)
- PHP(14)
- HTML(14)
- GSAP(11)
- React(10)
- Vite(9)
- Pug(9)
- Laravel(8)
- Cordova(8)
- Linux(7)
- Next.js(6)
- Apache(5)
- Shopify(4)
- REST API(4)
- Node.js(4)
- Smarty(3)
- Git(3)
- JSON(3)
- その他プログラミング(3)
- Google Apps API(3)
- Bootstrap(3)
- 環境構築・システム(3)
- TypeScript(2)
- EJS(2)
- RMS(2)
- Docker(2)
- Instagram API(2)
- Excel VBA(2)
- SVG(1)
- Dart(1)
- ECカートASP(1)
- Markdown(1)
- AMP(1)
- Nginx(1)
- XML(1)
- shellscript(1)
- Ruby(1)
- MySQL(1)