@@ -99,6 +99,16 @@ class WP_Ability {
99
99
* @param array<string,mixed> $properties An associative array of properties for the ability. This should
100
100
* include `label`, `description`, `input_schema`, `output_schema`,
101
101
* `execute_callback`, `permission_callback`, and `meta`.
102
+ *
103
+ * @phpstan-param array{
104
+ * label: string,
105
+ * description: string,
106
+ * input_schema?: array<string,mixed>,
107
+ * output_schema?: array<string,mixed>,
108
+ * execute_callback: callable( array<string,mixed> $input): (mixed|\WP_Error),
109
+ * permission_callback?: ?callable( ?array<string,mixed> $input ): bool,
110
+ * meta?: array<string,mixed>,
111
+ * } $properties
102
112
*/
103
113
public function __construct ( string $ name , array $ properties ) {
104
114
$ this ->name = $ name ;
@@ -180,29 +190,25 @@ public function get_meta(): array {
180
190
* @since 0.1.0
181
191
*
182
192
* @param array<string,mixed> $input Optional. The input data to validate.
183
- * @return bool Returns true if valid, false if validation fails.
193
+ * @return true|\WP_Error Returns true if valid or the WP_Error object if validation fails.
184
194
*/
185
- protected function validate_input ( array $ input = array () ): bool {
195
+ protected function validate_input ( array $ input = array () ) {
186
196
$ input_schema = $ this ->get_input_schema ();
187
197
if ( empty ( $ input_schema ) ) {
188
198
return true ;
189
199
}
190
200
191
- $ valid_input = rest_validate_value_from_schema ( $ input , $ input_schema );
201
+ $ valid_input = rest_validate_value_from_schema ( $ input , $ input_schema, ' input ' );
192
202
if ( is_wp_error ( $ valid_input ) ) {
193
- _doing_it_wrong (
194
- __METHOD__ ,
195
- esc_html (
196
- sprintf (
197
- /* translators: %1$s ability name, %2$s error message. */
198
- __ ( 'Invalid input provided for ability "%1$s": %2$s. ' ),
199
- $ this ->name ,
200
- $ valid_input ->get_error_message ()
201
- )
202
- ),
203
- '0.1.0 '
203
+ return new \WP_Error (
204
+ 'ability_invalid_input ' ,
205
+ sprintf (
206
+ /* translators: %1$s ability name, %2$s error message. */
207
+ __ ( 'Ability "%1$s" has invalid input. Reason: %2$s ' ),
208
+ $ this ->name ,
209
+ $ valid_input ->get_error_message ()
210
+ )
204
211
);
205
- return false ;
206
212
}
207
213
208
214
return true ;
@@ -216,11 +222,12 @@ protected function validate_input( array $input = array() ): bool {
216
222
* @since 0.1.0
217
223
*
218
224
* @param array<string,mixed> $input Optional. The input data for permission checking.
219
- * @return bool Whether the ability has the necessary permission.
225
+ * @return true|\WP_Error Whether the ability has the necessary permission.
220
226
*/
221
- public function has_permission ( array $ input = array () ): bool {
222
- if ( ! $ this ->validate_input ( $ input ) ) {
223
- return false ;
227
+ public function has_permission ( array $ input = array () ) {
228
+ $ is_valid = $ this ->validate_input ( $ input );
229
+ if ( is_wp_error ( $ is_valid ) ) {
230
+ return $ is_valid ;
224
231
}
225
232
226
233
if ( ! is_callable ( $ this ->permission_callback ) ) {
@@ -240,16 +247,13 @@ public function has_permission( array $input = array() ): bool {
240
247
*/
241
248
protected function do_execute ( array $ input ) {
242
249
if ( ! is_callable ( $ this ->execute_callback ) ) {
243
- _doing_it_wrong (
244
- __METHOD__ ,
245
- esc_html (
246
- /* translators: %s ability name. */
247
- sprintf ( __ ( 'Ability "%s" does not have a valid execute callback. ' ), $ this ->name )
248
- ),
249
- '0.1.0 '
250
+ return new \WP_Error (
251
+ 'ability_invalid_execute_callback ' ,
252
+ /* translators: %s ability name. */
253
+ sprintf ( __ ( 'Ability "%s" does not have a valid execute callback. ' ), $ this ->name )
250
254
);
251
- return null ;
252
255
}
256
+
253
257
return call_user_func ( $ this ->execute_callback , $ input );
254
258
}
255
259
@@ -259,29 +263,25 @@ protected function do_execute( array $input ) {
259
263
* @since 0.1.0
260
264
*
261
265
* @param mixed $output The output data to validate.
262
- * @return bool Returns true if valid, false if validation fails.
266
+ * @return true|\WP_Error Returns true if valid, or a WP_Error object if validation fails.
263
267
*/
264
- protected function validate_output ( $ output ): bool {
268
+ protected function validate_output ( $ output ) {
265
269
$ output_schema = $ this ->get_output_schema ();
266
270
if ( empty ( $ output_schema ) ) {
267
271
return true ;
268
272
}
269
273
270
- $ valid_output = rest_validate_value_from_schema ( $ output , $ output_schema );
274
+ $ valid_output = rest_validate_value_from_schema ( $ output , $ output_schema, ' output ' );
271
275
if ( is_wp_error ( $ valid_output ) ) {
272
- _doing_it_wrong (
273
- __METHOD__ ,
274
- esc_html (
275
- sprintf (
276
- /* translators: %1$s ability name, %2$s error message. */
277
- __ ( 'Invalid output provided for ability "%1$s": %2$s. ' ),
278
- $ this ->name ,
279
- $ valid_output ->get_error_message ()
280
- )
281
- ),
282
- '0.1.0 '
276
+ return new \WP_Error (
277
+ 'ability_invalid_output ' ,
278
+ sprintf (
279
+ /* translators: %1$s ability name, %2$s error message. */
280
+ __ ( 'Ability "%1$s" has invalid output. Reason: %2$s ' ),
281
+ $ this ->name ,
282
+ $ valid_output ->get_error_message ()
283
+ )
283
284
);
284
- return false ;
285
285
}
286
286
287
287
return true ;
@@ -297,28 +297,35 @@ protected function validate_output( $output ): bool {
297
297
* @return mixed|\WP_Error The result of the ability execution, or WP_Error on failure.
298
298
*/
299
299
public function execute ( array $ input = array () ) {
300
- if ( ! $ this ->has_permission ( $ input ) ) {
301
- _doing_it_wrong (
302
- __METHOD__ ,
303
- esc_html (
304
- /* translators: %s ability name. */
305
- sprintf ( __ ( 'Ability "%s" does not have necessary permission. ' ), $ this ->name )
306
- ),
307
- '0.1.0 '
300
+ $ has_permissions = $ this ->has_permission ( $ input );
301
+ if ( true !== $ has_permissions ) {
302
+ if ( is_wp_error ( $ has_permissions ) ) {
303
+ if ( 'ability_invalid_input ' === $ has_permissions ->get_error_code () ) {
304
+ return $ has_permissions ;
305
+ }
306
+ // Don't leak the permission check error to someone without the correct perms.
307
+ _doing_it_wrong (
308
+ __METHOD__ ,
309
+ esc_html ( $ has_permissions ->get_error_message () ),
310
+ '0.1.0 '
311
+ );
312
+ }
313
+
314
+ return new \WP_Error (
315
+ 'ability_invalid_permissions ' ,
316
+ /* translators: %s ability name. */
317
+ sprintf ( __ ( 'Ability "%s" does not have necessary permission. ' ), $ this ->name )
308
318
);
309
- return null ;
310
319
}
311
320
312
321
$ result = $ this ->do_execute ( $ input );
313
322
if ( is_wp_error ( $ result ) ) {
314
323
return $ result ;
315
324
}
316
325
317
- if ( ! $ this ->validate_output ( $ result ) ) {
318
- return null ;
319
- }
326
+ $ is_valid = $ this ->validate_output ( $ result );
320
327
321
- return $ result ;
328
+ return is_wp_error ( $ is_valid ) ? $ is_valid : $ result ;
322
329
}
323
330
324
331
/**
0 commit comments