| [ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * REST API list controller for Abilities API. 4 * 5 * @package WordPress 6 * @subpackage Abilities_API 7 * @since 6.9.0 8 */ 9 10 declare( strict_types = 1 ); 11 12 /** 13 * Core controller used to access abilities via the REST API. 14 * 15 * @since 6.9.0 16 * 17 * @see WP_REST_Controller 18 */ 19 class WP_REST_Abilities_V1_List_Controller extends WP_REST_Controller { 20 21 /** 22 * REST API namespace. 23 * 24 * @since 6.9.0 25 * @var string 26 */ 27 protected $namespace = 'wp-abilities/v1'; 28 29 /** 30 * REST API base route. 31 * 32 * @since 6.9.0 33 * @var string 34 */ 35 protected $rest_base = 'abilities'; 36 37 /** 38 * Registers the routes for abilities. 39 * 40 * @since 6.9.0 41 * 42 * @see register_rest_route() 43 */ 44 public function register_routes(): void { 45 register_rest_route( 46 $this->namespace, 47 '/' . $this->rest_base, 48 array( 49 array( 50 'methods' => WP_REST_Server::READABLE, 51 'callback' => array( $this, 'get_items' ), 52 'permission_callback' => array( $this, 'get_items_permissions_check' ), 53 'args' => $this->get_collection_params(), 54 ), 55 'schema' => array( $this, 'get_public_item_schema' ), 56 ) 57 ); 58 59 register_rest_route( 60 $this->namespace, 61 '/' . $this->rest_base . '/(?P<name>[a-zA-Z0-9\-\/]+)', 62 array( 63 'args' => array( 64 'name' => array( 65 'description' => __( 'Unique identifier for the ability.' ), 66 'type' => 'string', 67 'pattern' => '^[a-zA-Z0-9\-\/]+$', 68 ), 69 ), 70 array( 71 'methods' => WP_REST_Server::READABLE, 72 'callback' => array( $this, 'get_item' ), 73 'permission_callback' => array( $this, 'get_item_permissions_check' ), 74 ), 75 'schema' => array( $this, 'get_public_item_schema' ), 76 ) 77 ); 78 } 79 80 /** 81 * Retrieves all abilities. 82 * 83 * @since 6.9.0 84 * 85 * @param WP_REST_Request $request Full details about the request. 86 * @return WP_REST_Response Response object on success. 87 */ 88 public function get_items( $request ) { 89 $query_args = array( 90 'meta' => array( 'show_in_rest' => true ), 91 ); 92 93 if ( ! empty( $request['category'] ) ) { 94 $query_args['category'] = $request['category']; 95 } 96 97 if ( ! empty( $request['namespace'] ) ) { 98 $query_args['namespace'] = $request['namespace']; 99 } 100 101 if ( ! empty( $request['meta'] ) ) { 102 // Merge caller meta first so the forced show_in_rest filter wins. This keeps a caller from using meta to reveal abilities hidden from REST. 103 $query_args['meta'] = array_merge( $request['meta'], $query_args['meta'] ); 104 } 105 106 $abilities = wp_get_abilities( $query_args ); 107 108 $page = $request['page']; 109 $per_page = $request['per_page']; 110 $offset = ( $page - 1 ) * $per_page; 111 112 $total_abilities = count( $abilities ); 113 $max_pages = (int) ceil( $total_abilities / $per_page ); 114 115 if ( $request->get_method() === 'HEAD' ) { 116 $response = new WP_REST_Response( array() ); 117 } else { 118 $abilities = array_slice( $abilities, $offset, $per_page ); 119 120 $data = array(); 121 foreach ( $abilities as $ability ) { 122 $item = $this->prepare_item_for_response( $ability, $request ); 123 $data[] = $this->prepare_response_for_collection( $item ); 124 } 125 126 $response = rest_ensure_response( $data ); 127 } 128 129 $response->header( 'X-WP-Total', (string) $total_abilities ); 130 $response->header( 'X-WP-TotalPages', (string) $max_pages ); 131 132 $query_params = $request->get_query_params(); 133 $base = add_query_arg( urlencode_deep( $query_params ), rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ) ); 134 135 if ( $page > 1 ) { 136 $prev_page = $page - 1; 137 $prev_link = add_query_arg( 'page', $prev_page, $base ); 138 $response->link_header( 'prev', $prev_link ); 139 } 140 141 if ( $page < $max_pages ) { 142 $next_page = $page + 1; 143 $next_link = add_query_arg( 'page', $next_page, $base ); 144 $response->link_header( 'next', $next_link ); 145 } 146 147 return $response; 148 } 149 150 /** 151 * Retrieves a specific ability. 152 * 153 * @since 6.9.0 154 * 155 * @param WP_REST_Request $request Full details about the request. 156 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. 157 */ 158 public function get_item( $request ) { 159 $ability = wp_get_ability( $request['name'] ); 160 if ( ! $ability || ! $ability->get_meta_item( 'show_in_rest' ) ) { 161 return new WP_Error( 162 'rest_ability_not_found', 163 __( 'Ability not found.' ), 164 array( 'status' => 404 ) 165 ); 166 } 167 168 $data = $this->prepare_item_for_response( $ability, $request ); 169 return rest_ensure_response( $data ); 170 } 171 172 /** 173 * Checks if a given request has access to read ability items. 174 * 175 * @since 6.9.0 176 * 177 * @param WP_REST_Request $request Full details about the request. 178 * @return bool True if the request has read access. 179 */ 180 public function get_items_permissions_check( $request ) { 181 return current_user_can( 'read' ); 182 } 183 184 /** 185 * Checks if a given request has access to read an ability item. 186 * 187 * @since 6.9.0 188 * 189 * @param WP_REST_Request $request Full details about the request. 190 * @return bool True if the request has read access. 191 */ 192 public function get_item_permissions_check( $request ) { 193 return current_user_can( 'read' ); 194 } 195 196 /** 197 * Prepares an ability for response. 198 * 199 * @since 6.9.0 200 * 201 * @param WP_Ability $ability The ability object. 202 * @param WP_REST_Request $request Request object. 203 * @return WP_REST_Response Response object. 204 */ 205 public function prepare_item_for_response( $ability, $request ) { 206 $data = array( 207 'name' => $ability->get_name(), 208 'label' => $ability->get_label(), 209 'description' => $ability->get_description(), 210 'category' => $ability->get_category(), 211 'input_schema' => wp_prepare_json_schema_for_client( $ability->get_input_schema() ), 212 'output_schema' => wp_prepare_json_schema_for_client( $ability->get_output_schema() ), 213 'meta' => $ability->get_meta(), 214 ); 215 216 $context = $request['context'] ?? 'view'; 217 $data = $this->add_additional_fields_to_object( $data, $request ); 218 $data = $this->filter_response_by_context( $data, $context ); 219 220 $response = rest_ensure_response( $data ); 221 222 $fields = $this->get_fields_for_response( $request ); 223 if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) { 224 $links = array( 225 'self' => array( 226 'href' => rest_url( sprintf( '%s/%s/%s', $this->namespace, $this->rest_base, $ability->get_name() ) ), 227 ), 228 'collection' => array( 229 'href' => rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ), 230 ), 231 ); 232 233 $links['wp:action-run'] = array( 234 'href' => rest_url( sprintf( '%s/%s/%s/run', $this->namespace, $this->rest_base, $ability->get_name() ) ), 235 ); 236 237 $response->add_links( $links ); 238 } 239 240 return $response; 241 } 242 243 /** 244 * Retrieves the ability's schema, conforming to JSON Schema. 245 * 246 * @since 6.9.0 247 * 248 * @return array<string, mixed> Item schema data. 249 */ 250 public function get_item_schema(): array { 251 $schema = array( 252 '$schema' => 'http://json-schema.org/draft-04/schema#', 253 'title' => 'ability', 254 'type' => 'object', 255 'properties' => array( 256 'name' => array( 257 'description' => __( 'Unique identifier for the ability.' ), 258 'type' => 'string', 259 'context' => array( 'view', 'edit', 'embed' ), 260 'readonly' => true, 261 ), 262 'label' => array( 263 'description' => __( 'Display label for the ability.' ), 264 'type' => 'string', 265 'context' => array( 'view', 'edit', 'embed' ), 266 'readonly' => true, 267 ), 268 'description' => array( 269 'description' => __( 'Description of the ability.' ), 270 'type' => 'string', 271 'context' => array( 'view', 'edit' ), 272 'readonly' => true, 273 ), 274 'category' => array( 275 'description' => __( 'Ability category this ability belongs to.' ), 276 'type' => 'string', 277 'context' => array( 'view', 'edit', 'embed' ), 278 'readonly' => true, 279 ), 280 'input_schema' => array( 281 'description' => __( 'JSON Schema for the ability input.' ), 282 'type' => 'object', 283 'context' => array( 'view', 'edit' ), 284 'readonly' => true, 285 ), 286 'output_schema' => array( 287 'description' => __( 'JSON Schema for the ability output.' ), 288 'type' => 'object', 289 'context' => array( 'view', 'edit' ), 290 'readonly' => true, 291 ), 292 'meta' => array( 293 'description' => __( 'Meta information about the ability.' ), 294 'type' => 'object', 295 'properties' => array( 296 'annotations' => array( 297 'description' => __( 'Behavioral annotations for the ability.' ), 298 'type' => 'object', 299 'properties' => array( 300 'readonly' => array( 301 'description' => __( 'Whether the ability does not modify its environment.' ), 302 'type' => array( 'boolean', 'null' ), 303 ), 304 'destructive' => array( 305 'description' => __( 'Whether the ability may perform destructive updates to its environment.' ), 306 'type' => array( 'boolean', 'null' ), 307 ), 308 'idempotent' => array( 309 'description' => __( 'Whether repeated calls with the same arguments have no additional effect.' ), 310 'type' => array( 'boolean', 'null' ), 311 ), 312 ), 313 'additionalProperties' => true, 314 ), 315 ), 316 'context' => array( 'view', 'edit' ), 317 'readonly' => true, 318 ), 319 ), 320 ); 321 322 return $this->add_additional_fields_schema( $schema ); 323 } 324 325 /** 326 * Retrieves the query params for collections. 327 * 328 * @since 6.9.0 329 * 330 * @return array<string, mixed> Collection parameters. 331 */ 332 public function get_collection_params(): array { 333 $query_params = array( 334 'context' => $this->get_context_param( array( 'default' => 'view' ) ), 335 'page' => array( 336 'description' => __( 'Current page of the collection.' ), 337 'type' => 'integer', 338 'default' => 1, 339 'minimum' => 1, 340 ), 341 'per_page' => array( 342 'description' => __( 'Maximum number of items to be returned in result set.' ), 343 'type' => 'integer', 344 'default' => 50, 345 'minimum' => 1, 346 'maximum' => 100, 347 ), 348 'category' => array( 349 'description' => __( 'Limit results to abilities in specific ability category.' ), 350 'type' => 'string', 351 'sanitize_callback' => 'sanitize_key', 352 'validate_callback' => 'rest_validate_request_arg', 353 ), 354 'namespace' => array( 355 'description' => __( 'Limit results to abilities in a specific namespace.' ), 356 'type' => 'string', 357 'sanitize_callback' => 'sanitize_key', 358 'validate_callback' => 'rest_validate_request_arg', 359 ), 360 'meta' => array( 361 'description' => __( 'Limit results to abilities matching all of the given meta fields.' ), 362 'type' => 'object', 363 'properties' => array( 364 // show_in_rest is omitted on purpose. It is forced on and cannot be filtered by a caller. 365 'annotations' => array( 366 'description' => __( 'Limit results to abilities matching the given behavioral annotations.' ), 367 'type' => 'object', 368 'properties' => array( 369 'readonly' => array( 370 'description' => __( 'Whether the ability does not modify its environment.' ), 371 'type' => array( 'boolean', 'null' ), 372 ), 373 'destructive' => array( 374 'description' => __( 'Whether the ability may perform destructive updates to its environment.' ), 375 'type' => array( 'boolean', 'null' ), 376 ), 377 'idempotent' => array( 378 'description' => __( 'Whether repeated calls with the same arguments have no additional effect.' ), 379 'type' => array( 'boolean', 'null' ), 380 ), 381 ), 382 'additionalProperties' => true, 383 ), 384 ), 385 'additionalProperties' => true, 386 ), 387 ); 388 389 /** 390 * Filters REST API collection parameters for the abilities controller. 391 * 392 * Use this to declare the schema type of a custom meta key. A declared 393 * type lets REST coerce a query-string value, for example "true" to a 394 * boolean, before the meta filter matches it. 395 * 396 * @since 7.1.0 397 * 398 * @param array $query_params JSON Schema-formatted collection parameters. 399 */ 400 return apply_filters( 'rest_abilities_collection_params', $query_params ); 401 } 402 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated : Sun Jul 5 08:20:13 2026 | Cross-referenced by PHPXref |