diff --git a/docs/3.registering-abilities.md b/docs/3.registering-abilities.md index c4bb9169..9acc5ced 100644 --- a/docs/3.registering-abilities.md +++ b/docs/3.registering-abilities.md @@ -8,33 +8,34 @@ The primary way to add functionality to the Abilities API is by using the `wp_re wp_register_ability( string $id, array $args ): ?\WP_Ability ``` -- `$id` (`string`): A unique identifier for the ability. -- `$args` (`array`): An array of arguments defining the ability configuration. -- **Return:** (`?\WP_Ability`) An instance of the registered ability if it was successfully registered, `null` on failure (e.g., invalid arguments, duplicate ID). +- `$id` (`string`): A unique identifier for the ability. +- `$args` (`array`): An array of arguments defining the ability configuration. +- **Return:** (`?\WP_Ability`) An instance of the registered ability if it was successfully registered, `null` on failure (e.g., invalid arguments, duplicate ID). **Parameters Explained** The `$args` array accepts the following keys: -- `label` (`string`, **Required**): A human-readable name for the ability. Used for display purposes. Should be translatable. -- `description` (`string`, **Required**): A detailed description of what the ability does, its purpose, and its parameters or return values. This is crucial for AI agents to understand how and when to use the ability. Should be translatable. -- `input_schema` (`array`, **Required**): A JSON Schema definition describing the expected input parameters for the ability's execute callback. Used for validation and documentation. -- `output_schema` (`array`, **Required**): A JSON Schema definition describing the expected format of the data returned by the ability. Used for validation and documentation. -- `execute_callback` (`callable`, **Required**): The PHP function or method to execute when this ability is called. - - The callback receives one argument: an associative array of validated input parameters. - - The callback should return the result of the ability's operation or return a `WP_Error` object on failure. -- `permission_callback` (`callable`|`null`, **Optional**): A callback function to check if the current user has permission to execute this ability. - - Should return `true` if the user has permission, or a `WP_Error` object otherwise. - - If not provided, the ability will only validate input parameters before execution. - - This defaults to `true` if not set. -- `meta` (`array`, **Optional**): An associative array for storing arbitrary additional metadata about the ability. +- `label` (`string`, **Required**): A human-readable name for the ability. Used for display purposes. Should be translatable. +- `description` (`string`, **Required**): A detailed description of what the ability does, its purpose, and its parameters or return values. This is crucial for AI agents to understand how and when to use the ability. Should be translatable. +- `input_schema` (`array`, **Required**): A JSON Schema definition describing the expected input parameters for the ability's execute callback. Used for validation and documentation. +- `output_schema` (`array`, **Required**): A JSON Schema definition describing the expected format of the data returned by the ability. Used for validation and documentation. +- `execute_callback` (`callable`, **Required**): The PHP function or method to execute when this ability is called. + - The callback receives one optional argument: it can have any type as defined in the input schema (e.g., `array`, `object`, `string`, etc.). + - The callback should return the result of the ability's operation or return a `WP_Error` object on failure. +- `permission_callback` (`callable`|`null`, **Optional**): A callback function to check if the current user has permission to execute this ability. + - Should return `true` if the user has permission, or a `WP_Error` object otherwise. + - If not provided, the ability will only validate input parameters before execution. + - This defaults to `true` if not set. +- `meta` (`array`, **Optional**): An associative array for storing arbitrary additional metadata about the ability. **Ability ID Convention** The `$id` parameter must follow the pattern `namespace/ability-name`: -- **Format:** Must contain only lowercase alphanumeric characters (`a-z`, `0-9`), hyphens (`-`), and one forward slash (`/`) for namespacing. -- **Convention:** Use your plugin slug as the namespace, like `my-plugin/ability-name`. -- **Examples:** `my-plugin/update-settings`, `woocommerce/get-product`, `contact-form/send-message`, `analytics/track-event` + +- **Format:** Must contain only lowercase alphanumeric characters (`a-z`, `0-9`), hyphens (`-`), and one forward slash (`/`) for namespacing. +- **Convention:** Use your plugin slug as the namespace, like `my-plugin/ability-name`. +- **Examples:** `my-plugin/update-settings`, `woocommerce/get-product`, `contact-form/send-message`, `analytics/track-event` **Code Examples** @@ -59,7 +60,7 @@ function my_plugin_register_site_info_ability() { 'description' => 'Site name' ), 'description' => array( - 'type' => 'string', + 'type' => 'string', 'description' => 'Site tagline' ), 'url' => array( @@ -119,10 +120,10 @@ function my_plugin_register_update_option_ability() { 'execute_callback' => function( $input ) { $option_name = $input['option_name']; $new_value = $input['option_value']; - + $previous_value = get_option( $option_name ); $success = update_option( $option_name, $new_value ); - + return array( 'success' => $success, 'previous_value' => $previous_value @@ -144,7 +145,7 @@ function my_plugin_register_woo_stats_ability() { if ( ! class_exists( 'WooCommerce' ) ) { return; } - + wp_register_ability( 'my-plugin/get-woo-stats', array( 'label' => __( 'Get WooCommerce Statistics', 'my-plugin' ), 'description' => __( 'Retrieves basic WooCommerce store statistics including total orders and revenue.', 'my-plugin' ), @@ -175,7 +176,7 @@ function my_plugin_register_woo_stats_ability() { ), 'execute_callback' => function( $input ) { $period = $input['period'] ?? 'month'; - + // Implementation would calculate stats based on period return array( 'total_orders' => 42, @@ -238,14 +239,14 @@ function my_plugin_register_send_email_ability() { $input['subject'], $input['message'] ); - + if ( ! $sent ) { return new \WP_Error( 'email_send_failed', sprintf( __( 'Failed to send email' ), 'my-plugin' ) ); } - + return array( 'sent' => true ); }, 'permission_callback' => function() { diff --git a/docs/4.using-abilities.md b/docs/4.using-abilities.md index 4e94e8ef..11c0a79e 100644 --- a/docs/4.using-abilities.md +++ b/docs/4.using-abilities.md @@ -64,10 +64,10 @@ Once you have a `WP_Ability` object (usually from `wp_get_ability`), you execute /** * Executes the ability after input validation and running a permission check. * - * @param array $input Optional. The input data for the ability. + * @param mixed $input Optional. The input data for the ability. Defaults to `null`. * @return mixed|WP_Error The result of the ability execution, or WP_Error on failure. */ -// public function execute( array $input = array() ) +// public function execute( $input = null ) // Example 1: Ability with no input parameters $ability = wp_get_ability( 'my-plugin/get-site-info' ); @@ -135,7 +135,7 @@ if ( $ability ) { 'option_name' => 'blogname', 'option_value' => 'New Site Name', ); - + // Check permission before execution if ( $ability->has_permission( $input ) ) { $result = $ability->execute( $input ); @@ -166,14 +166,14 @@ if ( $ability ) { echo 'Name: ' . $ability->get_name() . "\n"; echo 'Label: ' . $ability->get_label() . "\n"; echo 'Description: ' . $ability->get_description() . "\n"; - + // Schema information $input_schema = $ability->get_input_schema(); $output_schema = $ability->get_output_schema(); - + echo 'Input Schema: ' . json_encode( $input_schema, JSON_PRETTY_PRINT ) . "\n"; echo 'Output Schema: ' . json_encode( $output_schema, JSON_PRETTY_PRINT ) . "\n"; - + // Metadata $meta = $ability->get_meta(); if ( ! empty( $meta ) ) { @@ -210,5 +210,5 @@ if ( is_null( $result ) ) { } // Success - use the result -// Process $result based on the ability's output schema +// Process $result based on the ability's output schema ``` diff --git a/includes/abilities-api.php b/includes/abilities-api.php index 13b4e06f..d78b25b9 100644 --- a/includes/abilities-api.php +++ b/includes/abilities-api.php @@ -35,8 +35,8 @@ * description?: string, * input_schema?: array, * output_schema?: array, - * execute_callback?: callable( array $input): (mixed|\WP_Error), - * permission_callback?: callable( array $input ): (bool|\WP_Error), + * execute_callback?: callable( mixed $input= ): (mixed|\WP_Error), + * permission_callback?: callable( mixed $input= ): (bool|\WP_Error), * meta?: array, * ability_class?: class-string<\WP_Ability>, * ... diff --git a/includes/abilities-api/class-wp-abilities-registry.php b/includes/abilities-api/class-wp-abilities-registry.php index 9094398c..dd507bd3 100644 --- a/includes/abilities-api/class-wp-abilities-registry.php +++ b/includes/abilities-api/class-wp-abilities-registry.php @@ -56,8 +56,8 @@ final class WP_Abilities_Registry { * description?: string, * input_schema?: array, * output_schema?: array, - * execute_callback?: callable( array $input): (mixed|\WP_Error), - * permission_callback?: ?callable( array $input ): (bool|\WP_Error), + * execute_callback?: callable( mixed $input= ): (mixed|\WP_Error), + * permission_callback?: ?callable( mixed $input= ): (bool|\WP_Error), * meta?: array, * ability_class?: class-string<\WP_Ability>, * ... diff --git a/includes/abilities-api/class-wp-ability.php b/includes/abilities-api/class-wp-ability.php index d622e926..a7d6a0af 100644 --- a/includes/abilities-api/class-wp-ability.php +++ b/includes/abilities-api/class-wp-ability.php @@ -65,7 +65,7 @@ class WP_Ability { * The ability execute callback. * * @since 0.1.0 - * @var callable( array $input): (mixed|\WP_Error) + * @var callable( mixed $input= ): (mixed|\WP_Error) */ protected $execute_callback; @@ -73,7 +73,7 @@ class WP_Ability { * The optional ability permission callback. * * @since 0.1.0 - * @var ?callable( array $input ): (bool|\WP_Error) + * @var ?callable( mixed $input= ): (bool|\WP_Error) */ protected $permission_callback = null; @@ -145,8 +145,8 @@ public function __construct( string $name, array $args ) { * description: string, * input_schema?: array, * output_schema?: array, - * execute_callback: callable( array $input): (mixed|\WP_Error), - * permission_callback?: ?callable( array $input ): (bool|\WP_Error), + * execute_callback: callable( mixed $input= ): (mixed|\WP_Error), + * permission_callback?: ?callable( mixed $input= ): (bool|\WP_Error), * meta?: array, * ..., * } $args @@ -269,13 +269,23 @@ public function get_meta(): array { * * @since 0.1.0 * - * @param array $input Optional. The input data to validate. + * @param mixed $input Optional. The input data to validate. Default `null`. * @return true|\WP_Error Returns true if valid or the WP_Error object if validation fails. */ - protected function validate_input( array $input = array() ) { + protected function validate_input( $input = null ) { $input_schema = $this->get_input_schema(); if ( empty( $input_schema ) ) { - return true; + if ( null === $input ) { + return true; + } + return new \WP_Error( + 'ability_missing_input_schema', + sprintf( + /* translators: %s ability name. */ + __( 'Ability "%s" does not define an input schema required to validate the provided input.' ), + $this->name + ) + ); } $valid_input = rest_validate_value_from_schema( $input, $input_schema, 'input' ); @@ -301,10 +311,10 @@ protected function validate_input( array $input = array() ) { * * @since 0.1.0 * - * @param array $input Optional. The input data for permission checking. + * @param mixed $input Optional. The input data for permission checking. Default `null`. * @return bool|\WP_Error Whether the ability has the necessary permission. */ - public function has_permission( array $input = array() ) { + public function has_permission( $input = null ) { $is_valid = $this->validate_input( $input ); if ( is_wp_error( $is_valid ) ) { return $is_valid; @@ -314,6 +324,10 @@ public function has_permission( array $input = array() ) { return true; } + if ( empty( $this->get_input_schema() ) ) { + return call_user_func( $this->permission_callback ); + } + return call_user_func( $this->permission_callback, $input ); } @@ -322,10 +336,10 @@ public function has_permission( array $input = array() ) { * * @since 0.1.0 * - * @param array $input The input data for the ability. + * @param mixed $input Optional. The input data for the ability. Default `null`. * @return mixed|\WP_Error The result of the ability execution, or WP_Error on failure. */ - protected function do_execute( array $input ) { + protected function do_execute( $input = null ) { if ( ! is_callable( $this->execute_callback ) ) { return new \WP_Error( 'ability_invalid_execute_callback', @@ -334,6 +348,10 @@ protected function do_execute( array $input ) { ); } + if ( empty( $this->get_input_schema() ) ) { + return call_user_func( $this->execute_callback ); + } + return call_user_func( $this->execute_callback, $input ); } @@ -373,10 +391,10 @@ protected function validate_output( $output ) { * * @since 0.1.0 * - * @param array $input Optional. The input data for the ability. + * @param mixed $input Optional. The input data for the ability. Default `null`. * @return mixed|\WP_Error The result of the ability execution, or WP_Error on failure. */ - public function execute( array $input = array() ) { + public function execute( $input = null ) { $has_permissions = $this->has_permission( $input ); if ( true !== $has_permissions ) { if ( is_wp_error( $has_permissions ) ) { diff --git a/includes/rest-api/endpoints/class-wp-rest-abilities-run-controller.php b/includes/rest-api/endpoints/class-wp-rest-abilities-run-controller.php index 6ae5af09..64fc223d 100644 --- a/includes/rest-api/endpoints/class-wp-rest-abilities-run-controller.php +++ b/includes/rest-api/endpoints/class-wp-rest-abilities-run-controller.php @@ -180,22 +180,18 @@ public function run_ability_permissions_check( $request ) { * @since 0.1.0 * * @param \WP_REST_Request> $request The request object. - * @return array The input parameters. + * @return mixed|null The input parameters. */ private function get_input_from_request( $request ) { if ( 'GET' === $request->get_method() ) { // For GET requests, look for 'input' query parameter. $query_params = $request->get_query_params(); - return isset( $query_params['input'] ) && is_array( $query_params['input'] ) - ? $query_params['input'] - : array(); + return $query_params['input'] ?? null; } // For POST requests, look for 'input' in JSON body. $json_params = $request->get_json_params(); - return isset( $json_params['input'] ) && is_array( $json_params['input'] ) - ? $json_params['input'] - : array(); + return $json_params['input'] ?? null; } /** @@ -209,8 +205,8 @@ public function get_run_args(): array { return array( 'input' => array( 'description' => __( 'Input parameters for the ability execution.' ), - 'type' => 'object', - 'default' => array(), + 'type' => array( 'integer', 'number', 'boolean', 'string', 'array', 'object', 'null' ), + 'default' => null, ), ); } @@ -230,7 +226,6 @@ public function get_run_schema(): array { 'properties' => array( 'result' => array( 'description' => __( 'The result of the ability execution.' ), - 'type' => 'mixed', 'context' => array( 'view' ), 'readonly' => true, ), diff --git a/tests/unit/abilities-api/wpAbility.php b/tests/unit/abilities-api/wpAbility.php new file mode 100644 index 00000000..b0b8d258 --- /dev/null +++ b/tests/unit/abilities-api/wpAbility.php @@ -0,0 +1,183 @@ + 'Calculator', + 'description' => 'Calculates the result of math operations.', + 'output_schema' => array( + 'type' => 'number', + 'description' => 'The result of performing a math operation.', + 'required' => true, + ), + 'permission_callback' => static function (): bool { + return true; + }, + 'meta' => array( + 'category' => 'math', + ), + ); + } + + /** + * Data provider for testing the execution of the ability. + */ + public function data_execute_input() { + return array( + 'null input' => array( + array( + 'type' => array( 'null', 'integer' ), + 'description' => 'The null or integer to convert to integer.', + 'required' => true, + ), + static function ( $input ): int { + return null === $input ? 0 : (int) $input; + }, + null, + 0, + ), + 'boolean input' => array( + array( + 'type' => 'boolean', + 'description' => 'The boolean to convert to integer.', + 'required' => true, + ), + static function ( bool $input ): int { + return $input ? 1 : 0; + }, + true, + 1, + ), + 'integer input' => array( + array( + 'type' => 'integer', + 'description' => 'The integer to add 5 to.', + 'required' => true, + ), + static function ( int $input ): int { + return 5 + $input; + }, + 2, + 7, + ), + 'number input' => array( + array( + 'type' => 'number', + 'description' => 'The floating number to round.', + 'required' => true, + ), + static function ( float $input ): int { + return (int) round( $input ); + }, + 2.7, + 3, + ), + 'string input' => array( + array( + 'type' => 'string', + 'description' => 'The string to measure the length of.', + 'required' => true, + ), + static function ( string $input ): int { + return strlen( $input ); + }, + 'Hello world!', + 12, + ), + 'object input' => array( + array( + 'type' => 'object', + 'description' => 'An object containing two numbers to add.', + 'properties' => array( + 'a' => array( + 'type' => 'integer', + 'description' => 'First number.', + 'required' => true, + ), + 'b' => array( + 'type' => 'integer', + 'description' => 'Second number.', + 'required' => true, + ), + ), + 'additionalProperties' => false, + ), + static function ( array $input ): int { + return $input['a'] + $input['b']; + }, + array( 'a' => 2, 'b' => 3 ), + 5, + ), + 'array input' => array( + array( + 'type' => 'array', + 'description' => 'An array containing two numbers to add.', + 'required' => true, + 'minItems' => 2, + 'maxItems' => 2, + 'items' => array( + 'type' => 'integer', + ), + ), + static function ( array $input ): int { + return $input[0] + $input[1]; + }, + array( 2, 3 ), + 5, + ), + ); + } + + /** + * Tests the execution of the ability. + * + * @dataProvider data_execute_input + */ + public function test_execute_input( $input_schema, $execute_callback, $input, $result ) { + $args = array_merge( + self::$test_ability_properties, + array( + 'input_schema' => $input_schema, + 'execute_callback' => $execute_callback, + ) + ); + + $ability = new WP_Ability( self::$test_ability_name, $args ); + + $this->assertSame( $result, $ability->execute( $input ) ); + } + + /** + * Tests the execution of the ability with no input. + */ + public function test_execute_no_input() { + $args = array_merge( + self::$test_ability_properties, + array( + 'execute_callback' => static function (): int { + return 42; + }, + ) + ); + + $ability = new WP_Ability( self::$test_ability_name, $args ); + + $this->assertSame( 42, $ability->execute() ); + } +} diff --git a/tests/unit/abilities-api/wpRegisterAbility.php b/tests/unit/abilities-api/wpRegisterAbility.php index a1c29c0f..7bfb983a 100644 --- a/tests/unit/abilities-api/wpRegisterAbility.php +++ b/tests/unit/abilities-api/wpRegisterAbility.php @@ -4,7 +4,7 @@ * Mock used to test a custom ability class. */ class Mock_Custom_Ability extends WP_Ability { - protected function do_execute( array $input ) { + protected function do_execute( $input = null ) { return 9999; } } diff --git a/tests/unit/rest-api/wpRestAbilitiesRunController.php b/tests/unit/rest-api/wpRestAbilitiesRunController.php index 7263b79d..a6c585f5 100644 --- a/tests/unit/rest-api/wpRestAbilitiesRunController.php +++ b/tests/unit/rest-api/wpRestAbilitiesRunController.php @@ -118,7 +118,7 @@ private function register_test_abilities(): void { 'execute_callback' => static function ( array $input ) { return $input['a'] + $input['b']; }, - 'permission_callback' => static function ( array $input ) { + 'permission_callback' => static function () { return current_user_can( 'edit_posts' ); }, 'meta' => array( @@ -160,7 +160,7 @@ private function register_test_abilities(): void { 'login' => $user->user_login, ); }, - 'permission_callback' => static function ( array $input ) { + 'permission_callback' => static function () { return is_user_logged_in(); }, 'meta' => array( @@ -263,7 +263,7 @@ private function register_test_abilities(): void { 'param2' => array( 'type' => 'integer' ), ), ), - 'execute_callback' => static function ( array $input ) { + 'execute_callback' => static function ( $input ) { return $input; }, 'permission_callback' => '__return_true', @@ -371,7 +371,6 @@ public function test_resource_ability_requires_get(): void { public function test_output_validation(): void { $request = new WP_REST_Request( 'POST', '/wp/v2/abilities/test/invalid-output/run' ); $request->set_header( 'Content-Type', 'application/json' ); - $request->set_body( wp_json_encode( array() ) ); $response = $this->server->dispatch( $request ); @@ -453,7 +452,6 @@ public function test_contextual_permission_check(): void { public function test_null_return_handling(): void { $request = new WP_REST_Request( 'POST', '/wp/v2/abilities/test/null-return/run' ); $request->set_header( 'Content-Type', 'application/json' ); - $request->set_body( wp_json_encode( array() ) ); $response = $this->server->dispatch( $request ); @@ -468,7 +466,6 @@ public function test_null_return_handling(): void { public function test_wp_error_return_handling(): void { $request = new WP_REST_Request( 'POST', '/wp/v2/abilities/test/error-return/run' ); $request->set_header( 'Content-Type', 'application/json' ); - $request->set_body( wp_json_encode( array() ) ); $response = $this->server->dispatch( $request ); @@ -486,7 +483,6 @@ public function test_wp_error_return_handling(): void { public function test_execute_non_existent_ability(): void { $request = new WP_REST_Request( 'POST', '/wp/v2/abilities/non/existent/run' ); $request->set_header( 'Content-Type', 'application/json' ); - $request->set_body( wp_json_encode( array() ) ); $response = $this->server->dispatch( $request ); @@ -608,7 +604,7 @@ public function test_output_validation_failure_returns_error(): void { ), 'required' => array( 'status' ), ), - 'execute_callback' => static function ( $input ) { + 'execute_callback' => static function () { // Return invalid output that doesn't match schema return array( 'wrong_field' => 'value' ); }, @@ -619,7 +615,6 @@ public function test_output_validation_failure_returns_error(): void { $request = new WP_REST_Request( 'POST', '/wp/v2/abilities/test/strict-output/run' ); $request->set_header( 'Content-Type', 'application/json' ); - $request->set_body( wp_json_encode( array( 'input' => array() ) ) ); $response = $this->server->dispatch( $request ); @@ -652,7 +647,7 @@ public function test_input_validation_failure_returns_error(): void { ), 'required' => array( 'required_field' ), ), - 'execute_callback' => static function ( $input ) { + 'execute_callback' => static function () { return array( 'status' => 'success' ); }, 'permission_callback' => '__return_true', @@ -687,7 +682,7 @@ public function test_ability_without_type_defaults_to_tool(): void { array( 'label' => 'No Type', 'description' => 'Ability without type', - 'execute_callback' => static function ( $input ) { + 'execute_callback' => static function () { return array( 'executed' => true ); }, 'permission_callback' => '__return_true', @@ -703,7 +698,6 @@ public function test_ability_without_type_defaults_to_tool(): void { // Should work with POST $post_request = new WP_REST_Request( 'POST', '/wp/v2/abilities/test/no-type/run' ); $post_request->set_header( 'Content-Type', 'application/json' ); - $post_request->set_body( wp_json_encode( array( 'input' => array() ) ) ); $post_response = $this->server->dispatch( $post_request ); $this->assertEquals( 200, $post_response->get_status() ); @@ -719,7 +713,7 @@ public function test_permission_check_passes_when_callback_not_set(): void { array( 'label' => 'No Permission Callback', 'description' => 'Ability without permission callback', - 'execute_callback' => static function ( $input ) { + 'execute_callback' => static function () { return array( 'executed' => true ); }, 'meta' => array( 'type' => 'tool' ), @@ -731,7 +725,6 @@ public function test_permission_check_passes_when_callback_not_set(): void { $request = new WP_REST_Request( 'POST', '/wp/v2/abilities/test/no-permission-callback/run' ); $request->set_header( 'Content-Type', 'application/json' ); - $request->set_body( wp_json_encode( array( 'input' => array() ) ) ); $response = $this->server->dispatch( $request ); @@ -746,14 +739,14 @@ public function test_permission_check_passes_when_callback_not_set(): void { * Test edge case with empty input for both GET and POST. */ public function test_empty_input_handling(): void { - // Register abilities for empty input testing + // Registers abilities for empty input testing. wp_register_ability( 'test/resource-empty', array( 'label' => 'Resource Empty', 'description' => 'Resource with empty input', - 'execute_callback' => static function ( $input ) { - return array( 'input_was_empty' => empty( $input ) ); + 'execute_callback' => static function () { + return array( 'input_was_empty' => 0 === func_num_args() ); }, 'permission_callback' => '__return_true', 'meta' => array( 'type' => 'resource' ), @@ -765,21 +758,21 @@ public function test_empty_input_handling(): void { array( 'label' => 'Tool Empty', 'description' => 'Tool with empty input', - 'execute_callback' => static function ( $input ) { - return array( 'input_was_empty' => empty( $input ) ); + 'execute_callback' => static function () { + return array( 'input_was_empty' => 0 === func_num_args() ); }, 'permission_callback' => '__return_true', 'meta' => array( 'type' => 'tool' ), ) ); - // Test GET with no input parameter + // Tests GET with no input parameter. $get_request = new WP_REST_Request( 'GET', '/wp/v2/abilities/test/resource-empty/run' ); $get_response = $this->server->dispatch( $get_request ); $this->assertEquals( 200, $get_response->get_status() ); $this->assertTrue( $get_response->get_data()['input_was_empty'] ); - // Test POST with no body + // Tests POST with no body. $post_request = new WP_REST_Request( 'POST', '/wp/v2/abilities/test/tool-empty/run' ); $post_request->set_header( 'Content-Type', 'application/json' ); $post_request->set_body( '{}' ); // Empty JSON object @@ -794,7 +787,7 @@ public function test_empty_input_handling(): void { * * @return array */ - public function malformed_json_provider(): array { + public function data_malformed_json_provider(): array { return array( 'Missing value' => array( '{"input": }' ), 'Trailing comma in array' => array( '{"input": [1, 2, }' ), @@ -810,7 +803,7 @@ public function malformed_json_provider(): array { /** * Test malformed JSON in POST body. * - * @dataProvider malformed_json_provider + * @dataProvider data_malformed_json_provider * @param string $json Malformed JSON to test. */ public function test_malformed_json_post_body( string $json ): void { @@ -835,6 +828,9 @@ public function test_php_type_strings_in_input(): void { array( 'label' => 'Echo', 'description' => 'Echoes input', + 'input_schema' => array( + 'type' => 'object', + ), 'execute_callback' => static function ( $input ) { return array( 'echo' => $input ); }, @@ -876,6 +872,9 @@ public function test_mixed_encoding_in_input(): void { array( 'label' => 'Echo Encoding', 'description' => 'Echoes input with encoding', + 'input_schema' => array( + 'type' => 'object', + ), 'execute_callback' => static function ( $input ) { return array( 'echo' => $input ); }, @@ -914,7 +913,7 @@ public function test_mixed_encoding_in_input(): void { * * @return array */ - public function invalid_http_methods_provider(): array { + public function data_invalid_http_methods_provider(): array { return array( 'PATCH' => array( 'PATCH' ), 'PUT' => array( 'PUT' ), @@ -926,7 +925,7 @@ public function invalid_http_methods_provider(): array { /** * Test request with invalid HTTP methods. * - * @dataProvider invalid_http_methods_provider + * @dataProvider data_invalid_http_methods_provider * @param string $method HTTP method to test. */ public function test_invalid_http_methods( string $method ): void {