@@ -65,17 +65,17 @@ class WP_Ability {
6565 * The ability execute callback.
6666 *
6767 * @since 0.1.0
68- * @var callable( array<string, mixed> $input): (mixed|\WP_Error)
68+ * @var callable( mixed $input= ): (mixed|\WP_Error)
6969 */
7070 protected $ execute_callback ;
7171
7272 /**
7373 * The optional ability permission callback.
7474 *
7575 * @since 0.1.0
76- * @var ? callable( array<string, mixed> $input ): (bool|\WP_Error)
76+ * @var callable( mixed $input= ): (bool|\WP_Error)
7777 */
78- protected $ permission_callback = null ;
78+ protected $ permission_callback ;
7979
8080 /**
8181 * The optional ability metadata.
@@ -143,15 +143,16 @@ public function __construct( string $name, array $args ) {
143143 * @phpstan-return array{
144144 * label: string,
145145 * description: string,
146+ * execute_callback: callable( mixed $input= ): (mixed|\WP_Error),
147+ * permission_callback: callable( mixed $input= ): (bool|\WP_Error),
146148 * input_schema?: array<string,mixed>,
147149 * output_schema?: array<string,mixed>,
148- * execute_callback: callable( array<string,mixed> $input): (mixed|\WP_Error),
149- * permission_callback?: ?callable( array<string,mixed> $input ): (bool|\WP_Error),
150150 * meta?: array<string,mixed>,
151151 * ...<string, mixed>,
152152 * } $args
153153 */
154154 protected function prepare_properties ( array $ args ): array {
155+ // Required args must be present and of the correct type.
155156 if ( empty ( $ args ['label ' ] ) || ! is_string ( $ args ['label ' ] ) ) {
156157 throw new \InvalidArgumentException (
157158 esc_html__ ( 'The ability properties must contain a `label` string. ' )
@@ -164,27 +165,28 @@ protected function prepare_properties( array $args ): array {
164165 );
165166 }
166167
167- if ( isset ( $ args ['input_schema ' ] ) && ! is_array ( $ args ['input_schema ' ] ) ) {
168+ if ( empty ( $ args ['execute_callback ' ] ) || ! is_callable ( $ args ['execute_callback ' ] ) ) {
168169 throw new \InvalidArgumentException (
169- esc_html__ ( 'The ability properties should provide a valid `input_schema` definition . ' )
170+ esc_html__ ( 'The ability properties must contain a valid `execute_callback` function . ' )
170171 );
171172 }
172173
173- if ( isset ( $ args ['output_schema ' ] ) && ! is_array ( $ args ['output_schema ' ] ) ) {
174+ if ( empty ( $ args ['permission_callback ' ] ) || ! is_callable ( $ args ['permission_callback ' ] ) ) {
174175 throw new \InvalidArgumentException (
175- esc_html__ ( 'The ability properties should provide a valid `output_schema` definition . ' )
176+ esc_html__ ( 'The ability properties must provide a valid `permission_callback` function . ' )
176177 );
177178 }
178179
179- if ( empty ( $ args ['execute_callback ' ] ) || ! is_callable ( $ args ['execute_callback ' ] ) ) {
180+ // Optional args only need to be of the correct type if they are present.
181+ if ( isset ( $ args ['input_schema ' ] ) && ! is_array ( $ args ['input_schema ' ] ) ) {
180182 throw new \InvalidArgumentException (
181- esc_html__ ( 'The ability properties must contain a valid `execute_callback` function . ' )
183+ esc_html__ ( 'The ability properties should provide a valid `input_schema` definition . ' )
182184 );
183185 }
184186
185- if ( isset ( $ args ['permission_callback ' ] ) && ! is_callable ( $ args ['permission_callback ' ] ) ) {
187+ if ( isset ( $ args ['output_schema ' ] ) && ! is_array ( $ args ['output_schema ' ] ) ) {
186188 throw new \InvalidArgumentException (
187- esc_html__ ( 'The ability properties should provide a valid `permission_callback` function . ' )
189+ esc_html__ ( 'The ability properties should provide a valid `output_schema` definition . ' )
188190 );
189191 }
190192
@@ -269,13 +271,24 @@ public function get_meta(): array {
269271 *
270272 * @since 0.1.0
271273 *
272- * @param array<string, mixed> $input Optional. The input data to validate.
274+ * @param mixed $input Optional. The input data to validate. Default `null` .
273275 * @return true|\WP_Error Returns true if valid or the WP_Error object if validation fails.
274276 */
275- protected function validate_input ( array $ input = array () ) {
277+ protected function validate_input ( $ input = null ) {
276278 $ input_schema = $ this ->get_input_schema ();
277279 if ( empty ( $ input_schema ) ) {
278- return true ;
280+ if ( null === $ input ) {
281+ return true ;
282+ }
283+
284+ return new \WP_Error (
285+ 'ability_missing_input_schema ' ,
286+ sprintf (
287+ /* translators: %s ability name. */
288+ __ ( 'Ability "%s" does not define an input schema required to validate the provided input. ' ),
289+ $ this ->name
290+ )
291+ );
279292 }
280293
281294 $ valid_input = rest_validate_value_from_schema ( $ input , $ input_schema , 'input ' );
@@ -296,36 +309,54 @@ protected function validate_input( array $input = array() ) {
296309
297310 /**
298311 * Checks whether the ability has the necessary permissions.
299- * If the permission callback is not set, the default behavior is to allow access
300- * when the input provided passes validation.
301312 *
302- * @since 0.1.0
313+ * The input is validated against the input schema before it is passed to to permission callback.
303314 *
304- * @param array<string,mixed> $input Optional. The input data for permission checking.
315+ * @since 0.2.0
316+ *
317+ * @param mixed $input Optional. The input data for permission checking. Default `null`.
305318 * @return bool|\WP_Error Whether the ability has the necessary permission.
306319 */
307- public function has_permission ( array $ input = array () ) {
320+ public function check_permissions ( $ input = null ) {
308321 $ is_valid = $ this ->validate_input ( $ input );
309322 if ( is_wp_error ( $ is_valid ) ) {
310323 return $ is_valid ;
311324 }
312325
313- if ( ! is_callable ( $ this ->permission_callback ) ) {
314- return true ;
326+ if ( empty ( $ this ->get_input_schema () ) ) {
327+ return call_user_func ( $ this -> permission_callback ) ;
315328 }
316329
317330 return call_user_func ( $ this ->permission_callback , $ input );
318331 }
319332
333+ /**
334+ * Checks whether the ability has the necessary permissions (deprecated).
335+ *
336+ * The input is validated against the input schema before it is passed to to permission callback.
337+ *
338+ * @deprecated 0.2.0 Use check_permissions() instead.
339+ * @see WP_Ability::check_permissions()
340+ *
341+ * @since 0.1.0
342+ *
343+ * @param mixed $input Optional. The input data for permission checking. Default `null`.
344+ * @return bool|\WP_Error Whether the ability has the necessary permission.
345+ */
346+ public function has_permission ( $ input = null ) {
347+ _deprecated_function ( __METHOD__ , '0.2.0 ' , 'WP_Ability::check_permissions() ' );
348+ return $ this ->check_permissions ( $ input );
349+ }
350+
320351 /**
321352 * Executes the ability callback.
322353 *
323354 * @since 0.1.0
324355 *
325- * @param array<string, mixed> $input The input data for the ability.
356+ * @param mixed $input Optional. The input data for the ability. Default `null` .
326357 * @return mixed|\WP_Error The result of the ability execution, or WP_Error on failure.
327358 */
328- protected function do_execute ( array $ input ) {
359+ protected function do_execute ( $ input = null ) {
329360 if ( ! is_callable ( $ this ->execute_callback ) ) {
330361 return new \WP_Error (
331362 'ability_invalid_execute_callback ' ,
@@ -334,6 +365,10 @@ protected function do_execute( array $input ) {
334365 );
335366 }
336367
368+ if ( empty ( $ this ->get_input_schema () ) ) {
369+ return call_user_func ( $ this ->execute_callback );
370+ }
371+
337372 return call_user_func ( $ this ->execute_callback , $ input );
338373 }
339374
@@ -373,11 +408,11 @@ protected function validate_output( $output ) {
373408 *
374409 * @since 0.1.0
375410 *
376- * @param array<string, mixed> $input Optional. The input data for the ability.
411+ * @param mixed $input Optional. The input data for the ability. Default `null` .
377412 * @return mixed|\WP_Error The result of the ability execution, or WP_Error on failure.
378413 */
379- public function execute ( array $ input = array () ) {
380- $ has_permissions = $ this ->has_permission ( $ input );
414+ public function execute ( $ input = null ) {
415+ $ has_permissions = $ this ->check_permissions ( $ input );
381416 if ( true !== $ has_permissions ) {
382417 if ( is_wp_error ( $ has_permissions ) ) {
383418 if ( 'ability_invalid_input ' === $ has_permissions ->get_error_code () ) {
@@ -398,14 +433,38 @@ public function execute( array $input = array() ) {
398433 );
399434 }
400435
436+ /**
437+ * Fires before an ability gets executed.
438+ *
439+ * @since 0.2.0
440+ *
441+ * @param string $ability_name The name of the ability.
442+ * @param mixed $input The input data for the ability.
443+ */
444+ do_action ( 'before_execute_ability ' , $ this ->name , $ input );
445+
401446 $ result = $ this ->do_execute ( $ input );
402447 if ( is_wp_error ( $ result ) ) {
403448 return $ result ;
404449 }
405450
406451 $ is_valid = $ this ->validate_output ( $ result );
452+ if ( is_wp_error ( $ is_valid ) ) {
453+ return $ is_valid ;
454+ }
407455
408- return is_wp_error ( $ is_valid ) ? $ is_valid : $ result ;
456+ /**
457+ * Fires immediately after an ability finished executing.
458+ *
459+ * @since 0.2.0
460+ *
461+ * @param string $ability_name The name of the ability.
462+ * @param mixed $input The input data for the ability.
463+ * @param mixed $result The result of the ability execution.
464+ */
465+ do_action ( 'after_execute_ability ' , $ this ->name , $ input , $ result );
466+
467+ return $ result ;
409468 }
410469
411470 /**
0 commit comments