@@ -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,22 +309,22 @@ 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 .
312+ *
313+ * The input is validated against the input schema before it is passed to to permission callback .
301314 *
302315 * @since 0.1.0
303316 *
304- * @param array<string, mixed> $input Optional. The input data for permission checking.
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 has_permission ( $ 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 );
@@ -322,10 +335,10 @@ public function has_permission( array $input = array() ) {
322335 *
323336 * @since 0.1.0
324337 *
325- * @param array<string, mixed> $input The input data for the ability.
338+ * @param mixed $input Optional. The input data for the ability. Default `null` .
326339 * @return mixed|\WP_Error The result of the ability execution, or WP_Error on failure.
327340 */
328- protected function do_execute ( array $ input ) {
341+ protected function do_execute ( $ input = null ) {
329342 if ( ! is_callable ( $ this ->execute_callback ) ) {
330343 return new \WP_Error (
331344 'ability_invalid_execute_callback ' ,
@@ -334,6 +347,10 @@ protected function do_execute( array $input ) {
334347 );
335348 }
336349
350+ if ( empty ( $ this ->get_input_schema () ) ) {
351+ return call_user_func ( $ this ->execute_callback );
352+ }
353+
337354 return call_user_func ( $ this ->execute_callback , $ input );
338355 }
339356
@@ -373,10 +390,10 @@ protected function validate_output( $output ) {
373390 *
374391 * @since 0.1.0
375392 *
376- * @param array<string, mixed> $input Optional. The input data for the ability.
393+ * @param mixed $input Optional. The input data for the ability. Default `null` .
377394 * @return mixed|\WP_Error The result of the ability execution, or WP_Error on failure.
378395 */
379- public function execute ( array $ input = array () ) {
396+ public function execute ( $ input = null ) {
380397 $ has_permissions = $ this ->has_permission ( $ input );
381398 if ( true !== $ has_permissions ) {
382399 if ( is_wp_error ( $ has_permissions ) ) {
@@ -398,14 +415,38 @@ public function execute( array $input = array() ) {
398415 );
399416 }
400417
418+ /**
419+ * Fires before an ability gets executed.
420+ *
421+ * @since 0.2.0
422+ *
423+ * @param string $ability_name The name of the ability.
424+ * @param mixed $input The input data for the ability.
425+ */
426+ do_action ( 'before_execute_ability ' , $ this ->name , $ input );
427+
401428 $ result = $ this ->do_execute ( $ input );
402429 if ( is_wp_error ( $ result ) ) {
403430 return $ result ;
404431 }
405432
406433 $ is_valid = $ this ->validate_output ( $ result );
434+ if ( is_wp_error ( $ is_valid ) ) {
435+ return $ is_valid ;
436+ }
407437
408- return is_wp_error ( $ is_valid ) ? $ is_valid : $ result ;
438+ /**
439+ * Fires immediately after an ability finished executing.
440+ *
441+ * @since 0.2.0
442+ *
443+ * @param string $ability_name The name of the ability.
444+ * @param mixed $input The input data for the ability.
445+ * @param mixed $result The result of the ability execution.
446+ */
447+ do_action ( 'after_execute_ability ' , $ this ->name , $ input , $ result );
448+
449+ return $ result ;
409450 }
410451
411452 /**
0 commit comments