Skip to content

Commit 994bfdc

Browse files
committed
Apply feedback from code review
1 parent f0345c0 commit 994bfdc

File tree

6 files changed

+1152
-39
lines changed

6 files changed

+1152
-39
lines changed

src/wp-includes/rest-api.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -485,7 +485,9 @@ function create_initial_rest_routes() {
485485
$font_collections_controller->register_routes();
486486

487487
// Abilities.
488-
$abilities_run_controller = new WP_REST_Abilities_V1_Run_Controller();
488+
$abilities_categories_controller = new WP_REST_Abilities_V1_Categories_Controller();
489+
$abilities_categories_controller->register_routes();
490+
$abilities_run_controller = new WP_REST_Abilities_V1_Run_Controller();
489491
$abilities_run_controller->register_routes();
490492
$abilities_list_controller = new WP_REST_Abilities_V1_List_Controller();
491493
$abilities_list_controller->register_routes();
Lines changed: 293 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,293 @@
1+
<?php
2+
/**
3+
* REST API ability categories 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 ability categories via the REST API.
14+
*
15+
* @since 6.9.0
16+
*
17+
* @see WP_REST_Controller
18+
*/
19+
class WP_REST_Abilities_V1_Categories_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 = 'categories';
36+
37+
/**
38+
* Registers the routes for ability categories.
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<slug>[a-z0-9]+(?:-[a-z0-9]+)*)',
62+
array(
63+
'args' => array(
64+
'slug' => array(
65+
'description' => __( 'Unique identifier for the ability category.' ),
66+
'type' => 'string',
67+
'pattern' => '^[a-z0-9]+(?:-[a-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 ability categories.
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+
$categories = wp_get_ability_categories();
90+
91+
$page = $request['page'];
92+
$per_page = $request['per_page'];
93+
$offset = ( $page - 1 ) * $per_page;
94+
95+
$total_categories = count( $categories );
96+
$max_pages = ceil( $total_categories / $per_page );
97+
98+
if ( $request->get_method() === 'HEAD' ) {
99+
$response = new WP_REST_Response( array() );
100+
} else {
101+
$categories = array_slice( $categories, $offset, $per_page );
102+
103+
$data = array();
104+
foreach ( $categories as $category ) {
105+
$item = $this->prepare_item_for_response( $category, $request );
106+
$data[] = $this->prepare_response_for_collection( $item );
107+
}
108+
109+
$response = rest_ensure_response( $data );
110+
}
111+
112+
$response->header( 'X-WP-Total', (string) $total_categories );
113+
$response->header( 'X-WP-TotalPages', (string) $max_pages );
114+
115+
$query_params = $request->get_query_params();
116+
$base = add_query_arg(
117+
urlencode_deep( $query_params ),
118+
rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) )
119+
);
120+
121+
if ( $page > 1 ) {
122+
$prev_page = $page - 1;
123+
$prev_link = add_query_arg( 'page', $prev_page, $base );
124+
$response->link_header( 'prev', $prev_link );
125+
}
126+
127+
if ( $page < $max_pages ) {
128+
$next_page = $page + 1;
129+
$next_link = add_query_arg( 'page', $next_page, $base );
130+
$response->link_header( 'next', $next_link );
131+
}
132+
133+
return $response;
134+
}
135+
136+
/**
137+
* Retrieves a specific ability category.
138+
*
139+
* @since 6.9.0
140+
*
141+
* @param WP_REST_Request $request Full details about the request.
142+
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
143+
*/
144+
public function get_item( $request ) {
145+
$category = wp_get_ability_category( $request['slug'] );
146+
if ( ! $category ) {
147+
return new WP_Error(
148+
'rest_ability_category_not_found',
149+
__( 'Ability category not found.' ),
150+
array( 'status' => 404 )
151+
);
152+
}
153+
154+
$data = $this->prepare_item_for_response( $category, $request );
155+
return rest_ensure_response( $data );
156+
}
157+
158+
/**
159+
* Checks if a given request has access to read ability categories.
160+
*
161+
* @since 6.9.0
162+
*
163+
* @param WP_REST_Request $request Full details about the request.
164+
* @return bool True if the request has read access.
165+
*/
166+
public function get_items_permissions_check( $request ) {
167+
return current_user_can( 'read' );
168+
}
169+
170+
/**
171+
* Checks if a given request has access to read an ability category.
172+
*
173+
* @since 6.9.0
174+
*
175+
* @param WP_REST_Request $request Full details about the request.
176+
* @return bool True if the request has read access.
177+
*/
178+
public function get_item_permissions_check( $request ) {
179+
return current_user_can( 'read' );
180+
}
181+
182+
/**
183+
* Prepares an ability category for response.
184+
*
185+
* @since 6.9.0
186+
*
187+
* @param WP_Ability_Category $category The ability category object.
188+
* @param WP_REST_Request $request Request object.
189+
* @return WP_REST_Response Response object.
190+
*/
191+
public function prepare_item_for_response( $category, $request ) {
192+
$data = array(
193+
'slug' => $category->get_slug(),
194+
'label' => $category->get_label(),
195+
'description' => $category->get_description(),
196+
'meta' => $category->get_meta(),
197+
);
198+
199+
$context = $request['context'] ?? 'view';
200+
$data = $this->add_additional_fields_to_object( $data, $request );
201+
$data = $this->filter_response_by_context( $data, $context );
202+
203+
$response = rest_ensure_response( $data );
204+
205+
$fields = $this->get_fields_for_response( $request );
206+
if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) {
207+
$links = array(
208+
'self' => array(
209+
'href' => rest_url( sprintf( '%s/%s/%s', $this->namespace, $this->rest_base, $category->get_slug() ) ),
210+
),
211+
'collection' => array(
212+
'href' => rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ),
213+
),
214+
'abilities' => array(
215+
'href' => rest_url( sprintf( '%s/abilities?category=%s', $this->namespace, $category->get_slug() ) ),
216+
),
217+
);
218+
219+
$response->add_links( $links );
220+
}
221+
222+
return $response;
223+
}
224+
225+
/**
226+
* Retrieves the ability category's schema, conforming to JSON Schema.
227+
*
228+
* @since 6.9.0
229+
*
230+
* @return array<string, mixed> Item schema data.
231+
*/
232+
public function get_item_schema(): array {
233+
$schema = array(
234+
'$schema' => 'http://json-schema.org/draft-04/schema#',
235+
'title' => 'ability-category',
236+
'type' => 'object',
237+
'properties' => array(
238+
'slug' => array(
239+
'description' => __( 'Unique identifier for the ability category.' ),
240+
'type' => 'string',
241+
'context' => array( 'view', 'edit', 'embed' ),
242+
'readonly' => true,
243+
),
244+
'label' => array(
245+
'description' => __( 'Display label for the category.' ),
246+
'type' => 'string',
247+
'context' => array( 'view', 'edit', 'embed' ),
248+
'readonly' => true,
249+
),
250+
'description' => array(
251+
'description' => __( 'Description of the category.' ),
252+
'type' => 'string',
253+
'context' => array( 'view', 'edit' ),
254+
'readonly' => true,
255+
),
256+
'meta' => array(
257+
'description' => __( 'Meta information about the category.' ),
258+
'type' => 'object',
259+
'context' => array( 'view', 'edit' ),
260+
'readonly' => true,
261+
),
262+
),
263+
);
264+
265+
return $this->add_additional_fields_schema( $schema );
266+
}
267+
268+
/**
269+
* Retrieves the query params for collections.
270+
*
271+
* @since 6.9.0
272+
*
273+
* @return array<string, mixed> Collection parameters.
274+
*/
275+
public function get_collection_params(): array {
276+
return array(
277+
'context' => $this->get_context_param( array( 'default' => 'view' ) ),
278+
'page' => array(
279+
'description' => __( 'Current page of the collection.' ),
280+
'type' => 'integer',
281+
'default' => 1,
282+
'minimum' => 1,
283+
),
284+
'per_page' => array(
285+
'description' => __( 'Maximum number of items to be returned in result set.' ),
286+
'type' => 'integer',
287+
'default' => 50,
288+
'minimum' => 1,
289+
'maximum' => 100,
290+
),
291+
);
292+
}
293+
}

src/wp-settings.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,7 @@
336336
require ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-font-families-controller.php';
337337
require ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-font-faces-controller.php';
338338
require ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-font-collections-controller.php';
339+
require ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-abilities-v1-categories-controller.php';
339340
require ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-abilities-v1-list-controller.php';
340341
require ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-abilities-v1-run-controller.php';
341342
require ABSPATH . WPINC . '/rest-api/fields/class-wp-rest-meta-fields.php';

tests/phpunit/tests/rest-api/rest-schema-setup.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,8 @@ public function test_expected_routes_in_schema() {
204204
'/wp/v2/font-families/(?P<font_family_id>[\d]+)/font-faces/(?P<id>[\d]+)',
205205
'/wp/v2/font-families/(?P<id>[\d]+)',
206206
'/wp-abilities/v1',
207+
'/wp-abilities/v1/categories',
208+
'/wp-abilities/v1/categories/(?P<slug>[a-z0-9]+(?:-[a-z0-9]+)*)',
207209
'/wp-abilities/v1/abilities/(?P<name>[a-zA-Z0-9\-\/]+?)/run',
208210
'/wp-abilities/v1/abilities/(?P<name>[a-zA-Z0-9\-\/]+)',
209211
'/wp-abilities/v1/abilities',

0 commit comments

Comments
 (0)