概要

REST APIは、WordPressインストール内のさまざまなリソースにURIをマッチさせる方法を提供します。デフォルトでは、きれいなパーマリンクが有効になっている場合、WordPress REST APIは/wp-json/に「存在」します。私たちのWordPressサイトhttps://ourawesomesite.comでは、https://ourawesomesite.com/wp-json/GETリクエストを行うことでREST APIのインデックスにアクセスできます。このインデックスは、その特定のWordPressインストールで利用可能なルート、サポートされているHTTPメソッド、および登録されたエンドポイントに関する情報を提供します。

「こんにちは世界、これはWordPress REST APIです」というフレーズを返すエンドポイントを作成したい場合、まずそのエンドポイントのルートを登録する必要があります。ルートを登録するには、register_rest_route()関数を使用する必要があります。これはrest_api_initアクションフックで呼び出す必要があります。register_rest_route()は、ルートをエンドポイントにマッピングするすべての処理を行います。「こんにちは世界、これはWordPress REST APIです」というルートを作成してみましょう。

  1. /**
  2. * This is our callback function that embeds our phrase in a WP_REST_Response
  3. */
  4. function prefix_get_endpoint_phrase() {
  5. // rest_ensure_response() wraps the data we want to return into a WP_REST_Response, and ensures it will be properly returned.
  6. return rest_ensure_response( 'Hello World, this is the WordPress REST API' );
  7. }
  8. /**
  9. * This function is where we register our routes for our example endpoint.
  10. */
  11. function prefix_register_example_routes() {
  12. // register_rest_route() handles more arguments but we are going to stick to the basics for now.
  13. register_rest_route( 'hello-world/v1', '/phrase', array(
  14. // By using this constant we ensure that when the WP_REST_Server changes our readable endpoints will work as intended.
  15. 'methods' => WP_REST_Server::READABLE,
  16. // Here we register our callback. The callback is fired when this endpoint is matched by the WP_REST_Server class.
  17. 'callback' => 'prefix_get_endpoint_phrase',
  18. ) );
  19. }
  20. add_action( 'rest_api_init', 'prefix_register_example_routes' );

register_rest_route()に渡される最初の引数は名前空間で、ルートをグループ化する方法を提供します。渡される2番目の引数はリソースパス、またはリソースベースです。私たちの例では、取得しているリソースは「こんにちは世界、これはWordPress REST APIです」というフレーズです。3番目の引数はオプションの配列です。エンドポイントが使用できるメソッドと、エンドポイントがマッチしたときに発生するコールバックを指定します(他にも多くのことができますが、これが基本です)。

3番目の引数は、エンドポイントへのアクセスを特定のユーザーのみに制限できる権限コールバックを提供することも可能です。また、3番目の引数は、リクエストがエンドポイントの応答を変更できるように、エンドポイントの引数を登録する方法も提供します。これらの概念については、このガイドのエンドポイントセクションで詳しく説明します。

https://ourawesomesite.com/wp-json/hello-world/v1/phraseに行くと、私たちのREST APIが親切に挨拶しているのを見ることができます。ルートについてもう少し深く見てみましょう。

ルート

REST APIのルートはURIで表されます。ルート自体はhttps://ourawesomesite.com/wp-jsonの末尾に追加されるものです。APIのインデックスルートは'/'であり、これがhttps://ourawesomesite.com/wp-json/がAPIの利用可能なすべての情報を返す理由です。すべてのルートはこのルートに基づいて構築されるべきで、wp-jsonの部分は変更できますが、一般的には同じに保つことが推奨されます。

私たちは、ルートがユニークであることを確認したいです。たとえば、次のように本のルートを持つことができます: /books。私たちの本のルートはhttps://ourawesomesite.com/wp-json/booksに存在します。しかし、これは良いプラクティスではありません。なぜなら、APIの潜在的なルートを汚染してしまうからです。別のプラグインが本のルートを登録したい場合、私たちは大きな問題に直面します。なぜなら、2つのルートが互いに衝突し、1つしか使用できなくなるからです。register_rest_field()への4番目のパラメータは、ルートが既存のルートを上書きするかどうかのブール値です。

上書きパラメータは、両方のルートが上書きされる可能性があるため、私たちの問題を本当に解決するわけではありません。また、異なる目的のために両方のルートを使用したい場合もあります。これが、ルートに名前空間を使用する理由です。

名前空間

ルートに名前空間を追加することは非常に重要です。「コア」エンドポイントは、WordPressコアにマージされるのを待っていますが、/wp/v2名前空間を使用します。

コアにマージする意図でエンドポイントを作成している場合を除き、/wp名前空間に何も配置しないでください。

コアエンドポイント名前空間で注意すべき重要な点がいくつかあります。名前空間の最初の部分は/wpで、ベンダー名を表します。WordPressです。私たちのプラグインでは、名前空間のベンダー部分に対してユニークな名前を考え出す必要があります。上記の例ではhello-worldを使用しました。

ベンダー部分の後には、名前空間のバージョン部分があります。「コア」エンドポイントは、WordPress REST APIのバージョン2を表すためにv2を利用します。プラグインを作成している場合、単に新しいエンドポイントを作成し、提供するバージョン番号を上げることで、REST APIエンドポイントの後方互換性を維持できます。この方法で、元のv1v2エンドポイントの両方にアクセスできます。

名前空間に続くルートの部分はリソースパスです。

リソースパス

リソースパスは、エンドポイントが関連付けられているリソースを示す必要があります。上記の例では、phraseという単語を使用して、私たちが対話しているリソースがフレーズであることを示しました。衝突を避けるために、登録する各リソースパスは名前空間内でユニークである必要があります。リソースパスは、特定の名前空間内で異なるリソースルートを定義するために使用されるべきです。

たとえば、基本的なeコマース機能を処理するプラグインがあるとしましょう。私たちは、注文と製品という2つの主要なリソースタイプを持ちます。注文は製品のリクエストですが、製品そのものではありません。同じ概念が製品にも当てはまります。これらのリソースは関連していますが、同じものではなく、それぞれが別々のリソースパスに存在する必要があります。私たちのルートは、eコマースプラグインのために次のようになります: /my-shop/v1/orders/my-shop/v1/products

このようなルートを使用すると、各ルートが注文または製品のコレクションを返すことを望みます。特定の製品をIDで取得したい場合、ルートにパス変数を使用する必要があります。

パス変数

パス変数を使用すると、動的ルートを追加できます。eコマースルートを拡張するために、個々の製品を取得するためのルートを登録できます。

  1. /**
  2. * This is our callback function to return our products.
  3. *
  4. * @param WP_REST_Request $request This function accepts a rest request to process data.
  5. */
  6. function prefix_get_products( $request ) {
  7. // In practice this function would fetch the desired data. Here we are just making stuff up.
  8. $products = array(
  9. '1' => 'I am product 1',
  10. '2' => 'I am product 2',
  11. '3' => 'I am product 3',
  12. );
  13. return rest_ensure_response( $products );
  14. }
  15. /**
  16. * This is our callback function to return a single product.
  17. *
  18. * @param WP_REST_Request $request This function accepts a rest request to process data.
  19. */
  20. function prefix_get_product( $request ) {
  21. // In practice this function would fetch the desired data. Here we are just making stuff up.
  22. $products = array(
  23. '1' => 'I am product 1',
  24. '2' => 'I am product 2',
  25. '3' => 'I am product 3',
  26. );
  27. // Here we are grabbing the 'id' path variable from the $request object. WP_REST_Request implements ArrayAccess, which allows us to grab properties as though it is an array.
  28. $id = (string) $request['id'];
  29. if ( isset( $products[ $id ] ) ) {
  30. // Grab the product.
  31. $product = $products[ $id ];
  32. // Return the product as a response.
  33. return rest_ensure_response( $product );
  34. } else {
  35. // Return a WP_Error because the request product was not found. In this case we return a 404 because the main resource was not found.
  36. return new WP_Error( 'rest_product_invalid', esc_html__( 'The product does not exist.', 'my-text-domain' ), array( 'status' => 404 ) );
  37. }
  38. // If the code somehow executes to here something bad happened return a 500.
  39. return new WP_Error( 'rest_api_sad', esc_html__( 'Something went horribly wrong.', 'my-text-domain' ), array( 'status' => 500 ) );
  40. }
  41. /**
  42. * This function is where we register our routes for our example endpoint.
  43. */
  44. function prefix_register_product_routes() {
  45. // Here we are registering our route for a collection of products.
  46. register_rest_route( 'my-shop/v1', '/products', array(
  47. // By using this constant we ensure that when the WP_REST_Server changes our readable endpoints will work as intended.
  48. 'methods' => WP_REST_Server::READABLE,
  49. // Here we register our callback. The callback is fired when this endpoint is matched by the WP_REST_Server class.
  50. 'callback' => 'prefix_get_products',
  51. ) );
  52. // Here we are registering our route for single products. The (?P<id>[\d]+) is our path variable for the ID, which, in this example, can only be some form of positive number.
  53. register_rest_route( 'my-shop/v1', '/products/(?P<id>[\d]+)', array(
  54. // By using this constant we ensure that when the WP_REST_Server changes our readable endpoints will work as intended.
  55. 'methods' => WP_REST_Server::READABLE,
  56. // Here we register our callback. The callback is fired when this endpoint is matched by the WP_REST_Server class.
  57. 'callback' => 'prefix_get_product',
  58. ) );
  59. }
  60. add_action( 'rest_api_init', 'prefix_register_product_routes' );

上記の例は多くのことをカバーしています。重要な点は、登録する2番目のルートで、リソースパス/productsにパス変数/(?P[\d]+)を追加していることです。パス変数は正規表現です。この場合、[\d]+を使用して、少なくとも1回は数値文字である必要があることを示します。リソースに数値IDを使用している場合、これはパス変数の使用方法の優れた例です。パス変数を使用する際は、ユーザー入力であるため、何がマッチするかに注意する必要があります。

幸いにも、正規表現は数値でないものをフィルタリングします。しかし、要求されたIDの製品が存在しない場合はどうでしょうか。エラーハンドリングを行う必要があります。上記のコード例で、エラーを処理する基本的な方法を見ることができます。エンドポイントコールバックでWP_Errorを返すと、APIサーバーは自動的にエラーをクライアントに提供します。

このセクションはルートについてですが、エンドポイントについてもかなりのことをカバーしています。エンドポイントとルートは相互に関連していますが、明確な違いがあります。

エンドポイント

エンドポイントは、ルートがマッピングされる宛先です。特定のルートに対して、複数の異なるエンドポイントを登録できます。架空のeコマースプラグインを拡張して、ルートとエンドポイントの違いをよりよく示します。/wp-json/my-shop/v1/products/ルートに存在する2つのエンドポイントを作成します。1つのエンドポイントはHTTP動詞GETを使用して製品を取得し、もう1つのエンドポイントはHTTP動詞POSTを使用して新しい製品を作成します。

  1. /**
  2. * This is our callback function to return our products.
  3. *
  4. * @param WP_REST_Request $request This function accepts a rest request to process data.
  5. */
  6. function prefix_get_products( $request ) {
  7. // In practice this function would fetch the desired data. Here we are just making stuff up.
  8. $products = array(
  9. '1' =&gt; 'I am product 1',
  10. '2' =&gt; 'I am product 2',
  11. '3' =&gt; 'I am product 3',
  12. );
  13. return rest_ensure_response( $products );
  14. }
  15. /**
  16. * This is our callback function to return a single product.
  17. *
  18. * @param WP_REST_Request $request This function accepts a rest request to process data.
  19. */
  20. function prefix_create_product( $request ) {
  21. // In practice this function would create a product. Here we are just making stuff up.
  22. return rest_ensure_response( 'Product has been created' );
  23. }
  24. /**
  25. * This function is where we register our routes for our example endpoint.
  26. */
  27. function prefix_register_product_routes() {
  28. // Here we are registering our route for a collection of products and creation of products.
  29. register_rest_route( 'my-shop/v1', '/products', array(
  30. array(
  31. // By using this constant we ensure that when the WP_REST_Server changes, our readable endpoints will work as intended.
  32. 'methods' =&gt; WP_REST_Server::READABLE,
  33. // Here we register our callback. The callback is fired when this endpoint is matched by the WP_REST_Server class.
  34. 'callback' =&gt; 'prefix_get_products',
  35. ),
  36. array(
  37. // By using this constant we ensure that when the WP_REST_Server changes, our create endpoints will work as intended.
  38. 'methods' =&gt; WP_REST_Server::CREATABLE,
  39. // Here we register our callback. The callback is fired when this endpoint is matched by the WP_REST_Server class.
  40. 'callback' =&gt; 'prefix_create_product',
  41. ),
  42. ) );
  43. }
  44. add_action( 'rest_api_init', 'prefix_register_product_routes' );

ルート/wp-json/my-shop/v1/productsに使用するHTTPメソッドによって、異なるエンドポイントにマッチし、異なるコールバックが発火します。POSTを使用すると、prefix_create_product()コールバックがトリガーされ、GETを使用すると、prefix_get_products()コールバックがトリガーされます。

さまざまなHTTPメソッドがあり、REST APIはそれらのいずれかを利用できます。

HTTPメソッド

HTTPメソッドは、時々HTTP動詞と呼ばれます。これは、HTTPを介して通信するための異なる方法です。WordPress REST APIで使用される主なものは次のとおりです。

  • GETはAPIからデータを取得するために使用されるべきです。
  • POSTは新しいリソース(ユーザー、投稿、分類など)を作成するために使用されるべきです。
  • PUTはリソースを更新するために使用されるべきです。
  • DELETEはリソースを削除するために使用されるべきです。
  • OPTIONSはリソースに関するコンテキストを提供するために使用されるべきです。

これらのメソッドはすべてのクライアントによってサポートされているわけではないことに注意することが重要です。なぜなら、これらはHTTP 1.1で導入されたからです。幸いにも、APIはこれらの不幸なケースに対する回避策を提供します。リソースを削除したいがDELETEリクエストを送信できない場合、_methodパラメータまたはX-HTTP-Method-Overrideヘッダーをリクエストに使用できます。これがどのように機能するかというと、POSTリクエストをhttps://ourawesomesite.com/wp-json/my-shop/v1/products/1?_method=DELETEに送信します。これで、クライアントがリクエストで適切なHTTPメソッドを送信できなかった場合でも、製品番号1を削除することができます。あるいは、DELETEリクエストをブロックするファイアウォールが存在するかもしれません。

HTTPメソッドは、ルートとコールバックと組み合わせて、エンドポイントのコアを構成します。

コールバック

現在、REST APIでサポートされているエンドポイントのコールバックは2種類のみです。callbackpermissions_callbackです。メインコールバックはリソースとのインタラクションを処理する必要があります。権限コールバックは、どのユーザーがエンドポイントにアクセスできるかを処理する必要があります。エンドポイントを登録する際に追加情報を追加することで、追加のコールバックを追加できます。その後、rest_pre_dispatchrest_dispatch_request、またはrest_post_dispatchフックにフックして、新しいカスタムコールバックを発火させることができます。

エンドポイントコールバック

削除エンドポイントのメインコールバックは、リソースを削除し、応答にそのコピーを返すだけであるべきです。作成エンドポイントのメインコールバックは、リソースを作成し、新しく作成されたデータに一致する応答を返すだけであるべきです。更新コールバックは、実際に存在するリソースのみを変更するべきです。読み取りコールバックは、既に存在するデータのみを取得するべきです。冪等性の概念を考慮することが重要です。

REST APIの文脈における冪等性とは、エンドポイントに同じリクエストを行った場合、サーバーがリクエストを同じ方法で処理することを意味します。もし私たちの読み取りエンドポイントが冪等でなかった場合、リクエストを行うたびにサーバーの状態がリクエストによって変更されてしまい、データを取得しようとしているだけなのに、これは壊滅的な結果を招く可能性があります。誰かがサーバーからデータを取得するたびに、内部的に何かが変わることになります。読み取り、更新、削除エンドポイントが悪影響を及ぼさず、意図されたことだけを行うことを確認することが重要です。

REST APIにおける冪等性の概念は、エンドポイントコールバックではなくHTTPメソッドに結びついています。GETHEADTRACEOPTIONSPUT、またはDELETEを使用するコールバックは、いかなる副作用も生じるべきではありません。POSTリクエストは冪等ではなく、通常はリソースを作成するために使用されます。冪等な作成メソッドを作成した場合、同じリクエストを行ってもサーバーに副作用がないため、リソースは1つしか作成されません。作成の場合、同じリクエストを何度も行うと、サーバーは毎回新しいリソースを生成するべきです。

エンドポイントの使用を制限するには、権限コールバックを登録する必要があります。

権限コールバック

権限コールバックは、WordPress REST APIのセキュリティにとって非常に重要です。公開されるべきでないプライベートデータがある場合、エンドポイントに対して権限コールバックを登録する必要があります。以下は、権限コールバックを登録する方法の例です。

  1. /**
  2. * This is our callback function that embeds our resource in a WP_REST_Response
  3. */
  4. function prefix_get_private_data() {
  5. // rest_ensure_response() wraps the data we want to return into a WP_REST_Response, and ensures it will be properly returned.
  6. return rest_ensure_response( 'This is private data.' );
  7. }
  8. /**
  9. * This is our callback function that embeds our resource in a WP_REST_Response
  10. */
  11. function prefix_get_private_data_permissions_check() {
  12. // Restrict endpoint to only users who have the edit_posts capability.
  13. if ( ! current_user_can( 'edit_posts' ) ) {
  14. return new WP_Error( 'rest_forbidden', esc_html__( 'OMG you can not view private data.', 'my-text-domain' ), array( 'status' => 401 ) );
  15. }
  16. // This is a black-listing approach. You could alternatively do this via white-listing, by returning false here and changing the permissions check.
  17. return true;
  18. }
  19. /**
  20. * This function is where we register our routes for our example endpoint.
  21. */
  22. function prefix_register_example_routes() {
  23. // register_rest_route() handles more arguments but we are going to stick to the basics for now.
  24. register_rest_route( 'my-plugin/v1', '/private-data', array(
  25. // By using this constant we ensure that when the WP_REST_Server changes our readable endpoints will work as intended.
  26. 'methods' => WP_REST_Server::READABLE,
  27. // Here we register our callback. The callback is fired when this endpoint is matched by the WP_REST_Server class.
  28. 'callback' => 'prefix_get_private_data',
  29. // Here we register our permissions callback. The callback is fired before the main callback to check if the current user can access the endpoint.
  30. 'permissions_callback' => 'prefix_get_private_data_permissions_check',
  31. ) );
  32. }
  33. add_action( 'rest_api_init', 'prefix_register_example_routes' );

認証が有効でない状態でこのエンドポイントを試すと、データを見ることを防ぐためにエラー応答が返されます。認証は大きなトピックであり、最終的にはこの章の一部が作成されて、独自の認証プロセスを作成する方法を示します。

引数

エンドポイントにリクエストを行う際、応答を変更するために追加のパラメータを指定する必要がある場合があります。これらの追加パラメータは、エンドポイントを登録する際に追加できます。引数をエンドポイントで使用する方法の例を見てみましょう。

  1. /**
  2. * This is our callback function that embeds our resource in a WP_REST_Response
  3. */
  4. function prefix_get_colors( $request ) {
  5. // In practice this function would fetch the desired data. Here we are just making stuff up.
  6. $colors = array(
  7. 'blue',
  8. 'blue',
  9. 'red',
  10. 'red',
  11. 'green',
  12. 'green',
  13. );
  14. if ( isset( $request['filter'] ) ) {
  15. $filtered_colors = array();
  16. foreach ( $colors as $color ) {
  17. if ( $request['filter'] === $color ) {
  18. $filtered_colors[] = $color;
  19. }
  20. }
  21. return rest_ensure_response( $filtered_colors );
  22. }
  23. return rest_ensure_response( $colors );
  24. }
  25. /**
  26. * We can use this function to contain our arguments for the example product endpoint.
  27. */
  28. function prefix_get_color_arguments() {
  29. $args = array();
  30. // Here we are registering the schema for the filter argument.
  31. $args['filter'] = array(
  32. // description should be a human readable description of the argument.
  33. 'description' => esc_html__( 'The filter parameter is used to filter the collection of colors', 'my-text-domain' ),
  34. // type specifies the type of data that the argument should be.
  35. 'type' => 'string',
  36. // enum specified what values filter can take on.
  37. 'enum' => array( 'red', 'green', 'blue' ),
  38. );
  39. return $args;
  40. }
  41. /**
  42. * This function is where we register our routes for our example endpoint.
  43. */
  44. function prefix_register_example_routes() {
  45. // register_rest_route() handles more arguments but we are going to stick to the basics for now.
  46. register_rest_route( 'my-colors/v1', '/colors', array(
  47. // By using this constant we ensure that when the WP_REST_Server changes our readable endpoints will work as intended.
  48. 'methods' => WP_REST_Server::READABLE,
  49. // Here we register our callback. The callback is fired when this endpoint is matched by the WP_REST_Server class.
  50. 'callback' => 'prefix_get_colors',
  51. // Here we register our permissions callback. The callback is fired before the main callback to check if the current user can access the endpoint.
  52. 'args' => prefix_get_color_arguments(),
  53. ) );
  54. }
  55. add_action( 'rest_api_init', 'prefix_register_example_routes' );

この例では、filter引数を指定しました。エンドポイントをリクエストする際に、クエリパラメータとして引数を指定できます。GETリクエストをhttps://ourawesomesitem.com/my-colors/v1/colors?filter=blueに行うと、コレクション内の青い色のみが返されます。クエリ文字列の代わりにリクエストボディ内のボディパラメータとしてこれらを渡すこともできます。クエリパラメータとボディパラメータの違いを理解するには、HTTP仕様について読む必要があります。クエリパラメータはURLに追加されるクエリ文字列に存在し、ボディパラメータはHTTPリクエストのボディに直接埋め込まれます。

エンドポイントに引数を作成しましたが、引数が文字列であることを確認し、赤、緑、または青の値と一致するかどうかを判断するにはどうすればよいでしょうか。これを行うには、引数の検証コールバックを指定する必要があります。

検証

検証とサニタイズは、APIのセキュリティにとって非常に重要です。検証コールバック(WP 4.6+)は、サニタイズコールバックの前に発火します。validate_callbackを引数に使用して、受信している入力が有効かどうかを確認する必要があります。sanitize_callbackは、引数がメインコールバックによって処理される前に、引数の入力を変換したり、不要な部分を取り除いたりするために使用されるべきです。

上記の例では、filterパラメータが文字列であり、赤、緑、または青の値と一致することを確認する必要があります。validate_callbackを追加した後のコードがどのように見えるか見てみましょう。

  1. /**
  2. * This is our callback function that embeds our resource in a WP_REST_Response
  3. */
  4. function prefix_get_colors( $request ) {
  5. // In practice this function would fetch more practical data. Here we are just making stuff up.
  6. $colors = array(
  7. 'blue',
  8. 'blue',
  9. 'red',
  10. 'red',
  11. 'green',
  12. 'green',
  13. );
  14. if ( isset( $request['filter'] ) ) {
  15. $filtered_colors = array();
  16. foreach ( $colors as $color ) {
  17. if ( $request['filter'] === $color ) {
  18. $filtered_colors[] = $color;
  19. }
  20. }
  21. return rest_ensure_response( $filtered_colors );
  22. }
  23. return rest_ensure_response( $colors );
  24. }
  25. /**
  26. * Validate a request argument based on details registered to the route.
  27. *
  28. * @param mixed $value Value of the 'filter' argument.
  29. * @param WP_REST_Request $request The current request object.
  30. * @param string $param Key of the parameter. In this case it is 'filter'.
  31. * @return WP_Error|boolean
  32. */
  33. function prefix_filter_arg_validate_callback( $value, $request, $param ) {
  34. // If the 'filter' argument is not a string return an error.
  35. if ( ! is_string( $value ) ) {
  36. return new WP_Error( 'rest_invalid_param', esc_html__( 'The filter argument must be a string.', 'my-text-domain' ), array( 'status' => 400 ) );
  37. }
  38. // Get the registered attributes for this endpoint request.
  39. $attributes = $request->get_attributes();
  40. // Grab the filter param schema.
  41. $args = $attributes['args'][ $param ];
  42. // If the filter param is not a value in our enum then we should return an error as well.
  43. if ( ! in_array( $value, $args['enum'], true ) ) {
  44. return new WP_Error( 'rest_invalid_param', sprintf( __( '%s is not one of %s' ), $param, implode( ', ', $args['enum'] ) ), array( 'status' => 400 ) );
  45. }
  46. }
  47. /**
  48. * We can use this function to contain our arguments for the example product endpoint.
  49. */
  50. function prefix_get_color_arguments() {
  51. $args = array();
  52. // Here we are registering the schema for the filter argument.
  53. $args['filter'] = array(
  54. // description should be a human readable description of the argument.
  55. 'description' => esc_html__( 'The filter parameter is used to filter the collection of colors', 'my-text-domain' ),
  56. // type specifies the type of data that the argument should be.
  57. 'type' => 'string',
  58. // enum specified what values filter can take on.
  59. 'enum' => array( 'red', 'green', 'blue' ),
  60. // Here we register the validation callback for the filter argument.
  61. 'validate_callback' => 'prefix_filter_arg_validate_callback',
  62. );
  63. return $args;
  64. }
  65. /**
  66. * This function is where we register our routes for our example endpoint.
  67. */
  68. function prefix_register_example_routes() {
  69. // register_rest_route() handles more arguments but we are going to stick to the basics for now.
  70. register_rest_route( 'my-colors/v1', '/colors', array(
  71. // By using this constant we ensure that when the WP_REST_Server changes our readable endpoints will work as intended.
  72. 'methods' => WP_REST_Server::READABLE,
  73. // Here we register our callback. The callback is fired when this endpoint is matched by the WP_REST_Server class.
  74. 'callback' => 'prefix_get_colors',
  75. // Here we register our permissions callback. The callback is fired before the main callback to check if the current user can access the endpoint.
  76. 'args' => prefix_get_color_arguments(),
  77. ) );
  78. }
  79. add_action( 'rest_api_init', 'prefix_register_example_routes' );

サニタイズ

上記の例では、enum内の値のみに入力を制限しているため、sanitize_callbackを使用する必要はありません。厳密な検証がなく、任意の文字列をパラメータとして受け入れた場合、sanitize_callbackを登録する必要があります。コンテンツフィールドを更新したい場合、ユーザーがalert('ZOMG Hacking you');のようなものを入力した場合はどうでしょうか。フィールド値は実行可能なスクリプトである可能性があります。不要なデータを取り除いたり、データを希望の形式に変換したりするために、引数のためにsanitize_callbackを登録する必要があります。WordPressのsanitize_text_field()をサニタイズコールバックとして使用する方法の例を示します:

  1. /**
  2. * This is our callback function that embeds our resource in a WP_REST_Response.
  3. *
  4. * The parameter is already sanitized by this point so we can use it without any worries.
  5. */
  6. function prefix_get_item( $request ) {
  7. if ( isset( $request['data'] ) ) {
  8. return rest_ensure_response( $request['data'] );
  9. }
  10. return new WP_Error( 'rest_invalid', esc_html__( 'The data parameter is required.', 'my-text-domain' ), array( 'status' => 400 ) );
  11. }
  12. /**
  13. * Validate a request argument based on details registered to the route.
  14. *
  15. * @param mixed $value Value of the 'filter' argument.
  16. * @param WP_REST_Request $request The current request object.
  17. * @param string $param Key of the parameter. In this case it is 'filter'.
  18. * @return WP_Error|boolean
  19. */
  20. function prefix_data_arg_validate_callback( $value, $request, $param ) {
  21. // If the 'data' argument is not a string return an error.
  22. if ( ! is_string( $value ) ) {
  23. return new WP_Error( 'rest_invalid_param', esc_html__( 'The filter argument must be a string.', 'my-text-domain' ), array( 'status' => 400 ) );
  24. }
  25. }
  26. /**
  27. * Sanitize a request argument based on details registered to the route.
  28. *
  29. * @param mixed $value Value of the 'filter' argument.
  30. * @param WP_REST_Request $request The current request object.
  31. * @param string $param Key of the parameter. In this case it is 'filter'.
  32. * @return WP_Error|boolean
  33. */
  34. function prefix_data_arg_sanitize_callback( $value, $request, $param ) {
  35. // It is as simple as returning the sanitized value.
  36. return sanitize_text_field( $value );
  37. }
  38. /**
  39. * We can use this function to contain our arguments for the example product endpoint.
  40. */
  41. function prefix_get_data_arguments() {
  42. $args = array();
  43. // Here we are registering the schema for the filter argument.
  44. $args['data'] = array(
  45. // description should be a human readable description of the argument.
  46. 'description' => esc_html__( 'The data parameter is used to be sanitized and returned in the response.', 'my-text-domain' ),
  47. // type specifies the type of data that the argument should be.
  48. 'type' => 'string',
  49. // Set the argument to be required for the endpoint.
  50. 'required' => true,
  51. // We are registering a basic validation callback for the data argument.
  52. 'validate_callback' => 'prefix_data_arg_validate_callback',
  53. // Here we register the validation callback for the filter argument.
  54. 'sanitize_callback' => 'prefix_data_arg_sanitize_callback',
  55. );
  56. return $args;
  57. }
  58. /**
  59. * This function is where we register our routes for our example endpoint.
  60. */
  61. function prefix_register_example_routes() {
  62. // register_rest_route() handles more arguments but we are going to stick to the basics for now.
  63. register_rest_route( 'my-plugin/v1', '/sanitized-data', array(
  64. // By using this constant we ensure that when the WP_REST_Server changes our readable endpoints will work as intended.
  65. 'methods' => WP_REST_Server::READABLE,
  66. // Here we register our callback. The callback is fired when this endpoint is matched by the WP_REST_Server class.
  67. 'callback' => 'prefix_get_item',
  68. // Here we register our permissions callback. The callback is fired before the main callback to check if the current user can access the endpoint.
  69. 'args' => prefix_get_data_arguments(),
  70. ) );
  71. }
  72. add_action( 'rest_api_init', 'prefix_register_example_routes' );

まとめ

WordPress REST APIのエンドポイントを登録する基本をカバーしました。ルートは、エンドポイントが存在するURIです。エンドポイントは、コールバック、メソッド、引数、およびその他のオプションのコレクションです。register_rest_route()を使用する際に、各エンドポイントはルートにマッピングされます。デフォルトでは、エンドポイントはさまざまなHTTPメソッド、メインコールバック、権限コールバック、および登録された引数をサポートできます。WordPressと対話するための使用ケースをカバーするためにエンドポイントを登録できます。エンドポイントはREST APIとのコアインタラクションポイントとして機能しますが、この強力なAPIを完全に活用するために探求し理解すべき他の多くのトピックがあります。