API Fetch について
WordPressのブロック開発メモ その11 REST API へのアクセス
基本的な REST API
WordPressでREST APIを使う前編
(σ・ω・)σ WordPressでREST APIを使う後編 REST APIの登録と REST コントローラ
REST API コントローラの実装
WP_REST_Controller メソッド前編
WP_REST_Controller メソッド後編 追加フィールド
WordPress REST API Controllerを実装してみる。
REST APIを公開する。
単純な例
REST APIを公開するにはregister_rest_route()
を使います。
第一引数は名前空間で任意ですが名前とバージョンの組み合わせからなります。
例えば名前をkurage-plugin
、バージョンを1とするとkurage-plugin/v1
になります。
本家では/wordpress/v2
が使われてます。
第二引数はルート名。
名前空間が/kurage-plugin/v1
でルート名がkurage
なら/kurage-plugin/v1/kurage
でアクセスできるようになります。
本体の場合は投稿ならposts
、固定ページならpages
となってます。
第三引数にオプションを定義します。
では早速実験していきます。
add_action('rest_api_init', function(){
register_rest_route(
'kurage-plugin/v1',
'/kurage',
[
'methods' => 'GET',
'callback' => function( $response )
{
$msg = 'Hello World';
return rest_ensure_response($msg);
}
]
);
});
JavaScript 標準のfetch()
関数から呼び出す場合。
await (await fetch('/wp-json/kurage-plugin/v1/kurage')).json()
ブロックエディタ開発の環境下で呼び出す場合。
await wp.apiFetch({path: '/kurage-plugin/v1/kurage' });
結果は、
Hello World
ブラウザから実行した場合は以下のようになります。
methods
でHTTPメソッドを指定します。
GET
やPOST
, DELETE
などが指定でき、また配列で複数指定するkともできます。
callback
にはレスポンスを返すコールバックを指定します。
この例では単純に文字列Hello World
を返します。
戻り値はWP_REST_Response
型を返すようにしますが、
rest_ensure_response()
を使うと変換してくれます。
すでに値がWP_REST_Response
であればそのまま返すなどの配慮がされてます、
リクエストとHTTPメソッドの定数
register_rest_route(
'kurage-plugin/v1',
'/kurage',
[
'methods' => WP_REST_Server::READABLE,
'callback' => function(WP_REST_Request $request)
{
$p1 = $request->get_param('p1');
$p2 = $request->get_param('p2');
$msg = "Hello {$p1}, {$p2}!";
return rest_ensure_response($msg);
}
]
);
以下を実行
await wp.apiFetch({
path: '/kurage-plugin/v1/kurage?p1=ikasan&p2=takosan'
});
結果
Hello ikasan, takosan!
HTTPメソッドはあらかじめクラス定数で用意してあります。
WP_REST_Server::READABLE
はGET
が設定してたります。
他にも以下の定数が定義してあります。
WP_REST_Server::CREATABLE
はPOST
WP_REST_Server::EDITABLE
はPOST, PUT, PATCH
WP_REST_Server::DELETE
はDELETE
callback
で受け取る引数はWP_REST_Request
クラスのインスタンスです。
WP_REST_Request
のget_param()
や連想配列としてクエリを取得出来ます。
正規表現
URLの一部に正規表現を使います。
register_rest_route(
'kurage-plugin/v1',
'/kurage/(\d+)',
[
'methods' => WP_REST_Server::READABLE,
'callback' => function(WP_REST_Request $r)
{
$msg = 'Hello Kurage!';
return rest_ensure_response($msg);
},
]
);
await wp.apiFetch({path: '/kurage-plugin/v1/kurage/123' });
await wp.apiFetch({path: '/kurage-plugin/v1/kurage/12x3' });
123
だと成功しますが、12x3
だと失敗します。
正規表現にマッチした部分を取得する
register_rest_route(
'kurage-plugin/v1',
'/kurage/(?P<id>\d+)',
[
'methods' => WP_REST_Server::READABLE,
'callback' => function(WP_REST_Request $r)
{
$id = $r->get_param('id');
$msg = "ID: {$id}!";
return rest_ensure_response($msg);
},
]
);
await wp.apiFetch({path: '/kurage-plugin/v1/kurage/123' });
ID: 123!
POSTを送る
register_rest_route(
'kurage-plugin/v1',
'/kurage',
[
'methods' => WP_REST_Server::CREATABLE,
'callback' => function(WP_REST_Request $request)
{
$p1 = $request->get_param('p1');
$p2 = $request->get_param('p2');
$msg = "Hello {$p1}, {$p2}!";
return rest_ensure_response($msg);
}
]
);
await wp.apiFetch({
path: '/kurage-plugin/v1/kurage'
method: 'POST',
data: { p1: 'ikasan', p2: 'takosan' }
});
HTTPメソッドをPOST
にする場合はmethods
をPOST
にします。
複数のHTTPメソッドに対応する
register_rest_route(
'kurage-plugin/v1',
'/kurage',
[
[
'methods' => WP_REST_Server::READABLE,
'callback' => function(WP_REST_Request $request)
{
$p1 = $request->get_param('p1');
$p2 = $request->get_param('p2');
$msg = "Hello READ {$p1}, {$p2}!";
return rest_ensure_response($msg);
}
],
[
'methods' => WP_REST_Server::CREATABLE,
'callback' => function(WP_REST_Request $request)
{
$p1 = $request->get_param('p1');
$p2 = $request->get_param('p2');
$msg = "Hello CREATE {$p1}, {$p2}!";
return rest_ensure_response($msg);
}
]
]
);
GET
とPOST
の二つ分定義しました。
パーミッション
アクセスに制限を設ける
register_rest_route(
'kurage-plugin/v1',
'/kurage',
[
[
'methods' => WP_REST_Server::READABLE,
'callback' => function(WP_REST_Request $request)
{
$p1 = $request->get_param('p1');
$p2 = $request->get_param('p2');
$msg = "Hello READ {$p1}, {$p2}!";
return rest_ensure_response($msg);
},
],
[
'methods' => WP_REST_Server::CREATABLE,
'callback' => function(WP_REST_Request $request)
{
$p1 = $request->get_param('p1');
$p2 = $request->get_param('p2');
$msg = "Hello CREATE {$p1}, {$p2}!";
return rest_ensure_response($msg);
},
'permission_callback' => fn() => current_user_can('dummy_manage_options'),
],
]
);
GET
はそのままアクセスできますが、
POST
はエラーになります。
権限についてはここでは触れません。
current_user_can('dummy_manage_options')
通常はdummy_manage_options
という権限は存在しないのでエラーになります。
検証
validate_callhack
を設定することで値を検証出来ます。
エラーが一つ見つかった時点で終了するのか、複数のエラーを纏めるのかは実装によりますがこの例ではエラーが一つ見つかった時点で終了します。
register_rest_route(
'kurage-plugin/v1',
'/kurage',
[
[
'methods' => WP_REST_Server::CREATABLE,
'callback' => function(WP_REST_Request $request)
{
$p1 = $request->get_param('p1');
$p2 = $request->get_param('p2');
$msg = "Hello CREATE {$p1}, {$p2}!";
return rest_ensure_response($msg);
},
// 管理者のみOK
'permission_callback' => fn() => current_user_can('manage_options'),
// 検証
'validate_callback' => function($r)
{
$p1 = $r->get_param('p1');
$p2 = $r->get_param('p2');
if(strlen($p1) < 10)
{
return new WP_Error('kurage_p1_error', 'p1 は10文字以上で!');
}
if(strlen($p2) < 10)
{
return new WP_Error('kurage_p1_error', 'p1 は10文字以上で!');
}
return true;
}
],
]
);
以下のリクエストを行います。
await wp.apiFetch({path: '/kurage-plugin/v1/kurage', method: 'POST', data: { p1: 'ikasan', p2: 'takosan'} });
この場合p1
とp2
がともに条件を満たしません。
複数エラーがあるときはどうしよう?
WP_Error
だけで工夫してみた(もっとましな方法が用意してあるのかもしれません)
'validate_callback' => function($r)
{
$p1 = $r->get_param('p1');
$p2 = $r->get_param('p2');
$error = new WP_Error('kurage_errors', 'エラー一覧');
if(strlen($p1) < 10)
{
$error->add('kurage_p1_error', 'p1 は10文字以上で!');
}
if(strlen($p2) < 10)
{
$error->add('kurage_p1_error', 'p1 は10文字以上で!');
}
// コンストラクタをnewした時点でエラーが一つ存在する
return count($error->get_error_codes()) > 1 ? $error : true;
}
argsを使った検証
register_rest_route(
'kurage-plugin/v1',
'/kurage',
[
[
'methods' => WP_REST_Server::CREATABLE,
'callback' => function(WP_REST_Request $request)
{
$p1 = $request->get_param('p1');
$p2 = $request->get_param('p2');
$msg = "Hello CREATE {$p1}, {$p2}!";
return rest_ensure_response($msg);
},
// 管理者のみOK
'permission_callback' => fn() => current_user_can('manage_options'),
// 検証
'args' =>
[
'p1' =>
[
'description' => 'P1 parameter',
'type' => 'string',
'minLength' => 10,
'maxLength' => 20
],
'p2' =>
[
'description' => 'P2 parameter',
'type' => 'string',
'enum' => ['takohachi', '8chan', 'takosuke']
]
]
],
]
);
args
の設定で検証出来ます。
description
は単にフィールドの説明、
type
は型情報で、例えばstring
に数値を渡したり、逆にinteger
に文字列を渡すとエラーになります。
minLength
は文字列が指定文字数未満だとエラーになります。
maxLength
は文字列が指定文字数を超えるとエラーになります。
enum
はそのリストのな海外も単語であればエラーになります。
argで検証
args
でvalidate_callback
を使用することもできます。
受け取る引数が違う点に注意してください。
register_rest_route(
'kurage-plugin/v1',
'/kurage',
[
[
'methods' => WP_REST_Server::CREATABLE,
'callback' => function(WP_REST_Request $request)
{
$p1 = $request->get_param('p1');
$p2 = $request->get_param('p2');
$msg = "Hello CREATE {$p1}, {$p2}!";
return rest_ensure_response($msg);
},
'args' =>
[
'p1' =>
[
'description' => 'P1 parameter',
'type' => 'string',
'validate_callback' => function($value, $request, $key)
{
return strlen($value) < 10 ?
new WP_Error('kurage_p1', '10文字以上記入してください') : true;
},
],
'p2' =>
[
'description' => 'P2 parameter',
'type' => 'string',
'validate_callback' => function($value, $request, $key)
{
return strlen($value) < 10 ?
new WP_Error('kurage_p2', '10文字以上記入してください') : true;
},
]
]
],
]
);
await wp.apiFetch({path: '/kurage-plugin/v1/kurage', method: 'POST', data: { p1: 'ikasan', p2: 'takosan'} });
第一引数が受け取った値、第二引数がWP_REST_Request
, 第三引数がフィールド名(今回はp1
やp2
)を受け取ります。
argsでサニタイズ
args
のsanitize_callback
にサニタイズ用のコールバックを指定します。
register_rest_route(
'kurage-plugin/v1',
'/kurage',
[
[
'methods' => WP_REST_Server::CREATABLE,
'callback' => function(WP_REST_Request $request)
{
$p1 = $request->get_param('p1');
$p2 = $request->get_param('p2');
$msg = "Hello CREATE {$p1}, {$p2}!";
return rest_ensure_response($msg);
},
'args' =>
[
'p1' =>
[
'description' => 'P1 parameter',
'type' => 'string',
'validate_callback' => function($value, $request, $key)
{
return strlen($value) < 10 ?
new WP_Error('kurage_p1', '10文字以上記入してください') : true;
},
'sanitize_callback' => function($value, $request, $param)
{
return sanitize_text_field($value);
}
],
'p2' =>
[
'description' => 'P2 parameter',
'type' => 'string',
'validate_callback' => function($value, $request, $key)
{
return strlen($value) < 10 ?
new WP_Error('kurage_p2', '10文字以上記入してください') : true;
},
'sanitize_callback' => function($value, $request, $param)
{
return sanitize_text_field($value);
}
]
]
],
]
);
await wp.apiFetch({
path: '/kurage-plugin/v1/kurage',
method: 'POST',
data: {
p1: 'ikasan <script>alert("attack")</script>',
p2: 'takosan <b>8chan</b>'}
}
);
Hello CREATE ikasan, takosan 8chan!
結果を見るとタグが消滅していることが確認出来ます。
REST Controllerのクラス図
まずはWP_REST_Controller
の手抜きクラス図です。
ググっても解説がほとんどなかったのでソースコードを読んでみました。
大まかには、CRUD系のメソッド、それのパーミッションチェック用のメソッド(CRUDと対)、
REST APIが返すデータの設定、追加フィールドの処理、スキーマやフィルターなどのメソッドが存在します。
登録
register_routes()
register_rest_route()
を使ってREST APIの登録を行います。
CRUD
これらのメソッドでアイテムの取得、アイテム一覧の取得、アイテムの新規作成、アイテムの更新、アイテムの削除を行います。
それとセットでパーミッションをチェックするメソッドがあります。
アイテム一覧取得
get_items( $request )
get_items_permissions_check( $request )
対象IDのアイテムの取得
get_item( $request )
get_item_permissions_check( $request )
アイテムの新規作成
create_item( $request )
create_item_permissions_check( $request )
対象IDのアイテムの更新
update_item( $request )
update_item_permissions_check( $request )
対象IDのアイテムの削除
delete_item( $request )
delete_item_permissions_check( $request )
これらは抽象メソッドにはなっておらず、実装は全てWP_Error
インスタンスを返すだけとなっております。
派生クラスではこれらをオーバーライドしCRUD及びそのパーミッションチェックを実装します。
WP_REST_Posts_Controller
の実装を見てもらえれば分かりますが、
register_rest_route()
ではこれらのメソッドとルートをマッピングします。
HTTPメソッドとルート(ID有り無しの2通り)の組合せでCRUDします。
[GET] /wp/v2/posts
get_items()
でアイテム一覧を取得します。
[POST] /wp/v2/posts
create_item()
でアイテムを新規作成します。
[GET] /posts/(?P[\d]+)
get_item()
対象IDのアイテムを一つ取得します。
[POST, PUT, PATCH] /posts/(?P[\d]+)
update_item()
で対象IDのアイテムを編集します。
[DELETE] /posts/(?P[\d]+)
delete_item()
で対象IDのアイテムを削除します。
アイテム系
リクエストから更新用オブジェクトの作成
prepare_item_for_database( $request )
派生クラスでオーバーライドします。
リクエスト(WP_REST_Request
)からアイテムの更新用オブジェクト(stdClass
)を作成します。
create_item()
やupdate_item()
から使用します。
追加や更新に必要な値だけプロパティを追加します。
リクエストからtitle
とmessage
を受け取りアイテムのオブジェクトを返す単純な例。
public function prepare_item_for_database( $request )
{
$o = new stdClass();
$o->title = $request->get_param('title');
$o->message = $request->get_param('message');
return $o;
}
実際はスキーマと照らし合わせて設定するようです。
アイテムとリクエストからレスポンスを作成
prepare_item_for_response( $item, $request )
派生クラスでオーバーライドします。
アイテムオブジェクト(投稿ならWP_Post
)とリクエスト(WP_REST_Request
)からレスポンス(WP_REST_Response
)を返します。
この値がREST APIの結果になります。
取得系からだけでなく、更新系からも使用します。
例えばREST APIで削除や追加更新を実行したらその時点でのアイテムを結果として取得出来るのはこのためです。
public function prepare_item_for_response( $item, $request ){
$data = [];
$data['title'] = $item->title;
$data['message'] = $item->message;
// 追加フィールドを実装する場合はこのメソッドで`get_callback`を実行させる
$data = $this->add_additional_fields_to_object( $data, $request );
// コンテキストによるフィルタリングを行う
$data = $this->filter_response_by_context( $data, $context );
// レスポンス化
$res = rest_ensure_response($data);
// 必要であれば $res->add_link(...) 等でリンク追加
return $res;
}
追加フィールドやフィルタリングを考慮すると結構複雑な箇所でもあります。
リンクの追加
prepare_response_for_collection( $response )
レスポンスのデータを配列化し、リンク(_links
)を追加して返します。
get_items()
内で使用される。
以下は動作の実験です。
// RESTコントローラのインスタンス作成
$controller = new class extends WP_REST_Controller
{
};
// データの作成
$obj = new stdClass();
$obj->myName = 'Kurage';
$obj->myMessage = 'Hello Kurage!';
// レスポンス化とリンクの追加(rest_ensure_response($obj)を使ってもいい)
$response = new WP_REST_Response($obj);
$response->add_link('posts', 'https://kurage/wp-json/wp/v2/posts');
$response->add_link('pages', 'https://kurage/wp-json/wp/v2/pages');
// メソッドにレスポンスを渡す
$data = $controller->prepare_response_for_collection($response);
// さてどうなる?
print_r($data);
Array
(
[myName] => Kurage
[myMessage] => Hello Kurage!
[_links] => Array
(
[posts] => Array
(
[0] => Array
(
[href] => https://kurage/wp-json/wp/v2/posts
)
)
[pages] => Array
(
[0] => Array
(
[href] => https://kurage/wp-json/wp/v2/pages
)
)
)
)
戻り値は配列化されている点に注意です。
内部では引数で渡したレスポンス(WP_REST_Response
)からデータ($response->get_data()
)を取得し配列化、
そのデータに加工されたリンク(_links
)を追加して返します。
リンクは同じくレスポンスの$response->get_links()
から取得されます。
以下は一般的なget_items()
からの利用のされ方です。
$data = [];
foreach($items as $item)
{
$res = $this->prepare_item_for_response($item);
$data[] = $this->prepare_response_for_collection($res);
}
return rest_ensure_response($data);
ほとんどの派生クラスで実装してあるのでソースコードを呼んだ方が早いと思います。
スキーマ系
ここでいうスキーマというのはJSONスキーマ
のことです。
値の型や詳細、検証情報などをJSONで定義したもので、WordPressの範囲外のことです。
PHPに限定されるものでもありません。
なので適当にJSONスキーマを先にググってみてください。
スキーマを取得
get_item_schema()
オーバーライドします。
スキーマを取得します。
結構な頻度で呼ばれるので通常はキャッシュして使うようです。
以下はJSONファイルにスキーマを記述し、REST Controllerのこのメソッドから取得する例です。
普通はPHPでJSONスキーマを記述しますが、JSONファイルを別に作ったほうがIDEのインテリセンスが効いたり便利なのでそちらの方向でいきます。
JSONファイルにJSONスキーマを記述
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "kurage",
"type": "object",
"properties": {
"nickname": {
"description": "Your Nickname",
"type": "string",
"context": [ "view" ]
},
"age": {
"description": "Your Age",
"type": "integer",
"context": [ "edit" ]
}
}
}
properties
に任意のプロパティnickname
とage
を追加しました。
context
はワードプレス側から使用されます。
PHP側の例
$controller = new class extends WP_REST_Controller
{
public function get_item_schema()
{
$schema = $this->schema ?? $this->schema = $this->createSingletonSchema();
return $this->add_additional_fields_schema($schema);
}
protected function createSingletonSchema()
{
$json = file_get_contents(dirname(__FILE__) . '/kurage-worker-ex-schema.json');
return json_decode($json, true);
}
};
print_r($controller->get_item_schema());
結果
Array
(
[$schema] => http://json-schema.org/draft-04/schema#
[title] => kurage
[type] => object
[properties] => Array
(
[nickname] => Array
(
[description] => Your Nickname
[type] => string
[context] => Array
(
[0] => view
)
)
[age] => Array
(
[description] => Your Age
[type] => integer
[context] => Array
(
[0] => edit
)
)
)
)
コードの説明。
protected function createSingletonSchema()
{
$json = file_get_contents(dirname(__FILE__) . '/kurage-worker-ex-schema.json');
return json_decode($json, true);
}
PHP側でJSONを構築してもいいのですが、どうせならJSONファイルを別に作ったほうが
VSCodeのインテリセンスも効くし楽なのでそうしました。
作ったJSONファイルはfile_get_contents()
で読み込み、json_decode()
でPHPの配列に変換します。
public function get_item_schema()
{
$schema = $this->schema ?? $this->schema = $this->createSingletonSchema();
return $this->add_additional_fields_schema($schema);
}
WP_REST_Controller::get_item_schema()
をオーバーライドします。
WP_REST_Controller
にはアクセス修飾子がprotected
な$schema
プロパティがあります。
スキーマが設定されてなければ作成し、すでに作成されていればそれを使用します。
一度作成したスキーマはリサイクルします。
ちなみにadd_additional_fields_schema($schema)
を使って追加フィールドのスキーマをマージします。
オブジェクトのタイプ
$controller = new class extends WP_REST_Controller
{
public function get_item_schema()
{
$schema = $this->schema ?? $this->schema = $this->createSingletonSchema();
return $this->add_additional_fields_schema($schema);
}
protected function createSingletonSchema()
{
$json = file_get_contents(dirname(__FILE__) . '/kurage-worker-ex-schema.json');
return json_decode($json, true);
}
public function showObjectType()
{
echo $this->get_object_type();
}
};
$schema = $controller->showObjectType();
結果
kurage
これはJSONスキーマのtitle
の項目を取得します。
パブリックスキーマ
get_public_item_schema()
スキーマのproperties
の格設定からarg_options
を省いて返します。
arg_options
はのちに出てきます。
コンテキストを取得
get_context_param( $args )
$controller = new class extends WP_REST_Controller
{
public function get_item_schema()
{
$schema = $this->schema ?? $this->schema = $this->createSingletonSchema();
return $this->add_additional_fields_schema($schema);
}
protected function createSingletonSchema()
{
$json = file_get_contents(dirname(__FILE__) . '/kurage-worker-ex-schema.json');
return json_decode($json, true);
}
};
$contexts = $controller->get_context_param();
Array
(
[description] => このリクエストが作成されたスコープ。レスポンスに含まれるフィールドはスコープにより異なります。
[type] => string
[sanitize_callback] => sanitize_key
[validate_callback] => rest_validate_request_arg
[enum] => Array
(
[0] => view
[1] => edit
)
)
enum
にview
とedit
が追加されています。
どういうことかというと、JSONスキーマの格プロパティで設定したcontext
をかき集めてます。
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "kurage",
"type": "object",
"properties": {
"nickname": {
"description": "Your Nickname",
"type": "string",
"context": [ "view" ]
},
"age": {
"description": "Your Age",
"type": "integer",
"context": [ "edit" ]
}
}
}
今回の例では、nickname
にview
が、age
にedit
が指定してあるので
それぞれの値view
とedit
の二つが取得されました。
もしJSONスキーマで以下のような設定をしているとします。
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "kurage",
"type": "object",
"properties": {
"nickname": {
"description": "Your Nickname",
"type": "string",
"context": [ "apple", "banana", "lemon" ]
},
"age": {
"description": "Your Age",
"type": "integer",
"context": [ "edit" ]
}
}
}
結果は以下のようになります。
Array
(
[description] => このリクエストが作成されたスコープ。レスポンスに含まれるフィールドはスコープにより異なります。
[type] => string
[sanitize_callback] => sanitize_key
[validate_callback] => rest_validate_request_arg
[enum] => Array
(
[0] => lemon
[1] => edit
[2] => banana
[3] => apple
)
)
view
がなくなり、変わってlemon
, banana
, apple
が出てきました。
もちろんこれら果物の単語は勝手に付けたのでコンテキストとして意味がありません。
ひな形
get_collection_params()
register_rest_route()
のargs
で使用する値のひな形を返します。
$controller = new class extends WP_REST_Controller
{
public function get_item_schema()
{
$schema = $this->schema ?? $this->schema = $this->createSingletonSchema();
return $this->add_additional_fields_schema($schema);
}
protected function createSingletonSchema()
{
$json = file_get_contents(dirname(__FILE__) . '/kurage-worker-ex-schema.json');
return json_decode($json, true);
}
};
$p = $controller->get_collection_params();
Array
(
[context] => Array
(
[description] => このリクエストが作成されたスコープ。レスポンスに含まれるフィールドはスコープにより異なります。
[type] => string
[sanitize_callback] => sanitize_key
[validate_callback] => rest_validate_request_arg
[enum] => Array
(
[0] => view
[1] => edit
)
)
[page] => Array
(
[description] => コレクションの現在のページ。
[type] => integer
[default] => 1
[sanitize_callback] => absint
[validate_callback] => rest_validate_request_arg
[minimum] => 1
)
[per_page] => Array
(
[description] => 結果として返される項目の最大数。
[type] => integer
[default] => 10
[minimum] => 1
[maximum] => 100
[sanitize_callback] => absint
[validate_callback] => rest_validate_request_arg
)
[search] => Array
(
[description] => 文字列に一致するものに結果を限定します。
[type] => string
[sanitize_callback] => sanitize_text_field
[validate_callback] => rest_validate_request_arg
)
)
page
, per_page
, search
及び、get_context_param()
の戻り値を持つcontext
が設定されたひな形的なものを返してるだけですね。
オーバーライドした派生側から呼び出すようです。
public function get_collection_params()
{
// 派生側から基底のメソッドを呼び出す。
$query_params = parent::get_collection_params();
// ...
}
以下はWP_REST_Posts_Controller
から抜粋したget_collection_params()
とget_endpoint_args_for_item_schema()
の典型的な使い方です。
register_rest_route(
$this->namespace,
'/' . $this->rest_base,
array(
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_items' ),
'permission_callback' => array( $this, 'get_items_permissions_check' ),
'args' => $this->get_collection_params(),
),
array(
'methods' => WP_REST_Server::CREATABLE,
'callback' => array( $this, 'create_item' ),
'permission_callback' => array( $this, 'create_item_permissions_check' ),
'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
),
'allow_batch' => $this->allow_batch,
'schema' => array( $this, 'get_public_item_schema' ),
)
);
GET
のargs
で使用されてます。
POST
のargs
はまた後で出てきます。
コンテキストによるフィルタリング
filter_response_by_context( $data, $context )
第一引数のデータを、スキーマに照らし合わせ、フィルタリングします。
内部ではrest_filter_response_by_context()
を呼び出してます。
主にprepare_item_for_response()
内で使用されます。
実際にはスキーマとコンテキストの二つからアイテムのデータをフィルタリングします。
$controller = new class extends WP_REST_Controller
{
public function get_item_schema()
{
$schema = $this->schema ?? $this->schema = $this->createSingletonSchema();
return $this->add_additional_fields_schema($schema);
}
protected function createSingletonSchema()
{
$json = file_get_contents(dirname(__FILE__) . '/kurage-worker-ex-schema.json');
return json_decode($json, true);
}
};
$viewContext = $controller->filter_response_by_context(
['nickname' => 'Kurako', 'age' => 123],
'view'
);
$editContext = $controller->filter_response_by_context(
['nickname' => 'Kurako', 'age' => 123],
'edit'
);
print_r($viewContext);
print_r($editContext);
結果。
Array
(
[nickname] => Kurako
)
Array
(
[age] => 123
)
どういうことかというと、JSONスキーマを見てください。
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "kurage",
"type": "object",
"properties": {
"nickname": {
"description": "Your Nickname",
"type": "string",
"context": [ "view" ]
},
"age": {
"description": "Your Age",
"type": "integer",
"context": [ "edit" ]
}
}
}
そのうえで第二引数がview
の場合を見ていきます。
$viewContext = $controller->filter_response_by_context(
['nickname' => 'Kurako', 'age' => 123],
'view'
);
第一引数の連想配列のキーを、スキーマのproperties
で設定したプロパティと照らし合わせます。
プロパティのcontext
のリスト中に、第二引数のview
が含まれないものは除外されます。
view
はnickname
には含まれますが、age
には含まれないのでage
は除外されます。
逆にedit
を指定するとage
には含まれますがnickname
には含まれないので’nickname`は除外されます。
例えば、
/wp/v2/kurage?_context=view
上記のURLがあったとすると、
アイテムのデータからcontext
にview
を含まないage
が外されて取得されるようにすることが出来ます。
詳しくはprepare_item_for_response()
の項を見てください。
スキーマ系
スキーマをargsに適用
get_endpoint_args_for_item_schema( $method = WP_REST_Server::CREATABLE )
スキーマから、スキーマで予言されているキーワードに含まれる設定をregister_rest_route()
のargs
で使用するよう変換します。
内部でrest_get_endpoint_args_for_schema()
を呼び出してます。
$controller = new class extends WP_REST_Controller
{
public function get_item_schema()
{
$schema = $this->schema ?? $this->schema = $this->createSingletonSchema();
return $this->add_additional_fields_schema($schema);
}
protected function createSingletonSchema()
{
$json = file_get_contents(dirname(__FILE__) . '/kurage-worker-ex-schema.json');
return json_decode($json, true);
}
};
$p = $controller->get_endpoint_args_for_item_schema();
$controller->get_endpoint_args_for_item_schema();
の戻り値は以下のようになります。
Array
(
[nickname] => Array
(
[validate_callback] => rest_validate_request_arg
[sanitize_callback] => rest_sanitize_request_arg
[description] => Your Nickname
[type] => string
)
[age] => Array
(
[validate_callback] => rest_validate_request_arg
[sanitize_callback] => rest_sanitize_request_arg
[description] => Your Age
[type] => integer
)
)
以下はWP_REST_Posts_Controller
から抜粋したget_collection_params()
とget_endpoint_args_for_item_schema()
の典型的な使い方です。
register_rest_route(
$this->namespace,
'/' . $this->rest_base,
array(
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_items' ),
'permission_callback' => array( $this, 'get_items_permissions_check' ),
'args' => $this->get_collection_params(),
),
array(
'methods' => WP_REST_Server::CREATABLE,
'callback' => array( $this, 'create_item' ),
'permission_callback' => array( $this, 'create_item_permissions_check' ),
'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
),
'allow_batch' => $this->allow_batch,
'schema' => array( $this, 'get_public_item_schema' ),
)
);
もう少しスキーマについて深堀していきます。
rest_get_allowed_schema_keywords()
以下の関数はスキーマの有効なキーワード一覧を取得します。
rest_get_allowed_schema_keywords()
title
description
default
type
format
enum
items
properties
additionalProperties
patternProperties
minProperties
maxProperties
minimum
maximum
exclusiveMinimum
exclusiveMaximum
multipleOf
minLength
maxLength
pattern
minItems
maxItems
uniqueItems
anyOf
oneOf
rest_get_endpoint_args_for_schema()
get_endpoint_args_for_item_schema()
は内部的にこのメソッドを呼び出しています。
スキーマで設定したプロパティ中からrest_get_allowed_schema_keywords()
のリストに含まれるプロパティを列挙します。
また以下の二つのプロパティが初期値として設定されます。
validate_callback
がrest_validate_request_arg
sanitize_callback
がrest_sanitize_request_arg
$schema = [
'$schema' => 'http://json-schema.org/draft-04/schema#',
'title' => 'kurage',
'type' => 'object',
'properties' => [
'p1' => [
'description' => 'P 1 param',
'type' => ['string', 'null'],
'enum' => ['a', 'b', 'c'],
'context' => ['view', 'edit', 'default'],
'xxx' => 'X',
'yyy' => 'Y',
'zzz' => 'Z'
],
'p2' => [
]
]
];
$args = rest_get_endpoint_args_for_schema(
$schema,
'POST'
);
p1
についてみていきましょう。
validate_callback
及びsanitize_callback
が自動的に追加されます。
またdescription
及びtype
, enum
はリストに含まれるので追加されます。
ただしcontext
及びxxx
, yyy
, zzz
はリストに含まれないので追加されません。
p2
についてはvalidate_callback
とsanitize_callback
が追加されていだけだと確認できます。
arg_options
スキーマプロパティーの中にarg_options
が入っていると特殊な動きをします。
arg_options
の一覧ががマージされます。
$schema = [
'$schema' => 'http://json-schema.org/draft-04/schema#',
'title' => 'kurage',
'type' => 'object',
'properties' => [
'p1' => [
'description' => 'P 1 param',
'type' => ['string', 'null'],
'enum' => ['a', 'b', 'c'],
'context' => ['view', 'edit', 'default'],
'xxx' => 'X',
'yyy' => 'Y',
'zzz' => 'Z',
'arg_options' => [
'maxLength' => 100,
'minLength' => 20,
'www' => 123
]
],
'p2' => [
]
]
];
$args = rest_get_endpoint_args_for_schema(
$schema,
'POST'
);
p1
を見るとarg_options
で定義したものはリストに関係なくマージされます。
maxLength
及びminLength
はリストに含まれますが、www
は含まれません。
すべてマージされていることが確認出来ます。
ただし、すべてマージ出来るのは第二引数がPOST
の時のみで、
それ以外だとrequired
とdefault
が無効になります。
これを踏まえて簡単なコントローラを実装してみます。
$controller = new class extends WP_REST_Controller
{
public function register_routes()
{
$args = $this->get_endpoint_args_for_item_schema('POST');
register_rest_route(
'/kurage-plugin/v1',
'/inoshishi',
[
[
'methods' => 'POST',
'callback' => function($request)
{
return 'xxx';
},
'args' => $args
]
]
);
}
public function get_item_schema()
{
return [
'$schema' => 'http://json-schema.org/draft-04/schema#',
'title' => 'kurage',
'type' => 'object',
'properties' => [
'p1' => [
'description' => 'P 1 param',
'type' => ['string', 'null'],
'enum' => ['a', 'b', 'c'],
'context' => ['view', 'edit', 'default'],
'xxx' => 'X',
'yyy' => 'Y',
'zzz' => 'Z',
'arg_options' => [
'maxLength' => 100,
'minLength' => 20,
'www' => 123,
'required' => true,
'default' => 'Hello'
]
],
'p2' => [
]
]
];
}
};
$controller->register_routes();
await wp.apiFetch({
path:'/kurage-plugin/v1/inoshishi',
method: 'POST',
data: { p1: '123', p2: 'b' }
})
p1 は最低20文字以上である必要があります。
とりあえarg_options
のminLength
が機能していたことがわかります。
register_rest_route()のschemaパラメータ
register_rest_route()
のパラメータのschema
はどんな状況で呼び出されるのでしょう?
この値が使用されるタイミングを調べるのめっちゃ苦労したのですが・・・。
WP_REST_Posts_Controller::register_routes()
での設定を参考にします。
register_rest_route(
$this->namespace,
'/' . $this->rest_base,
array(
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_items' ),
'permission_callback' => array( $this, 'get_items_permissions_check' ),
'args' => $this->get_collection_params(),
),
array(
'methods' => WP_REST_Server::CREATABLE,
'callback' => array( $this, 'create_item' ),
'permission_callback' => array( $this, 'create_item_permissions_check' ),
'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
),
'allow_batch' => $this->allow_batch,
'schema' => array( $this, 'get_public_item_schema' ),
)
);
schema
の項目はWP_REST_Controller::get_public_item_schema()
を参照するように設定されています。
ではそのメソッドの実装を見てみます。
public function get_public_item_schema() {
$schema = $this->get_item_schema();
if ( ! empty( $schema['properties'] ) ) {
foreach ( $schema['properties'] as &$property ) {
unset( $property['arg_options'] );
}
}
return $schema;
}
このメソッドはスキーマのプロパティからarg_options
を省くだけの単純なメソッドです。
このメソッドにブレークポイントを張って、REST APIからた叩いても引っかからなかったんですね。
await wp.apiFetch({ path:'/wp/v2/posts' })
一体どの場面で呼び出されているのだろうと。
単純でした。
特定の投稿の編集ページを開いたら引っかかりました。
どうやらREST APIで投稿(/wp/v2/posts
)では引っかからず、
管理画面からpost.php
にアクセスすると引っかかりました。
REST APIを直接たたいた時と、投稿の編集ページでは違いがあるんですね。
コールスタック(REST APIを叩くときはWP_REST_Posts_Controller::get_item()
あたりに張る)を見るとある特徴がわかりました。
共通点はWP_REST_Server::dispatch()
でして、
ここではrest_pre_dispatch
フィルターが実行されます。
フィルタにはrest_handle_options_request()
関数が登録してあります。
この関数は通常は何もせず戻り値を返すだけですが、
特定の条件ででWP_REST_Server::get_data_for_route()
を実行します。
// 第三引数はコンテキストで help を渡してます
$data = $handler->get_data_for_route( $route, $endpoints, 'help' );
特定の条件とはHTTPメソッドがOPTIONS
で、
なぜだかわかりませんがトップレベルにコールバックを指定してないことです。
このことを踏まえもう一度REST APIを叩いてみましょう。
await wp.apiFetch({path:'/wp/v2/posts', method: 'OPTIONS' })
今度は引っかかりました。
そして結果はというと・・・。
get_item_schema()
のスキーマからarg_options
が消された結果が返ってきました。
なるほど、HTTPメソッドをOPTIONS
にした時に取得するスキーマの設定なんですね。
コア開発者以外知る必要ないんでしょうがblock_editor_rest_api_preload()
関数を見ると、単にwp.apiFetch
にキャッシュさせるために呼び出されているようです。
このようにOPTIONSで取得したスキーマはOPTIONS
に配置されています。
ブラウザを見るとここで取得されたデータがJSONシリアライズされて埋め込まれていることがわかります。
以下は注意点です。
register_rest_route(
$this->namespace,
'/' . $this->rest_base,
[
// この場所でコールバックを指定したら`schema`は意味なし
// 'callback' => ...,
'allow_batch' => $this->allow_batch,
'schema' => array( $this, 'get_public_item_schema' ),
]
);
追加フィールド系
追加フィールドの実装はだいぶ複雑なので飛ばしてください。
追加フィールドの実装自体コア開発者が実装するもので、一般の開発者が知っていてもいみなさそう。
私のようなコードを理解しないと気が済まない人ようです。
get_additional_fields()
追加フィールドを取得します。
第一引数はオブジェクトタイプ(今回はkurage
)を渡しますが、スキーマを設定している場合はそちらから取得されるので省略できます。
register_rest_field(
'kurage',
'ikasan',
[
'get_callback' => function()
{
return '墨はくどー';
},
'update_callback' => function($value)
{
$v = $value;
}
]
);
register_rest_field(
'kurage',
'takosan',
[
'get_callback' => function()
{
return 'タコ殴りだべー!';
},
'update_callback' => function($value)
{
$v = $value;
}
]
);
$controller = new class extends WP_REST_Controller
{
public function register_routes()
{
$args = $this->get_endpoint_args_for_item_schema('POST');
register_rest_route(
'/kurage-plugin/v1',
'/kurage',
[
[
'methods' => 'POST',
'callback' => function($request)
{
return 'xxx';
},
'args' => $args
]
]
);
}
public function myExec()
{
// 第一引数を指定しなかったらスキーマのtitleがしようされる。
$fields = $this->get_additional_fields();
echo $fields;
}
public function get_item_schema()
{
return [
'$schema' => 'http://json-schema.org/draft-04/schema#',
'title' => 'kurage',
'type' => 'object',
'properties' => [
'p1' => [
'description' => 'P 1 param',
'type' => ['string', 'null']
],
'p2' => [
'description' => 'P 2 param',
'type' => ['string', 'null'],
]
]
];
}
};
$controller->register_routes();
$controller->myExec();
$fields = $this->get_additional_fields();
王ジェクトタイプがkurage
の追加フィールドの情報takosan
とikasan
を取得出来ました。
また追加フィールドの登録は
$args = $this->get_endpoint_args_for_item_schema('POST');
を呼び出す前に設定されていないといろいろまずいことがあります。
追加プロパティをマージする際にコードが三すくみになってしまいます。
add_additional_fields_schema( $schema )
スキーマプロパティに追加フィールドのスキーマをマージします。
register_rest_field(
'kurage',
'ikasan',
[
'get_callback' => function()
{
return '墨はくどー';
},
'update_callback' => function($value)
{
$v = $value;
},
// ここ注目
'schema' => [
'description' => 'Ika value',
'required' => true,
'type' => ['string', 'null']
]
]
);
register_rest_field(
'kurage',
'takosan',
[
'get_callback' => function()
{
return 'タコ殴りだべー!';
},
'update_callback' => function($value)
{
$v = $value;
},
// ここ注目
'schema' => [
'description' => 'Tako value',
'required' => true,
'type' => ['string', 'null']
]
]
);
$controller = new class extends WP_REST_Controller
{
public function register_routes()
{
$args = $this->get_endpoint_args_for_item_schema('POST');
/**
*
* この部分で追加フィールドの登録を行ってはいけない。
* 上のget_endpoint_args_for_item_schema()は内部get_item_schema()を取得します。
* ところがget_item_schema()で追加フィールドのスキーマをマージするコードを書いていると、
* 追加フィールドを追加する前に追加フィールドのスキーマを取得するという矛盾が生まれます。
*
*/
register_rest_route(
'/kurage-plugin/v1',
'/kurage',
[
[
'methods' => 'POST',
'callback' => function($request)
{
return rest_ensure_response( 'xxx' );
},
'permission_callback' => fn() => true,
'args' => $args
]
]
);
}
public function get_item_schema()
{
$schema = [
'$schema' => 'http://json-schema.org/draft-04/schema#',
'title' => 'kurage',
'type' => 'object',
'properties' => [
'p1' => [
'description' => 'P 1 param',
'type' => ['string', 'null']
],
'p2' => [
'description' => 'P 2 param',
'type' => ['string', 'null'],
]
]
];
$newSchema = $this->add_additional_fields_schema($schema);
return $newSchema;
}
};
$controller->register_routes();
$schema = $controller->get_item_schema();
get_item_schema()
を見てください。
この最後あたりにブレークポイントを張って$newSchema
の中身を見てみます。
ちなみに以下はvar_dump()
で得られたスキーマを吐いた結果です。
array(4) {
["$schema"]=>
string(39) "http://json-schema.org/draft-04/schema#"
["title"]=>
string(6) "kurage"
["type"]=>
string(6) "object"
["properties"]=>
array(4) {
["p1"]=>
array(2) {
["description"]=>
string(9) "P 1 param"
["type"]=>
array(2) {
[0]=>
string(6) "string"
[1]=>
string(4) "null"
}
}
["p2"]=>
array(2) {
["description"]=>
string(9) "P 2 param"
["type"]=>
array(2) {
[0]=>
string(6) "string"
[1]=>
string(4) "null"
}
}
["ikasan"]=>
array(3) {
["description"]=>
string(9) "Ika value"
["required"]=>
bool(true)
["type"]=>
array(2) {
[0]=>
string(6) "string"
[1]=>
string(4) "null"
}
}
["takosan"]=>
array(3) {
["description"]=>
string(10) "Tako value"
["required"]=>
bool(true)
["type"]=>
array(2) {
[0]=>
string(6) "string"
[1]=>
string(4) "null"
}
}
}
}
kurage
本来のプロパティはp1
とp2
だけですが、
add_additional_fields_schema()
にそのスキーマを渡すとkurage
の追加フィールドのikasan
とtakosan
がマージされているのがわかります。
ikasan
とtakosan
についてはregister_rest_field()
のオプションのschema
項目を見てください。
ikasan
もtakosan
もrequired
がtrue
なので必須です。
以下がエラーになるのが確認できます。
await wp.apiFetch({
path:'/kurage-plugin/v1/kurage',
method: 'POST',
data: { p1: '123', p2: 'b' }
})
まずikasan
とtakosan
が設定されてないとエラーが出たら期待した結果です。
以下は成功します。
await wp.apiFetch({
path:'/kurage-plugin/v1/kurage',
method: 'POST',
data: {
p1: '123',
p2: 'b',
takosan: 'takotako',
ikasan: 'ikaika'
}
})
add_additional_fields_to_object( $prepared, $request )
アイテムを取得する際に追加フィールドの値を設定するためのメソッドです。
基本的にprepare_item_for_response()
内で実行します。
register_rest_field(
'kurage',
'ikasan',
[
'get_callback' => function()
{
return '墨はくどー';
},
'update_callback' => function($value)
{
$v = $value;
},
'schema' => [
'description' => 'Ika value',
'required' => true,
'type' => ['string', 'null']
]
]
);
register_rest_field(
'kurage',
'takosan',
[
'get_callback' => function()
{
return 'タコ殴りだべー!';
},
'update_callback' => function($value)
{
$v = $value;
},
'schema' => [
'description' => 'Tako value',
'required' => true,
'type' => ['string', 'null']
]
]
);
$controller = new class extends WP_REST_Controller
{
public function register_routes()
{
$args = $this->get_endpoint_args_for_item_schema('POST');
register_rest_route(
'/kurage-plugin/v1',
'/kurage',
[
[
'methods' => 'POST',
'callback' => function($request)
{
return rest_ensure_response( 'xxx' );
},
'permission_callback' => fn() => true,
'args' => $args
]
]
);
// [GET] /kurage-plugin/kurage/(?P<id>\d+) を追加
register_rest_route(
'/kurage-plugin/v1',
'/kurage/(?P<id>\d+)',
[
[
'methods' => 'GET',
'callback' => [$this, 'get_item']
],
'args' => [
'description' => 'kurage ID',
'type' => 'integer'
]
]
);
}
public function get_item($request)
{
$id = $request->get_param('id');
// DBからデータを取ったつもり
$o = new stdClass();
$o->p1 = 'p1 value';
$o->p2 = 'p2 value';
// アイテムの前準備
$data = $this->prepare_item_for_response($o, $request);
return rest_ensure_response($data);
}
public function prepare_item_for_response($item, $request)
{
// アイテムを配列に戻す
$data = [];
$data['p1'] = $item->p1;
$data['p2'] = $item->p2;
// 追加フィールドの値を追加
$data = $this->add_additional_fields_to_object($data, $request);
return rest_ensure_response($data);
}
public function get_item_schema()
{
$schema = [
'$schema' => 'http://json-schema.org/draft-04/schema#',
'title' => 'kurage',
'type' => 'object',
'properties' => [
'p1' => [
'description' => 'P 1 param',
'type' => ['string', 'null']
],
'p2' => [
'description' => 'P 2 param',
'type' => ['string', 'null'],
]
]
];
$newSchema = $this->add_additional_fields_schema($schema);
return $newSchema;
}
};
$controller->register_routes();
await wp.apiFetch({path:'/kurage-plugin/v1/kurage/123' })
kurage
アイテムの結果(p1
, p2
)に
追加プロパティ(ikasan
, takosan
)がマージされていることが確認できます。
これら追加プロパティの値はregister_rest_field()
で設定したget_callback
コールバックを呼び出します。
$data = $this->add_additional_fields_to_object($data, $request);
protected function update_additional_fields_for_object( $object, $request )
create_item()
やupdate_item()
から呼び出します。
今回はcreate_item()
だけ実装。
$database = [];
function setDb($key, $value)
{
global $database;
$database[$key] = $value;
}
function getDb($key)
{
global $database;
return $database[$key];
}
register_rest_field(
'kurage',
'ikasan',
[
'get_callback' => function()
{
return getDb('ikasan');
},
'update_callback' => function($value)
{
setDb('ikasan', $value);
},
'schema' => [
'description' => 'Ika value',
'required' => true,
'type' => ['string', 'null']
]
]
);
register_rest_field(
'kurage',
'takosan',
[
'get_callback' => function()
{
return getDb('takosan');
},
'update_callback' => function($value)
{
setDb('takosan', $value);
},
'schema' => [
'description' => 'Tako value',
'required' => true,
'type' => ['string', 'null']
]
]
);
$controller = new class extends WP_REST_Controller
{
public function register_routes()
{
$args = $this->get_endpoint_args_for_item_schema('POST');
register_rest_route(
'/kurage-plugin/v1',
'/kurage',
[
[
'methods' => 'POST',
'callback' => [$this, 'create_item'],
'permission_callback' => fn() => true,
'args' => $args
]
]
);
}
public function create_item( $request )
{
// アイテムのオブジェクトを取得
$kurage = $this->prepare_item_for_database($request);
if( is_wp_error($kurage) )
{
return $kurage;
}
// $kurageをDBに保存
// 登録した`update_callback`を実行
$r = $this->update_additional_fields_for_object($kurage, $request);
if( is_wp_error($r) )
{
return $r;
}
// レスポンス作成
$response = $this->prepare_item_for_response($kurage, $request);
$response = rest_ensure_response($response);
$response->set_status(201);
return $response;
}
protected function prepare_item_for_database($request)
{
$o = new stdClass;
$o->p1 = $request->get_param('p1');
$o->p2 = $request->get_param('p2');
return $o;
}
public function prepare_item_for_response($item, $request)
{
// アイテムを配列に戻す
$data = [];
$data['p1'] = $item->p1;
$data['p2'] = $item->p2;
// 追加フィールドの値を追加
$data = $this->add_additional_fields_to_object($data, $request);
return rest_ensure_response($data);
}
public function get_item_schema()
{
$schema = [
'$schema' => 'http://json-schema.org/draft-04/schema#',
'title' => 'kurage',
'type' => 'object',
'properties' => [
'p1' => [
'description' => 'P 1 param',
'type' => ['string', 'null']
],
'p2' => [
'description' => 'P 2 param',
'type' => ['string', 'null'],
]
]
];
$newSchema = $this->add_additional_fields_schema($schema);
return $newSchema;
}
};
$controller->register_routes();
await wp.apiFetch({
path:'/kurage-plugin/v1/kurage',
method: 'POST',
data: {
p1: '123',
p2: 'b',
takosan: 'takotako',
ikasan: 'ikaika'
}
})
以下の例はkurage
の追加フィールド(ikasan
及びtakosan
)のupdate_callback
を実行します。
$r = $this->update_additional_fields_for_object($kurage, $request);
今回は永続化をイメージするためsetDb()
とgetD()
を用意しました。
もちろん永続化されるわけもなく、また特定のアイテムのIDに紐づけられるものでもありません。
あくまでこのメソッドの動作を確認するためだけのコードです。
その他
- sanitize_slug( $slug )
内部でsanitize_title()
を実行して返します。