Skip to content
This repository was archived by the owner on Feb 5, 2026. It is now read-only.

Commit 1af315d

Browse files
committed
fix: Code quality improvements for REST API controllers
PHPStan fixes: - Add return type annotations for void methods - Add array type hints for array parameters and returns - Cast integer header values to strings (PHPStan stubs expect strings) - Add ignore rule for WP_REST_Request generic types with explanation PHPCS compliance: - Add file documentation headers to all REST API files - Use fully qualified class names in PHPDoc comments - Add 'abilities-api' domain to all translation functions - Fix array alignment and spacing issues - Fix short ternary operators to explicit conditionals - Add periods to inline comments - Simplify elseif logic in run controller Type hints and modern PHP: - Add native PHP type hints where compatible with PHP 7.4+ - Add WP_REST_Abilities prefix to allowed prefixes in PHPCS config - Use native return types (void, array, bool) and parameter types
1 parent d473cf0 commit 1af315d

5 files changed

Lines changed: 138 additions & 99 deletions

phpcs.xml.dist

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@
254254
<element value="WP_Ability" />
255255
<element value="WP_Abilities" />
256256
<element value="WP_ABILITIES_API" />
257+
<element value="WP_REST_Abilities" />
257258
</property>
258259
</properties>
259260
</rule>

phpstan.neon.dist

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,15 @@ parameters:
2929
analyseAndScan:
3030
- node_modules (?)
3131

32+
# Ignore specific errors
33+
ignoreErrors:
34+
# WP_REST_Request is not actually a generic class in WordPress core.
35+
# PHPStan's WordPress stubs define it as generic for better type checking,
36+
# but WordPress itself doesn't use generics. This is a known incompatibility
37+
# between static analysis tools and WordPress's actual implementation.
38+
# All WordPress REST controllers have this same issue.
39+
-
40+
message: '#has parameter \$request with generic class WP_REST_Request but does not specify its types#'
41+
paths:
42+
- src/rest/*.php
43+

src/rest/class-wp-rest-abilities-init.php

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
1-
<?php declare( strict_types = 1 );
1+
<?php
2+
/**
3+
* REST API initialization for Abilities API.
4+
*
5+
* @package abilities-api
6+
* @since 0.1.0
7+
*/
8+
9+
declare( strict_types = 1 );
210

311
/**
412
* REST API: WP_REST_Abilities_Init class
@@ -20,7 +28,7 @@ class WP_REST_Abilities_Init {
2028
*
2129
* @since 0.1.0
2230
*/
23-
public static function register_routes() {
31+
public static function register_routes(): void {
2432
require_once __DIR__ . '/class-wp-rest-abilities-run-controller.php';
2533
require_once __DIR__ . '/class-wp-rest-abilities-list-controller.php';
2634

src/rest/class-wp-rest-abilities-list-controller.php

Lines changed: 53 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
1-
<?php declare( strict_types = 1 );
1+
<?php
2+
/**
3+
* REST API list controller for Abilities API.
4+
*
5+
* @package abilities-api
6+
* @since 0.1.0
7+
*/
8+
9+
declare( strict_types = 1 );
210

311
/**
412
* REST API: WP_REST_Abilities_List_Controller class
@@ -40,7 +48,7 @@ class WP_REST_Abilities_List_Controller extends WP_REST_Controller {
4048
*
4149
* @see register_rest_route()
4250
*/
43-
public function register_routes() {
51+
public function register_routes(): void {
4452
register_rest_route(
4553
$this->namespace,
4654
'/' . $this->rest_base,
@@ -59,9 +67,9 @@ public function register_routes() {
5967
$this->namespace,
6068
'/' . $this->rest_base . '/(?P<id>[a-zA-Z0-9\-\/]+)',
6169
array(
62-
'args' => array(
70+
'args' => array(
6371
'id' => array(
64-
'description' => __( 'Unique identifier for the ability.' ),
72+
'description' => __( 'Unique identifier for the ability.', 'abilities-api' ),
6573
'type' => 'string',
6674
'pattern' => '^[a-zA-Z0-9\-\/]+$',
6775
),
@@ -81,10 +89,10 @@ public function register_routes() {
8189
*
8290
* @since 0.1.0
8391
*
84-
* @param WP_REST_Request $request Full details about the request.
85-
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
92+
* @param \WP_REST_Request $request Full details about the request.
93+
* @return \WP_REST_Response Response object on success.
8694
*/
87-
public function get_items( $request ) {
95+
public function get_items( \WP_REST_Request $request ): \WP_REST_Response {
8896
$abilities = wp_get_abilities();
8997

9098
// Handle pagination.
@@ -105,11 +113,11 @@ public function get_items( $request ) {
105113

106114
$response = rest_ensure_response( $data );
107115

108-
$response->header( 'X-WP-Total', $total_abilities );
109-
$response->header( 'X-WP-TotalPages', $max_pages );
116+
$response->header( 'X-WP-Total', (string) $total_abilities );
117+
$response->header( 'X-WP-TotalPages', (string) $max_pages );
110118

111119
$request_params = $request->get_query_params();
112-
$base = add_query_arg( urlencode_deep( $request_params ), rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ) );
120+
$base = add_query_arg( urlencode_deep( $request_params ), rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ) );
113121

114122
if ( $page > 1 ) {
115123
$prev_page = $page - 1;
@@ -131,16 +139,16 @@ public function get_items( $request ) {
131139
*
132140
* @since 0.1.0
133141
*
134-
* @param WP_REST_Request $request Full details about the request.
135-
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
142+
* @param \WP_REST_Request $request Full details about the request.
143+
* @return \WP_REST_Response|\WP_Error Response object on success, or WP_Error object on failure.
136144
*/
137-
public function get_item( $request ) {
145+
public function get_item( \WP_REST_Request $request ) {
138146
$ability = wp_get_ability( $request['id'] );
139147

140148
if ( ! $ability ) {
141-
return new WP_Error(
149+
return new \WP_Error(
142150
'rest_ability_not_found',
143-
__( 'Ability not found.' ),
151+
__( 'Ability not found.', 'abilities-api' ),
144152
array( 'status' => 404 )
145153
);
146154
}
@@ -154,10 +162,10 @@ public function get_item( $request ) {
154162
*
155163
* @since 0.1.0
156164
*
157-
* @param WP_REST_Request $request Full details about the request.
158-
* @return true|WP_Error True if the request has read access, WP_Error object otherwise.
165+
* @param \WP_REST_Request $request Full details about the request.
166+
* @return boolean True if the request has read access.
159167
*/
160-
public function get_items_permissions_check( $request ) {
168+
public function get_items_permissions_check( \WP_REST_Request $request ): bool {
161169
return current_user_can( 'read' );
162170
}
163171

@@ -166,11 +174,11 @@ public function get_items_permissions_check( $request ) {
166174
*
167175
* @since 0.1.0
168176
*
169-
* @param WP_Ability $ability The ability object.
170-
* @param WP_REST_Request $request Request object.
171-
* @return WP_REST_Response Response object.
177+
* @param \WP_Ability $ability The ability object.
178+
* @param \WP_REST_Request $request Request object.
179+
* @return \WP_REST_Response Response object.
172180
*/
173-
public function prepare_item_for_response( $ability, $request ) {
181+
public function prepare_item_for_response( \WP_Ability $ability, \WP_REST_Request $request ): \WP_REST_Response {
174182
$data = array(
175183
'id' => $ability->get_name(),
176184
'label' => $ability->get_label(),
@@ -181,21 +189,21 @@ public function prepare_item_for_response( $ability, $request ) {
181189
);
182190

183191
$context = ! empty( $request['context'] ) ? $request['context'] : 'view';
184-
$data = $this->add_additional_fields_to_object( $data, $request );
185-
$data = $this->filter_response_by_context( $data, $context );
192+
$data = $this->add_additional_fields_to_object( $data, $request );
193+
$data = $this->filter_response_by_context( $data, $context );
186194

187195
$response = rest_ensure_response( $data );
188196

189197
$links = array(
190-
'self' => array(
198+
'self' => array(
191199
'href' => rest_url( sprintf( '%s/%s/%s', $this->namespace, $this->rest_base, $ability->get_name() ) ),
192200
),
193201
'collection' => array(
194202
'href' => rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ),
195203
),
196204
);
197205

198-
// Add run link for all abilities
206+
// Add run link for all abilities.
199207
$links['run'] = array(
200208
'href' => rest_url( sprintf( '%s/%s/%s/run', $this->namespace, $this->rest_base, $ability->get_name() ) ),
201209
);
@@ -210,46 +218,46 @@ public function prepare_item_for_response( $ability, $request ) {
210218
*
211219
* @since 0.1.0
212220
*
213-
* @return array Item schema data.
221+
* @return array<string, mixed> Item schema data.
214222
*/
215-
public function get_item_schema() {
223+
public function get_item_schema(): array {
216224
$schema = array(
217225
'$schema' => 'http://json-schema.org/draft-04/schema#',
218226
'title' => 'ability',
219227
'type' => 'object',
220228
'properties' => array(
221-
'id' => array(
222-
'description' => __( 'Unique identifier for the ability.' ),
229+
'id' => array(
230+
'description' => __( 'Unique identifier for the ability.', 'abilities-api' ),
223231
'type' => 'string',
224232
'context' => array( 'view', 'edit', 'embed' ),
225233
'readonly' => true,
226234
),
227-
'label' => array(
228-
'description' => __( 'Display label for the ability.' ),
235+
'label' => array(
236+
'description' => __( 'Display label for the ability.', 'abilities-api' ),
229237
'type' => 'string',
230238
'context' => array( 'view', 'edit', 'embed' ),
231239
'readonly' => true,
232240
),
233-
'description' => array(
234-
'description' => __( 'Description of the ability.' ),
241+
'description' => array(
242+
'description' => __( 'Description of the ability.', 'abilities-api' ),
235243
'type' => 'string',
236244
'context' => array( 'view', 'edit' ),
237245
'readonly' => true,
238246
),
239-
'input_schema' => array(
240-
'description' => __( 'JSON Schema for the ability input.' ),
247+
'input_schema' => array(
248+
'description' => __( 'JSON Schema for the ability input.', 'abilities-api' ),
241249
'type' => 'object',
242250
'context' => array( 'view', 'edit' ),
243251
'readonly' => true,
244252
),
245253
'output_schema' => array(
246-
'description' => __( 'JSON Schema for the ability output.' ),
254+
'description' => __( 'JSON Schema for the ability output.', 'abilities-api' ),
247255
'type' => 'object',
248256
'context' => array( 'view', 'edit' ),
249257
'readonly' => true,
250258
),
251-
'meta' => array(
252-
'description' => __( 'Meta information about the ability.' ),
259+
'meta' => array(
260+
'description' => __( 'Meta information about the ability.', 'abilities-api' ),
253261
'type' => 'object',
254262
'context' => array( 'view', 'edit' ),
255263
'readonly' => true,
@@ -265,21 +273,21 @@ public function get_item_schema() {
265273
*
266274
* @since 0.1.0
267275
*
268-
* @return array Collection parameters.
276+
* @return array<string, mixed> Collection parameters.
269277
*/
270-
public function get_collection_params() {
278+
public function get_collection_params(): array {
271279
return array(
272-
'context' => $this->get_context_param( array( 'default' => 'view' ) ),
273-
'page' => array(
274-
'description' => __( 'Current page of the collection.' ),
280+
'context' => $this->get_context_param( array( 'default' => 'view' ) ),
281+
'page' => array(
282+
'description' => __( 'Current page of the collection.', 'abilities-api' ),
275283
'type' => 'integer',
276284
'default' => 1,
277285
'sanitize_callback' => 'absint',
278286
'validate_callback' => 'rest_validate_request_arg',
279287
'minimum' => 1,
280288
),
281289
'per_page' => array(
282-
'description' => __( 'Maximum number of items to be returned in result set.' ),
290+
'description' => __( 'Maximum number of items to be returned in result set.', 'abilities-api' ),
283291
'type' => 'integer',
284292
'default' => 50,
285293
'minimum' => 1,

0 commit comments

Comments
 (0)