From 6debd58fe2f072bfb77c5f7772152a56256a3a6e Mon Sep 17 00:00:00 2001 From: Jorge Costa Date: Thu, 23 Oct 2025 18:45:16 +0100 Subject: [PATCH 01/20] Add: Core abiltiies registration. --- .../abilities/wp-core-abilities.php | 273 ++++++++++++++++++ src/wp-includes/default-filters.php | 4 + src/wp-settings.php | 1 + .../tests/abilities-api/wpCoreAbilities.php | 136 +++++++++ 4 files changed, 414 insertions(+) create mode 100644 src/wp-includes/abilities/wp-core-abilities.php create mode 100644 tests/phpunit/tests/abilities-api/wpCoreAbilities.php diff --git a/src/wp-includes/abilities/wp-core-abilities.php b/src/wp-includes/abilities/wp-core-abilities.php new file mode 100644 index 0000000000000..586f629dbdaa3 --- /dev/null +++ b/src/wp-includes/abilities/wp-core-abilities.php @@ -0,0 +1,273 @@ + __( 'Site' ), + 'description' => __( 'Abilities that retrieve or modify site information and settings.' ), + ) + ); + + wp_register_ability_category( + 'user', + array( + 'label' => __( 'User' ), + 'description' => __( 'Abilities that retrieve or modify user information and settings.' ), + ) + ); +} + +/** + * Registers the default core abilities. + * + * @since 0.3.0 + * + * @return void + */ +// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound +function wp_register_core_abilities(): void { + $category_site = 'site'; + $category_user = 'user'; + + $site_info_fields = array( + 'name', + 'description', + 'url', + 'wpurl', + 'admin_email', + 'charset', + 'language', + 'version', + ); + + wp_register_ability( + 'core/get-site-info', + array( + 'label' => __( 'Get Site Information' ), + 'description' => __( 'Returns site information configured in WordPress. By default returns all fields, or optionally a filtered subset.' ), + 'category' => $category_site, + 'input_schema' => array( + 'type' => 'object', + 'properties' => array( + 'fields' => array( + 'type' => 'array', + 'items' => array( + 'type' => 'string', + 'enum' => $site_info_fields, + ), + 'description' => __( 'Optional: Limit response to specific fields. If omitted, all fields are returned.' ), + ), + ), + 'additionalProperties' => false, + 'default' => array(), + ), + 'output_schema' => array( + 'type' => 'object', + 'properties' => array( + 'name' => array( + 'type' => 'string', + 'description' => __( 'The site title.' ), + ), + 'description' => array( + 'type' => 'string', + 'description' => __( 'The site tagline.' ), + ), + 'url' => array( + 'type' => 'string', + 'description' => __( 'The site home URL.' ), + ), + 'wpurl' => array( + 'type' => 'string', + 'description' => __( 'The WordPress installation URL.' ), + ), + 'admin_email' => array( + 'type' => 'string', + 'description' => __( 'The site administrator email address.' ), + ), + 'charset' => array( + 'type' => 'string', + 'description' => __( 'The site character encoding.' ), + ), + 'language' => array( + 'type' => 'string', + 'description' => __( 'The site language locale code.' ), + ), + 'version' => array( + 'type' => 'string', + 'description' => __( 'The WordPress version.' ), + ), + ), + 'additionalProperties' => false, + ), + 'execute_callback' => static function ( $input = array() ): array { + $input = is_array( $input ) ? $input : array(); + $all_fields = array( 'name', 'description', 'url', 'wpurl', 'admin_email', 'charset', 'language', 'version' ); + $requested_fields = ! empty( $input['fields'] ) ? $input['fields'] : $all_fields; + + $result = array(); + foreach ( $requested_fields as $field ) { + $result[ $field ] = get_bloginfo( $field ); + } + + return $result; + }, + 'permission_callback' => static function (): bool { + return current_user_can( 'manage_options' ); + }, + 'meta' => array( + 'annotations' => array( + 'readonly' => true, + 'destructive' => false, + 'idempotent' => true, + ), + 'show_in_rest' => true, + ), + ) + ); + + wp_register_ability( + 'core/get-user-info', + array( + 'label' => __( 'Get User Information' ), + 'description' => __( 'Returns basic profile details for the current authenticated user to support personalization, auditing, and access-aware behavior.' ), + 'category' => $category_user, + 'output_schema' => array( + 'type' => 'object', + 'required' => array( 'id', 'display_name', 'user_nicename', 'user_login', 'roles', 'locale' ), + 'properties' => array( + 'id' => array( + 'type' => 'integer', + 'description' => __( 'The user ID.' ), + ), + 'display_name' => array( + 'type' => 'string', + 'description' => __( 'The display name of the user.' ), + ), + 'user_nicename' => array( + 'type' => 'string', + 'description' => __( 'The URL-friendly name for the user.' ), + ), + 'user_login' => array( + 'type' => 'string', + 'description' => __( 'The login username for the user.' ), + ), + 'roles' => array( + 'type' => 'array', + 'description' => __( 'The roles assigned to the user.' ), + 'items' => array( + 'type' => 'string', + ), + ), + 'locale' => array( + 'type' => 'string', + 'description' => __( 'The locale string for the user, such as en_US.' ), + ), + ), + 'additionalProperties' => false, + ), + 'execute_callback' => static function (): array { + $current_user = wp_get_current_user(); + + return array( + 'id' => $current_user->ID, + 'display_name' => $current_user->display_name, + 'user_nicename' => $current_user->user_nicename, + 'user_login' => $current_user->user_login, + 'roles' => $current_user->roles, + 'locale' => get_user_locale( $current_user ), + ); + }, + 'permission_callback' => static function (): bool { + return is_user_logged_in(); + }, + 'meta' => array( + 'annotations' => array( + 'readonly' => true, + 'destructive' => false, + 'idempotent' => true, + ), + 'show_in_rest' => false, + ), + ) + ); + + wp_register_ability( + 'core/get-environment-info', + array( + 'label' => __( 'Get Environment Info' ), + 'description' => __( 'Returns core details about the site\'s runtime context for diagnostics and compatibility (environment, PHP runtime, database server info, WordPress version).' ), + 'category' => $category_site, + 'output_schema' => array( + 'type' => 'object', + 'required' => array( 'environment', 'php_version', 'db_server_info', 'wp_version' ), + 'properties' => array( + 'environment' => array( + 'type' => 'string', + 'description' => __( 'The site\'s runtime environment classification (can be one of these: production, staging, development, local).' ), + 'enum' => array( 'production', 'staging', 'development', 'local' ), + ), + 'php_version' => array( + 'type' => 'string', + 'description' => __( 'The PHP runtime version executing WordPress.' ), + ), + 'db_server_info' => array( + 'type' => 'string', + 'description' => __( 'The database server vendor and version string reported by the driver.' ), + 'examples' => array( '8.0.34', '10.11.6-MariaDB' ), + ), + 'wp_version' => array( + 'type' => 'string', + 'description' => __( 'The WordPress core version running on this site.' ), + ), + ), + 'additionalProperties' => false, + ), + 'execute_callback' => static function (): array { + global $wpdb; + + $env = wp_get_environment_type(); + $php_version = phpversion(); + $db_server_info = ''; + if ( isset( $wpdb ) && is_object( $wpdb ) && method_exists( $wpdb, 'db_server_info' ) ) { + $db_server_info = $wpdb->db_server_info() ?? ''; + } + $wp_version = get_bloginfo( 'version' ); + + return array( + 'environment' => $env, + 'php_version' => $php_version, + 'db_server_info' => $db_server_info, + 'wp_version' => $wp_version, + ); + }, + 'permission_callback' => static function (): bool { + return current_user_can( 'manage_options' ); + }, + 'meta' => array( + 'annotations' => array( + 'readonly' => true, + 'destructive' => false, + 'idempotent' => true, + ), + 'show_in_rest' => true, + ), + ) + ); +} diff --git a/src/wp-includes/default-filters.php b/src/wp-includes/default-filters.php index ba2776506395c..4a386eb53cb65 100644 --- a/src/wp-includes/default-filters.php +++ b/src/wp-includes/default-filters.php @@ -532,6 +532,10 @@ add_action( 'rest_api_init', 'create_initial_rest_routes', 99 ); add_action( 'parse_request', 'rest_api_loaded' ); +// Abilities API. +add_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); +add_action( 'wp_abilities_api_init', 'wp_register_core_abilities' ); + // Sitemaps actions. add_action( 'init', 'wp_sitemaps_get_server' ); diff --git a/src/wp-settings.php b/src/wp-settings.php index 256a0f6791427..471c22b0fd7df 100644 --- a/src/wp-settings.php +++ b/src/wp-settings.php @@ -290,6 +290,7 @@ require ABSPATH . WPINC . '/abilities-api/class-wp-ability.php'; require ABSPATH . WPINC . '/abilities-api/class-wp-abilities-registry.php'; require ABSPATH . WPINC . '/abilities-api.php'; +require ABSPATH . WPINC . '/abilities/wp-core-abilities.php'; require ABSPATH . WPINC . '/rest-api.php'; require ABSPATH . WPINC . '/rest-api/class-wp-rest-server.php'; require ABSPATH . WPINC . '/rest-api/class-wp-rest-response.php'; diff --git a/tests/phpunit/tests/abilities-api/wpCoreAbilities.php b/tests/phpunit/tests/abilities-api/wpCoreAbilities.php new file mode 100644 index 0000000000000..2ca1a441d0dda --- /dev/null +++ b/tests/phpunit/tests/abilities-api/wpCoreAbilities.php @@ -0,0 +1,136 @@ +assertInstanceOf( WP_Ability::class, $ability ); + $this->assertTrue( $ability->get_meta_item( 'show_in_rest', false ) ); + + $input_schema = $ability->get_input_schema(); + $output_schema = $ability->get_output_schema(); + + $this->assertSame( 'object', $input_schema['type'] ); + $this->assertArrayHasKey( 'default', $input_schema ); + $this->assertSame( array(), $input_schema['default'] ); + + // Input schema should have optional fields array. + $this->assertArrayHasKey( 'fields', $input_schema['properties'] ); + $this->assertSame( 'array', $input_schema['properties']['fields']['type'] ); + $this->assertContains( 'name', $input_schema['properties']['fields']['items']['enum'] ); + + // Output schema should have all fields documented. + $this->assertArrayHasKey( 'name', $output_schema['properties'] ); + $this->assertArrayHasKey( 'url', $output_schema['properties'] ); + $this->assertArrayHasKey( 'version', $output_schema['properties'] ); + } + + /** + * Tests executing the `core/get-site-info` ability returns all fields by default. + */ + public function test_core_get_bloginfo_executes(): void { + // Requires manage_options. + $admin_id = self::factory()->user->create( array( 'role' => 'administrator' ) ); + wp_set_current_user( $admin_id ); + + $ability = wp_get_ability( 'core/get-site-info' ); + + // Test without fields parameter - should return all fields. + $result = $ability->execute(); + + $this->assertIsArray( $result ); + $this->assertArrayHasKey( 'name', $result ); + $this->assertArrayHasKey( 'description', $result ); + $this->assertArrayHasKey( 'url', $result ); + $this->assertArrayHasKey( 'version', $result ); + $this->assertSame( get_bloginfo( 'name' ), $result['name'] ); + + // Test with fields parameter - should return only requested fields. + $result = $ability->execute( + array( + 'fields' => array( 'name', 'url' ), + ) + ); + + $this->assertIsArray( $result ); + $this->assertArrayHasKey( 'name', $result ); + $this->assertArrayHasKey( 'url', $result ); + $this->assertArrayNotHasKey( 'description', $result ); + $this->assertArrayNotHasKey( 'version', $result ); + $this->assertSame( get_bloginfo( 'name' ), $result['name'] ); + $this->assertSame( get_bloginfo( 'url' ), $result['url'] ); + + wp_set_current_user( 0 ); + } + + /** + * Tests that executing the current user info ability requires authentication. + */ + public function test_core_get_current_user_info_requires_authentication(): void { + $ability = wp_get_ability( 'core/get-user-info' ); + + $this->assertFalse( $ability->check_permissions() ); + + $result = $ability->execute(); + $this->assertWPError( $result ); + $this->assertSame( 'ability_invalid_permissions', $result->get_error_code() ); + } + + /** + * Tests executing the current user info ability as an authenticated user. + */ + public function test_core_get_current_user_info_returns_user_data(): void { + $user_id = self::factory()->user->create( + array( + 'role' => 'subscriber', + 'locale' => 'fr_FR', + ) + ); + + wp_set_current_user( $user_id ); + + $ability = wp_get_ability( 'core/get-user-info' ); + + $this->assertTrue( $ability->check_permissions() ); + + $result = $ability->execute(); + $this->assertSame( $user_id, $result['id'] ); + $this->assertSame( 'fr_FR', $result['locale'] ); + $this->assertSame( 'subscriber', $result['roles'][0] ); + $this->assertSame( get_userdata( $user_id )->display_name, $result['display_name'] ); + + wp_set_current_user( 0 ); + } + + /** + * Tests executing the environment info ability. + */ + public function test_core_get_environment_type_executes(): void { + // Requires manage_options. + $admin_id = self::factory()->user->create( array( 'role' => 'administrator' ) ); + wp_set_current_user( $admin_id ); + + $ability = wp_get_ability( 'core/get-environment-info' ); + $environment = wp_get_environment_type(); + $ability_data = $ability->execute(); + + $this->assertIsArray( $ability_data ); + $this->assertArrayHasKey( 'environment', $ability_data ); + $this->assertArrayHasKey( 'php_version', $ability_data ); + $this->assertArrayHasKey( 'db_server_info', $ability_data ); + $this->assertArrayHasKey( 'wp_version', $ability_data ); + $this->assertSame( $environment, $ability_data['environment'] ); + + wp_set_current_user( 0 ); + } + +} From 0a15be141b45c478b593a861a6eaea3c4dac9662 Mon Sep 17 00:00:00 2001 From: Jorge Costa Date: Fri, 24 Oct 2025 09:59:42 +0100 Subject: [PATCH 02/20] correct version field --- src/wp-includes/abilities/wp-core-abilities.php | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/wp-includes/abilities/wp-core-abilities.php b/src/wp-includes/abilities/wp-core-abilities.php index 586f629dbdaa3..44c3527677327 100644 --- a/src/wp-includes/abilities/wp-core-abilities.php +++ b/src/wp-includes/abilities/wp-core-abilities.php @@ -4,18 +4,17 @@ * * @package WordPress * @subpackage Abilities_API - * @since 0.3.0 + * @since 6.9.0 */ declare( strict_types = 1 ); /** * Registers the core abilities categories. * - * @since 0.3.0 + * @since 6.9.0 * * @return void */ -// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound function wp_register_core_ability_categories(): void { wp_register_ability_category( 'site', @@ -37,11 +36,10 @@ function wp_register_core_ability_categories(): void { /** * Registers the default core abilities. * - * @since 0.3.0 + * @since 6.9.0 * * @return void */ -// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound function wp_register_core_abilities(): void { $category_site = 'site'; $category_user = 'user'; From 9427ec6ba6a7efc792f3e5dfa2380ed9efac29b7 Mon Sep 17 00:00:00 2001 From: Jorge Costa Date: Fri, 24 Oct 2025 10:03:03 +0100 Subject: [PATCH 03/20] lint fix --- .../tests/abilities-api/wpCoreAbilities.php | 81 +++++++++---------- 1 file changed, 40 insertions(+), 41 deletions(-) diff --git a/tests/phpunit/tests/abilities-api/wpCoreAbilities.php b/tests/phpunit/tests/abilities-api/wpCoreAbilities.php index 2ca1a441d0dda..2287ef5725ce5 100644 --- a/tests/phpunit/tests/abilities-api/wpCoreAbilities.php +++ b/tests/phpunit/tests/abilities-api/wpCoreAbilities.php @@ -8,10 +8,10 @@ class Tests_Abilities_API_WpCoreAbilities extends WP_UnitTestCase { /** - * Tests that the `core/get-site-info` ability is registered with the expected schema. - */ - public function test_core_get_bloginfo_ability_is_registered(): void { - $ability = wp_get_ability( 'core/get-site-info' ); + * Tests that the `core/get-site-info` ability is registered with the expected schema. + */ + public function test_core_get_bloginfo_ability_is_registered(): void { + $ability = wp_get_ability( 'core/get-site-info' ); $this->assertInstanceOf( WP_Ability::class, $ability ); $this->assertTrue( $ability->get_meta_item( 'show_in_rest', false ) ); @@ -35,14 +35,14 @@ public function test_core_get_bloginfo_ability_is_registered(): void { } /** - * Tests executing the `core/get-site-info` ability returns all fields by default. - */ - public function test_core_get_bloginfo_executes(): void { - // Requires manage_options. - $admin_id = self::factory()->user->create( array( 'role' => 'administrator' ) ); - wp_set_current_user( $admin_id ); + * Tests executing the `core/get-site-info` ability returns all fields by default. + */ + public function test_core_get_bloginfo_executes(): void { + // Requires manage_options. + $admin_id = self::factory()->user->create( array( 'role' => 'administrator' ) ); + wp_set_current_user( $admin_id ); - $ability = wp_get_ability( 'core/get-site-info' ); + $ability = wp_get_ability( 'core/get-site-info' ); // Test without fields parameter - should return all fields. $result = $ability->execute(); @@ -69,14 +69,14 @@ public function test_core_get_bloginfo_executes(): void { $this->assertSame( get_bloginfo( 'name' ), $result['name'] ); $this->assertSame( get_bloginfo( 'url' ), $result['url'] ); - wp_set_current_user( 0 ); - } + wp_set_current_user( 0 ); + } /** - * Tests that executing the current user info ability requires authentication. - */ - public function test_core_get_current_user_info_requires_authentication(): void { - $ability = wp_get_ability( 'core/get-user-info' ); + * Tests that executing the current user info ability requires authentication. + */ + public function test_core_get_current_user_info_requires_authentication(): void { + $ability = wp_get_ability( 'core/get-user-info' ); $this->assertFalse( $ability->check_permissions() ); @@ -86,9 +86,9 @@ public function test_core_get_current_user_info_requires_authentication(): void } /** - * Tests executing the current user info ability as an authenticated user. - */ - public function test_core_get_current_user_info_returns_user_data(): void { + * Tests executing the current user info ability as an authenticated user. + */ + public function test_core_get_current_user_info_returns_user_data(): void { $user_id = self::factory()->user->create( array( 'role' => 'subscriber', @@ -98,7 +98,7 @@ public function test_core_get_current_user_info_returns_user_data(): void { wp_set_current_user( $user_id ); - $ability = wp_get_ability( 'core/get-user-info' ); + $ability = wp_get_ability( 'core/get-user-info' ); $this->assertTrue( $ability->check_permissions() ); @@ -112,25 +112,24 @@ public function test_core_get_current_user_info_returns_user_data(): void { } /** - * Tests executing the environment info ability. - */ - public function test_core_get_environment_type_executes(): void { - // Requires manage_options. - $admin_id = self::factory()->user->create( array( 'role' => 'administrator' ) ); - wp_set_current_user( $admin_id ); - - $ability = wp_get_ability( 'core/get-environment-info' ); - $environment = wp_get_environment_type(); - $ability_data = $ability->execute(); - - $this->assertIsArray( $ability_data ); - $this->assertArrayHasKey( 'environment', $ability_data ); - $this->assertArrayHasKey( 'php_version', $ability_data ); - $this->assertArrayHasKey( 'db_server_info', $ability_data ); - $this->assertArrayHasKey( 'wp_version', $ability_data ); - $this->assertSame( $environment, $ability_data['environment'] ); - - wp_set_current_user( 0 ); - } + * Tests executing the environment info ability. + */ + public function test_core_get_environment_type_executes(): void { + // Requires manage_options. + $admin_id = self::factory()->user->create( array( 'role' => 'administrator' ) ); + wp_set_current_user( $admin_id ); + + $ability = wp_get_ability( 'core/get-environment-info' ); + $environment = wp_get_environment_type(); + $ability_data = $ability->execute(); + + $this->assertIsArray( $ability_data ); + $this->assertArrayHasKey( 'environment', $ability_data ); + $this->assertArrayHasKey( 'php_version', $ability_data ); + $this->assertArrayHasKey( 'db_server_info', $ability_data ); + $this->assertArrayHasKey( 'wp_version', $ability_data ); + $this->assertSame( $environment, $ability_data['environment'] ); + wp_set_current_user( 0 ); + } } From ca040810da63a147d5779c689b49f61bc0f8f1ce Mon Sep 17 00:00:00 2001 From: Jorge Costa Date: Fri, 24 Oct 2025 10:26:28 +0100 Subject: [PATCH 04/20] fix wpRegisterAbility tests --- .../tests/abilities-api/wpRegisterAbilityCategory.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/phpunit/tests/abilities-api/wpRegisterAbilityCategory.php b/tests/phpunit/tests/abilities-api/wpRegisterAbilityCategory.php index ede55f98eaeaf..980a30643a68b 100644 --- a/tests/phpunit/tests/abilities-api/wpRegisterAbilityCategory.php +++ b/tests/phpunit/tests/abilities-api/wpRegisterAbilityCategory.php @@ -26,6 +26,12 @@ public function set_up(): void { 'label' => 'Math', 'description' => 'Mathematical operations.', ); + + // Unregister all ability categories to ensure a clean slate for each test. + foreach ( wp_get_ability_categories() as $ability_category ) { + wp_unregister_ability_category( $ability_category->get_slug() ); + } + remove_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); } /** @@ -52,6 +58,10 @@ public function tear_down(): void { * @expectedIncorrectUsage wp_register_ability_category */ public function test_register_category_before_init_hook(): void { + // simulate that the 'wp_abilities_api_categories_init' action has not yet fired. + global $wp_actions; + $wp_actions[ 'wp_abilities_api_categories_init' ] = 0; + $result = wp_register_ability_category( self::$test_ability_category_name, self::$test_ability_category_args From fd17d0126412c6f191f1c22904971e0646526868 Mon Sep 17 00:00:00 2001 From: Jorge Costa Date: Fri, 24 Oct 2025 10:31:24 +0100 Subject: [PATCH 05/20] additional test fixes --- .../tests/abilities-api/wpAbilitiesRegistry.php | 5 +++++ tests/phpunit/tests/abilities-api/wpAbility.php | 5 +++++ .../phpunit/tests/abilities-api/wpRegisterAbility.php | 5 +++++ .../rest-api/wpRestAbilitiesV1CategoriesController.php | 5 +++++ .../tests/rest-api/wpRestAbilitiesV1ListController.php | 10 ++++++++++ .../tests/rest-api/wpRestAbilitiesV1RunController.php | 10 ++++++++++ 6 files changed, 40 insertions(+) diff --git a/tests/phpunit/tests/abilities-api/wpAbilitiesRegistry.php b/tests/phpunit/tests/abilities-api/wpAbilitiesRegistry.php index 95fa29a20d9f3..2972a6a2b0f52 100644 --- a/tests/phpunit/tests/abilities-api/wpAbilitiesRegistry.php +++ b/tests/phpunit/tests/abilities-api/wpAbilitiesRegistry.php @@ -29,6 +29,11 @@ public function set_up(): void { remove_all_filters( 'wp_register_ability_args' ); + // Unregister all ability categories to ensure a clean slate for each test. + foreach ( wp_get_ability_categories() as $ability_category ) { + wp_unregister_ability_category( $ability_category->get_slug() ); + } + // Fire the init hook to allow test ability category registration. do_action( 'wp_abilities_api_categories_init' ); wp_register_ability_category( diff --git a/tests/phpunit/tests/abilities-api/wpAbility.php b/tests/phpunit/tests/abilities-api/wpAbility.php index 910ae7dad06fe..01c1e6fdabac1 100644 --- a/tests/phpunit/tests/abilities-api/wpAbility.php +++ b/tests/phpunit/tests/abilities-api/wpAbility.php @@ -18,6 +18,11 @@ class Tests_Abilities_API_WpAbility extends WP_UnitTestCase { public function set_up(): void { parent::set_up(); + // Unregister all ability categories to ensure a clean slate for each test. + foreach ( wp_get_ability_categories() as $ability_category ) { + wp_unregister_ability_category( $ability_category->get_slug() ); + } + // Fire the init hook to allow test ability category registration. do_action( 'wp_abilities_api_categories_init' ); wp_register_ability_category( diff --git a/tests/phpunit/tests/abilities-api/wpRegisterAbility.php b/tests/phpunit/tests/abilities-api/wpRegisterAbility.php index 21b108f5ac8f9..0c3b3e49899d0 100644 --- a/tests/phpunit/tests/abilities-api/wpRegisterAbility.php +++ b/tests/phpunit/tests/abilities-api/wpRegisterAbility.php @@ -31,6 +31,11 @@ class Test_Abilities_API_WpRegisterAbility extends WP_UnitTestCase { public function set_up(): void { parent::set_up(); + // Unregister all ability categories to ensure a clean slate for each test. + foreach ( wp_get_ability_categories() as $ability_category ) { + wp_unregister_ability_category( $ability_category->get_slug() ); + } + // Fire the init hook to allow test ability category registration. do_action( 'wp_abilities_api_categories_init' ); wp_register_ability_category( diff --git a/tests/phpunit/tests/rest-api/wpRestAbilitiesV1CategoriesController.php b/tests/phpunit/tests/rest-api/wpRestAbilitiesV1CategoriesController.php index a6b7f233ceebf..5d28d0acd11b9 100644 --- a/tests/phpunit/tests/rest-api/wpRestAbilitiesV1CategoriesController.php +++ b/tests/phpunit/tests/rest-api/wpRestAbilitiesV1CategoriesController.php @@ -62,6 +62,11 @@ public function set_up(): void { do_action( 'rest_api_init' ); + // Unregister all ability categories to ensure a clean slate for each test. + foreach ( wp_get_ability_categories() as $ability_category ) { + wp_unregister_ability_category( $ability_category->get_slug() ); + } + // Initialize the API and register test ability categories. do_action( 'wp_abilities_api_categories_init' ); $this->register_test_ability_categories(); diff --git a/tests/phpunit/tests/rest-api/wpRestAbilitiesV1ListController.php b/tests/phpunit/tests/rest-api/wpRestAbilitiesV1ListController.php index a6e5d92f270b7..cc6dbb677815b 100644 --- a/tests/phpunit/tests/rest-api/wpRestAbilitiesV1ListController.php +++ b/tests/phpunit/tests/rest-api/wpRestAbilitiesV1ListController.php @@ -67,6 +67,16 @@ public function set_up(): void { do_action( 'rest_api_init' ); + // Unregister all abilities to ensure a clean slate for each test. + foreach ( wp_get_abilities() as $ability ) { + wp_unregister_ability( $ability->get_name() ); + } + + // Unregister all ability categories to ensure a clean slate for each test. + foreach ( wp_get_ability_categories() as $ability_category ) { + wp_unregister_ability_category( $ability_category->get_slug() ); + } + // Initialize Abilities API. do_action( 'wp_abilities_api_init' ); $this->register_test_abilities(); diff --git a/tests/phpunit/tests/rest-api/wpRestAbilitiesV1RunController.php b/tests/phpunit/tests/rest-api/wpRestAbilitiesV1RunController.php index 40372fe57b4be..193295168e028 100644 --- a/tests/phpunit/tests/rest-api/wpRestAbilitiesV1RunController.php +++ b/tests/phpunit/tests/rest-api/wpRestAbilitiesV1RunController.php @@ -78,6 +78,16 @@ public function set_up(): void { do_action( 'rest_api_init' ); + // Unregister all abilities to ensure a clean slate for each test. + foreach ( wp_get_abilities() as $ability ) { + wp_unregister_ability( $ability->get_name() ); + } + + // Unregister all ability categories to ensure a clean slate for each test. + foreach ( wp_get_ability_categories() as $ability_category ) { + wp_unregister_ability_category( $ability_category->get_slug() ); + } + // Initialize Abilities API. do_action( 'wp_abilities_api_init' ); $this->register_test_abilities(); From ec22568a2fda0b730588dcea38d2c3dcc34c7645 Mon Sep 17 00:00:00 2001 From: Jorge Costa Date: Fri, 24 Oct 2025 10:57:10 +0100 Subject: [PATCH 06/20] in progress test fixes --- .../phpunit/tests/abilities-api/wpAbilitiesRegistry.php | 7 +++++++ tests/phpunit/tests/abilities-api/wpAbility.php | 7 +++++++ tests/phpunit/tests/abilities-api/wpRegisterAbility.php | 7 +++++++ .../tests/abilities-api/wpRegisterAbilityCategory.php | 4 ++++ .../rest-api/wpRestAbilitiesV1CategoriesController.php | 9 ++++++++- .../tests/rest-api/wpRestAbilitiesV1ListController.php | 9 +++++++++ .../tests/rest-api/wpRestAbilitiesV1RunController.php | 9 +++++++++ 7 files changed, 51 insertions(+), 1 deletion(-) diff --git a/tests/phpunit/tests/abilities-api/wpAbilitiesRegistry.php b/tests/phpunit/tests/abilities-api/wpAbilitiesRegistry.php index 2972a6a2b0f52..2a40122fdf8da 100644 --- a/tests/phpunit/tests/abilities-api/wpAbilitiesRegistry.php +++ b/tests/phpunit/tests/abilities-api/wpAbilitiesRegistry.php @@ -34,6 +34,9 @@ public function set_up(): void { wp_unregister_ability_category( $ability_category->get_slug() ); } + // Remove core registration action to prevent re-registration. + remove_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); + // Fire the init hook to allow test ability category registration. do_action( 'wp_abilities_api_categories_init' ); wp_register_ability_category( @@ -92,6 +95,10 @@ public function tear_down(): void { // Clean up registered test ability category. wp_unregister_ability_category( 'math' ); + // Re-add core registration action and re-register core categories. + add_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); + do_action( 'wp_abilities_api_categories_init' ); + parent::tear_down(); } diff --git a/tests/phpunit/tests/abilities-api/wpAbility.php b/tests/phpunit/tests/abilities-api/wpAbility.php index 01c1e6fdabac1..dae2e02f2ee64 100644 --- a/tests/phpunit/tests/abilities-api/wpAbility.php +++ b/tests/phpunit/tests/abilities-api/wpAbility.php @@ -23,6 +23,9 @@ public function set_up(): void { wp_unregister_ability_category( $ability_category->get_slug() ); } + // Remove core registration action to prevent re-registration. + remove_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); + // Fire the init hook to allow test ability category registration. do_action( 'wp_abilities_api_categories_init' ); wp_register_ability_category( @@ -64,6 +67,10 @@ public function tear_down(): void { // Clean up registered test ability category. wp_unregister_ability_category( 'math' ); + // Re-add core registration action and re-register core categories. + add_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); + do_action( 'wp_abilities_api_categories_init' ); + parent::tear_down(); } diff --git a/tests/phpunit/tests/abilities-api/wpRegisterAbility.php b/tests/phpunit/tests/abilities-api/wpRegisterAbility.php index 0c3b3e49899d0..cfcf3b1f3cbb7 100644 --- a/tests/phpunit/tests/abilities-api/wpRegisterAbility.php +++ b/tests/phpunit/tests/abilities-api/wpRegisterAbility.php @@ -36,6 +36,9 @@ public function set_up(): void { wp_unregister_ability_category( $ability_category->get_slug() ); } + // Remove core registration action to prevent re-registration. + remove_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); + // Fire the init hook to allow test ability category registration. do_action( 'wp_abilities_api_categories_init' ); wp_register_ability_category( @@ -102,6 +105,10 @@ public function tear_down(): void { // Clean up registered test ability category. wp_unregister_ability_category( 'math' ); + // Re-add core registration action and re-register core categories. + add_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); + do_action( 'wp_abilities_api_categories_init' ); + parent::tear_down(); } diff --git a/tests/phpunit/tests/abilities-api/wpRegisterAbilityCategory.php b/tests/phpunit/tests/abilities-api/wpRegisterAbilityCategory.php index 980a30643a68b..2059978fcd035 100644 --- a/tests/phpunit/tests/abilities-api/wpRegisterAbilityCategory.php +++ b/tests/phpunit/tests/abilities-api/wpRegisterAbilityCategory.php @@ -47,6 +47,10 @@ public function tear_down(): void { wp_unregister_ability_category( $ability_category->get_slug() ); } + // Re-add core registration action and re-register core categories. + add_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); + do_action( 'wp_abilities_api_categories_init' ); + parent::tear_down(); } diff --git a/tests/phpunit/tests/rest-api/wpRestAbilitiesV1CategoriesController.php b/tests/phpunit/tests/rest-api/wpRestAbilitiesV1CategoriesController.php index 5d28d0acd11b9..f96085087f748 100644 --- a/tests/phpunit/tests/rest-api/wpRestAbilitiesV1CategoriesController.php +++ b/tests/phpunit/tests/rest-api/wpRestAbilitiesV1CategoriesController.php @@ -25,7 +25,7 @@ class Tests_REST_API_WpRestAbilitiesV1CategoriesController extends WP_UnitTestCa protected static $admin_user_id; /** - * Test subscriber user ID. + * Test subscriber user ID.x * * @var int */ @@ -67,6 +67,9 @@ public function set_up(): void { wp_unregister_ability_category( $ability_category->get_slug() ); } + // Remove core registration action to prevent re-registration. + remove_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); + // Initialize the API and register test ability categories. do_action( 'wp_abilities_api_categories_init' ); $this->register_test_ability_categories(); @@ -88,6 +91,10 @@ public function tear_down(): void { wp_unregister_ability_category( $ability_category->get_slug() ); } + // Re-add core registration action and re-register core categories. + add_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); + do_action( 'wp_abilities_api_categories_init' ); + global $wp_rest_server; $wp_rest_server = null; diff --git a/tests/phpunit/tests/rest-api/wpRestAbilitiesV1ListController.php b/tests/phpunit/tests/rest-api/wpRestAbilitiesV1ListController.php index cc6dbb677815b..640e9b8f5d847 100644 --- a/tests/phpunit/tests/rest-api/wpRestAbilitiesV1ListController.php +++ b/tests/phpunit/tests/rest-api/wpRestAbilitiesV1ListController.php @@ -77,6 +77,10 @@ public function set_up(): void { wp_unregister_ability_category( $ability_category->get_slug() ); } + // Remove core registration actions to prevent re-registration. + remove_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); + remove_action( 'wp_abilities_api_init', 'wp_register_core_abilities' ); + // Initialize Abilities API. do_action( 'wp_abilities_api_init' ); $this->register_test_abilities(); @@ -98,6 +102,11 @@ public function tear_down(): void { wp_unregister_ability( $ability->get_name() ); } + // Re-add core registration actions and re-register core abilities. + add_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); + add_action( 'wp_abilities_api_init', 'wp_register_core_abilities' ); + do_action( 'wp_abilities_api_init' ); + // Reset REST server global $wp_rest_server; $wp_rest_server = null; diff --git a/tests/phpunit/tests/rest-api/wpRestAbilitiesV1RunController.php b/tests/phpunit/tests/rest-api/wpRestAbilitiesV1RunController.php index 193295168e028..50c3a4b62dbb8 100644 --- a/tests/phpunit/tests/rest-api/wpRestAbilitiesV1RunController.php +++ b/tests/phpunit/tests/rest-api/wpRestAbilitiesV1RunController.php @@ -88,6 +88,10 @@ public function set_up(): void { wp_unregister_ability_category( $ability_category->get_slug() ); } + // Remove core registration actions to prevent re-registration. + remove_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); + remove_action( 'wp_abilities_api_init', 'wp_register_core_abilities' ); + // Initialize Abilities API. do_action( 'wp_abilities_api_init' ); $this->register_test_abilities(); @@ -109,6 +113,11 @@ public function tear_down(): void { wp_unregister_ability( $ability->get_name() ); } + // Re-add core registration actions and re-register core abilities. + add_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); + add_action( 'wp_abilities_api_init', 'wp_register_core_abilities' ); + do_action( 'wp_abilities_api_init' ); + global $wp_rest_server; $wp_rest_server = null; From 16d94b863fb333f031a1c115e86cd7c779361001 Mon Sep 17 00:00:00 2001 From: Jorge Costa Date: Fri, 24 Oct 2025 10:57:26 +0100 Subject: [PATCH 07/20] in progress test fixes From ec261bb46b3292848ef0ff832a1441b89b27614f Mon Sep 17 00:00:00 2001 From: Jorge Costa Date: Fri, 24 Oct 2025 16:22:44 +0100 Subject: [PATCH 08/20] middle most tests working --- .../wpRestAbilitiesV1ListController.php | 17 ++++++++--------- .../rest-api/wpRestAbilitiesV1RunController.php | 17 ++++++++--------- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/tests/phpunit/tests/rest-api/wpRestAbilitiesV1ListController.php b/tests/phpunit/tests/rest-api/wpRestAbilitiesV1ListController.php index 640e9b8f5d847..3541991b96542 100644 --- a/tests/phpunit/tests/rest-api/wpRestAbilitiesV1ListController.php +++ b/tests/phpunit/tests/rest-api/wpRestAbilitiesV1ListController.php @@ -36,21 +36,12 @@ public static function set_up_before_class(): void { 'role' => 'subscriber', ) ); - - // Fire the init hook to allow test ability categories registration. - do_action( 'wp_abilities_api_categories_init' ); - self::register_test_categories(); } /** * Tear down after class. */ public static function tear_down_after_class(): void { - // Clean up registered test ability categories. - foreach ( array( 'math', 'system', 'general' ) as $slug ) { - wp_unregister_ability_category( $slug ); - } - parent::tear_down_after_class(); } @@ -81,8 +72,16 @@ public function set_up(): void { remove_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); remove_action( 'wp_abilities_api_init', 'wp_register_core_abilities' ); + // Fire categories init to trigger internal setup (happens inside get_instance). + do_action( 'wp_abilities_api_categories_init' ); + + // Register test categories after the init. + self::register_test_categories(); + // Initialize Abilities API. do_action( 'wp_abilities_api_init' ); + + // Register test abilities. $this->register_test_abilities(); // Set default user for tests diff --git a/tests/phpunit/tests/rest-api/wpRestAbilitiesV1RunController.php b/tests/phpunit/tests/rest-api/wpRestAbilitiesV1RunController.php index 50c3a4b62dbb8..b22d85bde3ca3 100644 --- a/tests/phpunit/tests/rest-api/wpRestAbilitiesV1RunController.php +++ b/tests/phpunit/tests/rest-api/wpRestAbilitiesV1RunController.php @@ -48,21 +48,12 @@ public static function set_up_before_class(): void { 'role' => 'subscriber', ) ); - - // Fire the init hook to allow test ability categories registration. - do_action( 'wp_abilities_api_categories_init' ); - self::register_test_categories(); } /** * Tear down after class. */ public static function tear_down_after_class(): void { - // Clean up registered test ability categories. - foreach ( array( 'math', 'system', 'general' ) as $slug ) { - wp_unregister_ability_category( $slug ); - } - parent::tear_down_after_class(); } @@ -92,8 +83,16 @@ public function set_up(): void { remove_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); remove_action( 'wp_abilities_api_init', 'wp_register_core_abilities' ); + // Fire categories init to trigger internal setup (happens inside get_instance). + do_action( 'wp_abilities_api_categories_init' ); + + // Register test categories after the init. + self::register_test_categories(); + // Initialize Abilities API. do_action( 'wp_abilities_api_init' ); + + // Register test abilities. $this->register_test_abilities(); // Set default user for tests From bbc0ae2168c75bde187b05f429bdd4a705b68b47 Mon Sep 17 00:00:00 2001 From: Jorge Costa Date: Fri, 24 Oct 2025 16:31:58 +0100 Subject: [PATCH 09/20] one failure --- .../tests/abilities-api/wpAbilitiesRegistry.php | 6 ++++-- tests/phpunit/tests/abilities-api/wpAbility.php | 6 ++++-- .../tests/abilities-api/wpRegisterAbility.php | 12 ++++++++++-- .../rest-api/wpRestAbilitiesV1ListController.php | 10 ++++++++++ .../rest-api/wpRestAbilitiesV1RunController.php | 10 ++++++++++ 5 files changed, 38 insertions(+), 6 deletions(-) diff --git a/tests/phpunit/tests/abilities-api/wpAbilitiesRegistry.php b/tests/phpunit/tests/abilities-api/wpAbilitiesRegistry.php index 2a40122fdf8da..d096201959b77 100644 --- a/tests/phpunit/tests/abilities-api/wpAbilitiesRegistry.php +++ b/tests/phpunit/tests/abilities-api/wpAbilitiesRegistry.php @@ -34,8 +34,9 @@ public function set_up(): void { wp_unregister_ability_category( $ability_category->get_slug() ); } - // Remove core registration action to prevent re-registration. + // Remove core registration actions to prevent re-registration. remove_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); + remove_action( 'wp_abilities_api_init', 'wp_register_core_abilities' ); // Fire the init hook to allow test ability category registration. do_action( 'wp_abilities_api_categories_init' ); @@ -95,8 +96,9 @@ public function tear_down(): void { // Clean up registered test ability category. wp_unregister_ability_category( 'math' ); - // Re-add core registration action and re-register core categories. + // Re-add core registration actions and re-register core categories and abilities. add_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); + add_action( 'wp_abilities_api_init', 'wp_register_core_abilities' ); do_action( 'wp_abilities_api_categories_init' ); parent::tear_down(); diff --git a/tests/phpunit/tests/abilities-api/wpAbility.php b/tests/phpunit/tests/abilities-api/wpAbility.php index dae2e02f2ee64..32942b155173d 100644 --- a/tests/phpunit/tests/abilities-api/wpAbility.php +++ b/tests/phpunit/tests/abilities-api/wpAbility.php @@ -23,8 +23,9 @@ public function set_up(): void { wp_unregister_ability_category( $ability_category->get_slug() ); } - // Remove core registration action to prevent re-registration. + // Remove core registration actions to prevent re-registration. remove_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); + remove_action( 'wp_abilities_api_init', 'wp_register_core_abilities' ); // Fire the init hook to allow test ability category registration. do_action( 'wp_abilities_api_categories_init' ); @@ -67,8 +68,9 @@ public function tear_down(): void { // Clean up registered test ability category. wp_unregister_ability_category( 'math' ); - // Re-add core registration action and re-register core categories. + // Re-add core registration actions and re-register core categories and abilities. add_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); + add_action( 'wp_abilities_api_init', 'wp_register_core_abilities' ); do_action( 'wp_abilities_api_categories_init' ); parent::tear_down(); diff --git a/tests/phpunit/tests/abilities-api/wpRegisterAbility.php b/tests/phpunit/tests/abilities-api/wpRegisterAbility.php index cfcf3b1f3cbb7..e844650868530 100644 --- a/tests/phpunit/tests/abilities-api/wpRegisterAbility.php +++ b/tests/phpunit/tests/abilities-api/wpRegisterAbility.php @@ -36,8 +36,9 @@ public function set_up(): void { wp_unregister_ability_category( $ability_category->get_slug() ); } - // Remove core registration action to prevent re-registration. + // Remove core registration actions to prevent re-registration. remove_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); + remove_action( 'wp_abilities_api_init', 'wp_register_core_abilities' ); // Fire the init hook to allow test ability category registration. do_action( 'wp_abilities_api_categories_init' ); @@ -105,8 +106,9 @@ public function tear_down(): void { // Clean up registered test ability category. wp_unregister_ability_category( 'math' ); - // Re-add core registration action and re-register core categories. + // Re-add core registration actions and re-register core categories and abilities. add_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); + add_action( 'wp_abilities_api_init', 'wp_register_core_abilities' ); do_action( 'wp_abilities_api_categories_init' ); parent::tear_down(); @@ -533,6 +535,10 @@ public function test_get_existing_ability_using_callback() { add_action( 'wp_abilities_api_init', $callback ); + // Re-add core registration actions since we're resetting the registry. + add_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); + add_action( 'wp_abilities_api_init', 'wp_register_core_abilities' ); + // Reset the Registry, to ensure it's empty before the test. $registry_reflection = new ReflectionClass( WP_Abilities_Registry::class ); $instance_prop = $registry_reflection->getProperty( 'instance' ); @@ -544,6 +550,8 @@ public function test_get_existing_ability_using_callback() { $result = wp_get_ability( $name ); remove_action( 'wp_abilities_api_init', $callback ); + remove_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); + remove_action( 'wp_abilities_api_init', 'wp_register_core_abilities' ); $this->assertEquals( new WP_Ability( $name, $args ), diff --git a/tests/phpunit/tests/rest-api/wpRestAbilitiesV1ListController.php b/tests/phpunit/tests/rest-api/wpRestAbilitiesV1ListController.php index 3541991b96542..66f0a2690834c 100644 --- a/tests/phpunit/tests/rest-api/wpRestAbilitiesV1ListController.php +++ b/tests/phpunit/tests/rest-api/wpRestAbilitiesV1ListController.php @@ -101,6 +101,16 @@ public function tear_down(): void { wp_unregister_ability( $ability->get_name() ); } + // Clean up test ability categories. + foreach ( wp_get_ability_categories() as $ability_category ) { + $slug = $ability_category->get_slug(); + if ( ! str_starts_with( $slug, 'test-' ) && ! in_array( $slug, array( 'math', 'system', 'general' ), true ) ) { + continue; + } + + wp_unregister_ability_category( $slug ); + } + // Re-add core registration actions and re-register core abilities. add_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); add_action( 'wp_abilities_api_init', 'wp_register_core_abilities' ); diff --git a/tests/phpunit/tests/rest-api/wpRestAbilitiesV1RunController.php b/tests/phpunit/tests/rest-api/wpRestAbilitiesV1RunController.php index b22d85bde3ca3..041917f8c93aa 100644 --- a/tests/phpunit/tests/rest-api/wpRestAbilitiesV1RunController.php +++ b/tests/phpunit/tests/rest-api/wpRestAbilitiesV1RunController.php @@ -112,6 +112,16 @@ public function tear_down(): void { wp_unregister_ability( $ability->get_name() ); } + // Clean up test ability categories. + foreach ( wp_get_ability_categories() as $ability_category ) { + $slug = $ability_category->get_slug(); + if ( ! str_starts_with( $slug, 'test-' ) && ! in_array( $slug, array( 'math', 'system', 'general' ), true ) ) { + continue; + } + + wp_unregister_ability_category( $slug ); + } + // Re-add core registration actions and re-register core abilities. add_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); add_action( 'wp_abilities_api_init', 'wp_register_core_abilities' ); From 6a5562c493e2d639f9b63704d6e16b32b3e9a2a5 Mon Sep 17 00:00:00 2001 From: Jorge Costa Date: Fri, 24 Oct 2025 16:41:26 +0100 Subject: [PATCH 10/20] fix remaning test case --- .../tests/abilities-api/wpRegisterAbility.php | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/tests/phpunit/tests/abilities-api/wpRegisterAbility.php b/tests/phpunit/tests/abilities-api/wpRegisterAbility.php index e844650868530..5ab58181ce229 100644 --- a/tests/phpunit/tests/abilities-api/wpRegisterAbility.php +++ b/tests/phpunit/tests/abilities-api/wpRegisterAbility.php @@ -535,23 +535,13 @@ public function test_get_existing_ability_using_callback() { add_action( 'wp_abilities_api_init', $callback ); - // Re-add core registration actions since we're resetting the registry. - add_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); - add_action( 'wp_abilities_api_init', 'wp_register_core_abilities' ); - - // Reset the Registry, to ensure it's empty before the test. - $registry_reflection = new ReflectionClass( WP_Abilities_Registry::class ); - $instance_prop = $registry_reflection->getProperty( 'instance' ); - if ( PHP_VERSION_ID < 80100 ) { - $instance_prop->setAccessible( true ); - } - $instance_prop->setValue( null, null ); + // Fire the init action - this triggers the callback. + do_action( 'wp_abilities_api_init' ); + // Now get the ability. $result = wp_get_ability( $name ); remove_action( 'wp_abilities_api_init', $callback ); - remove_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); - remove_action( 'wp_abilities_api_init', 'wp_register_core_abilities' ); $this->assertEquals( new WP_Ability( $name, $args ), From 527bc405a7a6acff5c731c4fa04893b3549a74bf Mon Sep 17 00:00:00 2001 From: Jorge Costa Date: Fri, 24 Oct 2025 16:42:37 +0100 Subject: [PATCH 11/20] Update tests/phpunit/tests/abilities-api/wpCoreAbilities.php Co-authored-by: Mukesh Panchal --- tests/phpunit/tests/abilities-api/wpCoreAbilities.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/phpunit/tests/abilities-api/wpCoreAbilities.php b/tests/phpunit/tests/abilities-api/wpCoreAbilities.php index 2287ef5725ce5..bd52278f8d7b9 100644 --- a/tests/phpunit/tests/abilities-api/wpCoreAbilities.php +++ b/tests/phpunit/tests/abilities-api/wpCoreAbilities.php @@ -1,4 +1,6 @@ - Date: Fri, 24 Oct 2025 16:44:25 +0100 Subject: [PATCH 12/20] Update src/wp-includes/abilities/wp-core-abilities.php MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Greg Ziółkowski --- src/wp-includes/abilities/wp-core-abilities.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/abilities/wp-core-abilities.php b/src/wp-includes/abilities/wp-core-abilities.php index 44c3527677327..a775964e1d36d 100644 --- a/src/wp-includes/abilities/wp-core-abilities.php +++ b/src/wp-includes/abilities/wp-core-abilities.php @@ -9,7 +9,7 @@ declare( strict_types = 1 ); /** - * Registers the core abilities categories. + * Registers the core ability categories. * * @since 6.9.0 * From 9269d56f39ec428138f913dfa483924cb367e374 Mon Sep 17 00:00:00 2001 From: Jorge Costa Date: Fri, 24 Oct 2025 17:10:02 +0100 Subject: [PATCH 13/20] test fixes different appraoch --- tests/phpunit/includes/functions.php | 24 +++++++++++++++++++ .../abilities-api/wpAbilitiesRegistry.php | 10 ++++++-- .../phpunit/tests/abilities-api/wpAbility.php | 10 ++++++-- .../tests/abilities-api/wpCoreAbilities.php | 22 +++++++++++++++++ .../tests/abilities-api/wpRegisterAbility.php | 10 ++++++-- 5 files changed, 70 insertions(+), 6 deletions(-) diff --git a/tests/phpunit/includes/functions.php b/tests/phpunit/includes/functions.php index 898f1214ab15a..3a18a716cb863 100644 --- a/tests/phpunit/includes/functions.php +++ b/tests/phpunit/includes/functions.php @@ -364,3 +364,27 @@ function _unhook_font_registration() { remove_action( 'init', '_wp_register_default_font_collections' ); } tests_add_filter( 'init', '_unhook_font_registration', 1000 ); + +/** + * After the abilities API categories init action has been run once, trying to re-register + * core ability categories can cause _doing_it_wrong warnings. To avoid this, unhook the + * core ability categories registration function. + * + * @since 6.9.0 + */ +function _unhook_core_ability_categories_registration() { + remove_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); +} +tests_add_filter( 'wp_abilities_api_categories_init', '_unhook_core_ability_categories_registration', 1000 ); + +/** + * After the abilities API init action has been run once, trying to re-register + * core abilities can cause _doing_it_wrong warnings. To avoid this, unhook the + * core abilities registration function. + * + * @since 6.9.0 + */ +function _unhook_core_abilities_registration() { + remove_action( 'wp_abilities_api_init', 'wp_register_core_abilities' ); +} +tests_add_filter( 'wp_abilities_api_init', '_unhook_core_abilities_registration', 1000 ); diff --git a/tests/phpunit/tests/abilities-api/wpAbilitiesRegistry.php b/tests/phpunit/tests/abilities-api/wpAbilitiesRegistry.php index d096201959b77..d9d8f2ac68a2a 100644 --- a/tests/phpunit/tests/abilities-api/wpAbilitiesRegistry.php +++ b/tests/phpunit/tests/abilities-api/wpAbilitiesRegistry.php @@ -34,7 +34,12 @@ public function set_up(): void { wp_unregister_ability_category( $ability_category->get_slug() ); } - // Remove core registration actions to prevent re-registration. + // Unregister core abilities and remove core registration actions to prevent interference with tests. + foreach ( wp_get_abilities() as $ability ) { + if ( str_starts_with( $ability->get_name(), 'core/' ) ) { + wp_unregister_ability( $ability->get_name() ); + } + } remove_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); remove_action( 'wp_abilities_api_init', 'wp_register_core_abilities' ); @@ -96,10 +101,11 @@ public function tear_down(): void { // Clean up registered test ability category. wp_unregister_ability_category( 'math' ); - // Re-add core registration actions and re-register core categories and abilities. + // Re-add core registration actions and re-register core abilities for subsequent tests. add_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); add_action( 'wp_abilities_api_init', 'wp_register_core_abilities' ); do_action( 'wp_abilities_api_categories_init' ); + do_action( 'wp_abilities_api_init' ); parent::tear_down(); } diff --git a/tests/phpunit/tests/abilities-api/wpAbility.php b/tests/phpunit/tests/abilities-api/wpAbility.php index 32942b155173d..9b65d7bab3035 100644 --- a/tests/phpunit/tests/abilities-api/wpAbility.php +++ b/tests/phpunit/tests/abilities-api/wpAbility.php @@ -23,7 +23,12 @@ public function set_up(): void { wp_unregister_ability_category( $ability_category->get_slug() ); } - // Remove core registration actions to prevent re-registration. + // Unregister core abilities and remove core registration actions to prevent interference with tests. + foreach ( wp_get_abilities() as $ability ) { + if ( str_starts_with( $ability->get_name(), 'core/' ) ) { + wp_unregister_ability( $ability->get_name() ); + } + } remove_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); remove_action( 'wp_abilities_api_init', 'wp_register_core_abilities' ); @@ -68,10 +73,11 @@ public function tear_down(): void { // Clean up registered test ability category. wp_unregister_ability_category( 'math' ); - // Re-add core registration actions and re-register core categories and abilities. + // Re-add core registration actions and re-register core abilities for subsequent tests. add_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); add_action( 'wp_abilities_api_init', 'wp_register_core_abilities' ); do_action( 'wp_abilities_api_categories_init' ); + do_action( 'wp_abilities_api_init' ); parent::tear_down(); } diff --git a/tests/phpunit/tests/abilities-api/wpCoreAbilities.php b/tests/phpunit/tests/abilities-api/wpCoreAbilities.php index bd52278f8d7b9..a52d352e398f5 100644 --- a/tests/phpunit/tests/abilities-api/wpCoreAbilities.php +++ b/tests/phpunit/tests/abilities-api/wpCoreAbilities.php @@ -9,6 +9,28 @@ */ class Tests_Abilities_API_WpCoreAbilities extends WP_UnitTestCase { + /** + * Set up before each test. + */ + public function set_up(): void { + parent::set_up(); + + // Ensure core ability categories and abilities are registered for these tests. + // Re-add the action hooks if they were removed by other tests. + $needs_categories_init = ! has_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); + $needs_abilities_init = ! has_action( 'wp_abilities_api_init', 'wp_register_core_abilities' ); + + if ( $needs_categories_init ) { + add_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); + do_action( 'wp_abilities_api_categories_init' ); + } + + if ( $needs_abilities_init ) { + add_action( 'wp_abilities_api_init', 'wp_register_core_abilities' ); + do_action( 'wp_abilities_api_init' ); + } + } + /** * Tests that the `core/get-site-info` ability is registered with the expected schema. */ diff --git a/tests/phpunit/tests/abilities-api/wpRegisterAbility.php b/tests/phpunit/tests/abilities-api/wpRegisterAbility.php index 5ab58181ce229..38b4774e31b5e 100644 --- a/tests/phpunit/tests/abilities-api/wpRegisterAbility.php +++ b/tests/phpunit/tests/abilities-api/wpRegisterAbility.php @@ -36,7 +36,12 @@ public function set_up(): void { wp_unregister_ability_category( $ability_category->get_slug() ); } - // Remove core registration actions to prevent re-registration. + // Unregister core abilities and remove core registration actions to prevent interference with tests. + foreach ( wp_get_abilities() as $ability ) { + if ( str_starts_with( $ability->get_name(), 'core/' ) ) { + wp_unregister_ability( $ability->get_name() ); + } + } remove_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); remove_action( 'wp_abilities_api_init', 'wp_register_core_abilities' ); @@ -106,10 +111,11 @@ public function tear_down(): void { // Clean up registered test ability category. wp_unregister_ability_category( 'math' ); - // Re-add core registration actions and re-register core categories and abilities. + // Re-add core registration actions and re-register core abilities for subsequent tests. add_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); add_action( 'wp_abilities_api_init', 'wp_register_core_abilities' ); do_action( 'wp_abilities_api_categories_init' ); + do_action( 'wp_abilities_api_init' ); parent::tear_down(); } From 0335699baec5c6868ff565793067e5d6631bb864 Mon Sep 17 00:00:00 2001 From: Jorge Costa Date: Fri, 24 Oct 2025 17:33:41 +0100 Subject: [PATCH 14/20] Fix abilities API tests without test-specific changes - Modified tests/phpunit/includes/functions.php to unhook core abilities at priority 1 (before registration) instead of priority 1000 (after) - Updated tests/phpunit/tests/abilities-api/wpCoreAbilities.php to use set_up_before_class() for one-time core abilities registration - All 239 abilities API tests now pass (565 assertions) - Minimal test-specific code required --- tests/phpunit/includes/functions.php | 15 +++--- .../abilities-api/wpAbilitiesRegistry.php | 20 -------- .../phpunit/tests/abilities-api/wpAbility.php | 20 -------- .../tests/abilities-api/wpCoreAbilities.php | 36 +++++++-------- .../tests/abilities-api/wpRegisterAbility.php | 30 +++--------- .../wpRegisterAbilityCategory.php | 14 ------ .../wpRestAbilitiesV1CategoriesController.php | 14 +----- .../wpRestAbilitiesV1ListController.php | 46 ++++--------------- .../wpRestAbilitiesV1RunController.php | 46 ++++--------------- 9 files changed, 51 insertions(+), 190 deletions(-) diff --git a/tests/phpunit/includes/functions.php b/tests/phpunit/includes/functions.php index 3a18a716cb863..c0e78f5dd3787 100644 --- a/tests/phpunit/includes/functions.php +++ b/tests/phpunit/includes/functions.php @@ -366,25 +366,24 @@ function _unhook_font_registration() { tests_add_filter( 'init', '_unhook_font_registration', 1000 ); /** - * After the abilities API categories init action has been run once, trying to re-register - * core ability categories can cause _doing_it_wrong warnings. To avoid this, unhook the - * core ability categories registration function. + * Before the abilities API categories init action runs, unhook the core ability + * categories registration function to prevent core categories from being registered + * during tests. * * @since 6.9.0 */ function _unhook_core_ability_categories_registration() { remove_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); } -tests_add_filter( 'wp_abilities_api_categories_init', '_unhook_core_ability_categories_registration', 1000 ); +tests_add_filter( 'wp_abilities_api_categories_init', '_unhook_core_ability_categories_registration', 1 ); /** - * After the abilities API init action has been run once, trying to re-register - * core abilities can cause _doing_it_wrong warnings. To avoid this, unhook the - * core abilities registration function. + * Before the abilities API init action runs, unhook the core abilities + * registration function to prevent core abilities from being registered during tests. * * @since 6.9.0 */ function _unhook_core_abilities_registration() { remove_action( 'wp_abilities_api_init', 'wp_register_core_abilities' ); } -tests_add_filter( 'wp_abilities_api_init', '_unhook_core_abilities_registration', 1000 ); +tests_add_filter( 'wp_abilities_api_init', '_unhook_core_abilities_registration', 1 ); diff --git a/tests/phpunit/tests/abilities-api/wpAbilitiesRegistry.php b/tests/phpunit/tests/abilities-api/wpAbilitiesRegistry.php index d9d8f2ac68a2a..95fa29a20d9f3 100644 --- a/tests/phpunit/tests/abilities-api/wpAbilitiesRegistry.php +++ b/tests/phpunit/tests/abilities-api/wpAbilitiesRegistry.php @@ -29,20 +29,6 @@ public function set_up(): void { remove_all_filters( 'wp_register_ability_args' ); - // Unregister all ability categories to ensure a clean slate for each test. - foreach ( wp_get_ability_categories() as $ability_category ) { - wp_unregister_ability_category( $ability_category->get_slug() ); - } - - // Unregister core abilities and remove core registration actions to prevent interference with tests. - foreach ( wp_get_abilities() as $ability ) { - if ( str_starts_with( $ability->get_name(), 'core/' ) ) { - wp_unregister_ability( $ability->get_name() ); - } - } - remove_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); - remove_action( 'wp_abilities_api_init', 'wp_register_core_abilities' ); - // Fire the init hook to allow test ability category registration. do_action( 'wp_abilities_api_categories_init' ); wp_register_ability_category( @@ -101,12 +87,6 @@ public function tear_down(): void { // Clean up registered test ability category. wp_unregister_ability_category( 'math' ); - // Re-add core registration actions and re-register core abilities for subsequent tests. - add_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); - add_action( 'wp_abilities_api_init', 'wp_register_core_abilities' ); - do_action( 'wp_abilities_api_categories_init' ); - do_action( 'wp_abilities_api_init' ); - parent::tear_down(); } diff --git a/tests/phpunit/tests/abilities-api/wpAbility.php b/tests/phpunit/tests/abilities-api/wpAbility.php index 9b65d7bab3035..910ae7dad06fe 100644 --- a/tests/phpunit/tests/abilities-api/wpAbility.php +++ b/tests/phpunit/tests/abilities-api/wpAbility.php @@ -18,20 +18,6 @@ class Tests_Abilities_API_WpAbility extends WP_UnitTestCase { public function set_up(): void { parent::set_up(); - // Unregister all ability categories to ensure a clean slate for each test. - foreach ( wp_get_ability_categories() as $ability_category ) { - wp_unregister_ability_category( $ability_category->get_slug() ); - } - - // Unregister core abilities and remove core registration actions to prevent interference with tests. - foreach ( wp_get_abilities() as $ability ) { - if ( str_starts_with( $ability->get_name(), 'core/' ) ) { - wp_unregister_ability( $ability->get_name() ); - } - } - remove_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); - remove_action( 'wp_abilities_api_init', 'wp_register_core_abilities' ); - // Fire the init hook to allow test ability category registration. do_action( 'wp_abilities_api_categories_init' ); wp_register_ability_category( @@ -73,12 +59,6 @@ public function tear_down(): void { // Clean up registered test ability category. wp_unregister_ability_category( 'math' ); - // Re-add core registration actions and re-register core abilities for subsequent tests. - add_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); - add_action( 'wp_abilities_api_init', 'wp_register_core_abilities' ); - do_action( 'wp_abilities_api_categories_init' ); - do_action( 'wp_abilities_api_init' ); - parent::tear_down(); } diff --git a/tests/phpunit/tests/abilities-api/wpCoreAbilities.php b/tests/phpunit/tests/abilities-api/wpCoreAbilities.php index a52d352e398f5..0befd9d09c132 100644 --- a/tests/phpunit/tests/abilities-api/wpCoreAbilities.php +++ b/tests/phpunit/tests/abilities-api/wpCoreAbilities.php @@ -10,25 +10,25 @@ class Tests_Abilities_API_WpCoreAbilities extends WP_UnitTestCase { /** - * Set up before each test. + * Set up before the class. */ - public function set_up(): void { - parent::set_up(); - - // Ensure core ability categories and abilities are registered for these tests. - // Re-add the action hooks if they were removed by other tests. - $needs_categories_init = ! has_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); - $needs_abilities_init = ! has_action( 'wp_abilities_api_init', 'wp_register_core_abilities' ); - - if ( $needs_categories_init ) { - add_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); - do_action( 'wp_abilities_api_categories_init' ); - } - - if ( $needs_abilities_init ) { - add_action( 'wp_abilities_api_init', 'wp_register_core_abilities' ); - do_action( 'wp_abilities_api_init' ); - } + public static function set_up_before_class(): void { + parent::set_up_before_class(); + + // Ensure core abilities are registered for these tests. + // Temporarily remove the unhook functions so we can register core abilities. + remove_action( 'wp_abilities_api_categories_init', '_unhook_core_ability_categories_registration', 1 ); + remove_action( 'wp_abilities_api_init', '_unhook_core_abilities_registration', 1 ); + + // Add the core registration hooks and fire the actions. + add_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); + add_action( 'wp_abilities_api_init', 'wp_register_core_abilities' ); + do_action( 'wp_abilities_api_categories_init' ); + do_action( 'wp_abilities_api_init' ); + + // Re-add the unhook functions for subsequent tests. + add_action( 'wp_abilities_api_categories_init', '_unhook_core_ability_categories_registration', 1 ); + add_action( 'wp_abilities_api_init', '_unhook_core_abilities_registration', 1 ); } /** diff --git a/tests/phpunit/tests/abilities-api/wpRegisterAbility.php b/tests/phpunit/tests/abilities-api/wpRegisterAbility.php index 38b4774e31b5e..21b108f5ac8f9 100644 --- a/tests/phpunit/tests/abilities-api/wpRegisterAbility.php +++ b/tests/phpunit/tests/abilities-api/wpRegisterAbility.php @@ -31,20 +31,6 @@ class Test_Abilities_API_WpRegisterAbility extends WP_UnitTestCase { public function set_up(): void { parent::set_up(); - // Unregister all ability categories to ensure a clean slate for each test. - foreach ( wp_get_ability_categories() as $ability_category ) { - wp_unregister_ability_category( $ability_category->get_slug() ); - } - - // Unregister core abilities and remove core registration actions to prevent interference with tests. - foreach ( wp_get_abilities() as $ability ) { - if ( str_starts_with( $ability->get_name(), 'core/' ) ) { - wp_unregister_ability( $ability->get_name() ); - } - } - remove_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); - remove_action( 'wp_abilities_api_init', 'wp_register_core_abilities' ); - // Fire the init hook to allow test ability category registration. do_action( 'wp_abilities_api_categories_init' ); wp_register_ability_category( @@ -111,12 +97,6 @@ public function tear_down(): void { // Clean up registered test ability category. wp_unregister_ability_category( 'math' ); - // Re-add core registration actions and re-register core abilities for subsequent tests. - add_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); - add_action( 'wp_abilities_api_init', 'wp_register_core_abilities' ); - do_action( 'wp_abilities_api_categories_init' ); - do_action( 'wp_abilities_api_init' ); - parent::tear_down(); } @@ -541,10 +521,14 @@ public function test_get_existing_ability_using_callback() { add_action( 'wp_abilities_api_init', $callback ); - // Fire the init action - this triggers the callback. - do_action( 'wp_abilities_api_init' ); + // Reset the Registry, to ensure it's empty before the test. + $registry_reflection = new ReflectionClass( WP_Abilities_Registry::class ); + $instance_prop = $registry_reflection->getProperty( 'instance' ); + if ( PHP_VERSION_ID < 80100 ) { + $instance_prop->setAccessible( true ); + } + $instance_prop->setValue( null, null ); - // Now get the ability. $result = wp_get_ability( $name ); remove_action( 'wp_abilities_api_init', $callback ); diff --git a/tests/phpunit/tests/abilities-api/wpRegisterAbilityCategory.php b/tests/phpunit/tests/abilities-api/wpRegisterAbilityCategory.php index 2059978fcd035..ede55f98eaeaf 100644 --- a/tests/phpunit/tests/abilities-api/wpRegisterAbilityCategory.php +++ b/tests/phpunit/tests/abilities-api/wpRegisterAbilityCategory.php @@ -26,12 +26,6 @@ public function set_up(): void { 'label' => 'Math', 'description' => 'Mathematical operations.', ); - - // Unregister all ability categories to ensure a clean slate for each test. - foreach ( wp_get_ability_categories() as $ability_category ) { - wp_unregister_ability_category( $ability_category->get_slug() ); - } - remove_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); } /** @@ -47,10 +41,6 @@ public function tear_down(): void { wp_unregister_ability_category( $ability_category->get_slug() ); } - // Re-add core registration action and re-register core categories. - add_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); - do_action( 'wp_abilities_api_categories_init' ); - parent::tear_down(); } @@ -62,10 +52,6 @@ public function tear_down(): void { * @expectedIncorrectUsage wp_register_ability_category */ public function test_register_category_before_init_hook(): void { - // simulate that the 'wp_abilities_api_categories_init' action has not yet fired. - global $wp_actions; - $wp_actions[ 'wp_abilities_api_categories_init' ] = 0; - $result = wp_register_ability_category( self::$test_ability_category_name, self::$test_ability_category_args diff --git a/tests/phpunit/tests/rest-api/wpRestAbilitiesV1CategoriesController.php b/tests/phpunit/tests/rest-api/wpRestAbilitiesV1CategoriesController.php index f96085087f748..a6b7f233ceebf 100644 --- a/tests/phpunit/tests/rest-api/wpRestAbilitiesV1CategoriesController.php +++ b/tests/phpunit/tests/rest-api/wpRestAbilitiesV1CategoriesController.php @@ -25,7 +25,7 @@ class Tests_REST_API_WpRestAbilitiesV1CategoriesController extends WP_UnitTestCa protected static $admin_user_id; /** - * Test subscriber user ID.x + * Test subscriber user ID. * * @var int */ @@ -62,14 +62,6 @@ public function set_up(): void { do_action( 'rest_api_init' ); - // Unregister all ability categories to ensure a clean slate for each test. - foreach ( wp_get_ability_categories() as $ability_category ) { - wp_unregister_ability_category( $ability_category->get_slug() ); - } - - // Remove core registration action to prevent re-registration. - remove_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); - // Initialize the API and register test ability categories. do_action( 'wp_abilities_api_categories_init' ); $this->register_test_ability_categories(); @@ -91,10 +83,6 @@ public function tear_down(): void { wp_unregister_ability_category( $ability_category->get_slug() ); } - // Re-add core registration action and re-register core categories. - add_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); - do_action( 'wp_abilities_api_categories_init' ); - global $wp_rest_server; $wp_rest_server = null; diff --git a/tests/phpunit/tests/rest-api/wpRestAbilitiesV1ListController.php b/tests/phpunit/tests/rest-api/wpRestAbilitiesV1ListController.php index 66f0a2690834c..a6e5d92f270b7 100644 --- a/tests/phpunit/tests/rest-api/wpRestAbilitiesV1ListController.php +++ b/tests/phpunit/tests/rest-api/wpRestAbilitiesV1ListController.php @@ -36,12 +36,21 @@ public static function set_up_before_class(): void { 'role' => 'subscriber', ) ); + + // Fire the init hook to allow test ability categories registration. + do_action( 'wp_abilities_api_categories_init' ); + self::register_test_categories(); } /** * Tear down after class. */ public static function tear_down_after_class(): void { + // Clean up registered test ability categories. + foreach ( array( 'math', 'system', 'general' ) as $slug ) { + wp_unregister_ability_category( $slug ); + } + parent::tear_down_after_class(); } @@ -58,30 +67,8 @@ public function set_up(): void { do_action( 'rest_api_init' ); - // Unregister all abilities to ensure a clean slate for each test. - foreach ( wp_get_abilities() as $ability ) { - wp_unregister_ability( $ability->get_name() ); - } - - // Unregister all ability categories to ensure a clean slate for each test. - foreach ( wp_get_ability_categories() as $ability_category ) { - wp_unregister_ability_category( $ability_category->get_slug() ); - } - - // Remove core registration actions to prevent re-registration. - remove_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); - remove_action( 'wp_abilities_api_init', 'wp_register_core_abilities' ); - - // Fire categories init to trigger internal setup (happens inside get_instance). - do_action( 'wp_abilities_api_categories_init' ); - - // Register test categories after the init. - self::register_test_categories(); - // Initialize Abilities API. do_action( 'wp_abilities_api_init' ); - - // Register test abilities. $this->register_test_abilities(); // Set default user for tests @@ -101,21 +88,6 @@ public function tear_down(): void { wp_unregister_ability( $ability->get_name() ); } - // Clean up test ability categories. - foreach ( wp_get_ability_categories() as $ability_category ) { - $slug = $ability_category->get_slug(); - if ( ! str_starts_with( $slug, 'test-' ) && ! in_array( $slug, array( 'math', 'system', 'general' ), true ) ) { - continue; - } - - wp_unregister_ability_category( $slug ); - } - - // Re-add core registration actions and re-register core abilities. - add_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); - add_action( 'wp_abilities_api_init', 'wp_register_core_abilities' ); - do_action( 'wp_abilities_api_init' ); - // Reset REST server global $wp_rest_server; $wp_rest_server = null; diff --git a/tests/phpunit/tests/rest-api/wpRestAbilitiesV1RunController.php b/tests/phpunit/tests/rest-api/wpRestAbilitiesV1RunController.php index 041917f8c93aa..40372fe57b4be 100644 --- a/tests/phpunit/tests/rest-api/wpRestAbilitiesV1RunController.php +++ b/tests/phpunit/tests/rest-api/wpRestAbilitiesV1RunController.php @@ -48,12 +48,21 @@ public static function set_up_before_class(): void { 'role' => 'subscriber', ) ); + + // Fire the init hook to allow test ability categories registration. + do_action( 'wp_abilities_api_categories_init' ); + self::register_test_categories(); } /** * Tear down after class. */ public static function tear_down_after_class(): void { + // Clean up registered test ability categories. + foreach ( array( 'math', 'system', 'general' ) as $slug ) { + wp_unregister_ability_category( $slug ); + } + parent::tear_down_after_class(); } @@ -69,30 +78,8 @@ public function set_up(): void { do_action( 'rest_api_init' ); - // Unregister all abilities to ensure a clean slate for each test. - foreach ( wp_get_abilities() as $ability ) { - wp_unregister_ability( $ability->get_name() ); - } - - // Unregister all ability categories to ensure a clean slate for each test. - foreach ( wp_get_ability_categories() as $ability_category ) { - wp_unregister_ability_category( $ability_category->get_slug() ); - } - - // Remove core registration actions to prevent re-registration. - remove_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); - remove_action( 'wp_abilities_api_init', 'wp_register_core_abilities' ); - - // Fire categories init to trigger internal setup (happens inside get_instance). - do_action( 'wp_abilities_api_categories_init' ); - - // Register test categories after the init. - self::register_test_categories(); - // Initialize Abilities API. do_action( 'wp_abilities_api_init' ); - - // Register test abilities. $this->register_test_abilities(); // Set default user for tests @@ -112,21 +99,6 @@ public function tear_down(): void { wp_unregister_ability( $ability->get_name() ); } - // Clean up test ability categories. - foreach ( wp_get_ability_categories() as $ability_category ) { - $slug = $ability_category->get_slug(); - if ( ! str_starts_with( $slug, 'test-' ) && ! in_array( $slug, array( 'math', 'system', 'general' ), true ) ) { - continue; - } - - wp_unregister_ability_category( $slug ); - } - - // Re-add core registration actions and re-register core abilities. - add_action( 'wp_abilities_api_categories_init', 'wp_register_core_ability_categories' ); - add_action( 'wp_abilities_api_init', 'wp_register_core_abilities' ); - do_action( 'wp_abilities_api_init' ); - global $wp_rest_server; $wp_rest_server = null; From b3896596f94f7b98f5b51f1b855eeefd9db30a9f Mon Sep 17 00:00:00 2001 From: Jorge Costa Date: Fri, 24 Oct 2025 17:44:09 +0100 Subject: [PATCH 15/20] add ticket mark to new tests --- tests/phpunit/tests/abilities-api/wpCoreAbilities.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/phpunit/tests/abilities-api/wpCoreAbilities.php b/tests/phpunit/tests/abilities-api/wpCoreAbilities.php index 0befd9d09c132..bbcdab3b0a990 100644 --- a/tests/phpunit/tests/abilities-api/wpCoreAbilities.php +++ b/tests/phpunit/tests/abilities-api/wpCoreAbilities.php @@ -33,6 +33,7 @@ public static function set_up_before_class(): void { /** * Tests that the `core/get-site-info` ability is registered with the expected schema. + * @ticket 64146 */ public function test_core_get_bloginfo_ability_is_registered(): void { $ability = wp_get_ability( 'core/get-site-info' ); @@ -60,6 +61,7 @@ public function test_core_get_bloginfo_ability_is_registered(): void { /** * Tests executing the `core/get-site-info` ability returns all fields by default. + * @ticket 64146 */ public function test_core_get_bloginfo_executes(): void { // Requires manage_options. @@ -98,6 +100,7 @@ public function test_core_get_bloginfo_executes(): void { /** * Tests that executing the current user info ability requires authentication. + * @ticket 64146 */ public function test_core_get_current_user_info_requires_authentication(): void { $ability = wp_get_ability( 'core/get-user-info' ); @@ -111,6 +114,7 @@ public function test_core_get_current_user_info_requires_authentication(): void /** * Tests executing the current user info ability as an authenticated user. + * @ticket 64146 */ public function test_core_get_current_user_info_returns_user_data(): void { $user_id = self::factory()->user->create( @@ -137,6 +141,7 @@ public function test_core_get_current_user_info_returns_user_data(): void { /** * Tests executing the environment info ability. + * @ticket 64146 */ public function test_core_get_environment_type_executes(): void { // Requires manage_options. From 54b48d6cd0fa39b188564c0328999c5360de9179 Mon Sep 17 00:00:00 2001 From: Jorge Costa Date: Fri, 24 Oct 2025 17:51:36 +0100 Subject: [PATCH 16/20] apply test feedback --- tests/phpunit/tests/abilities-api/wpCoreAbilities.php | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/tests/phpunit/tests/abilities-api/wpCoreAbilities.php b/tests/phpunit/tests/abilities-api/wpCoreAbilities.php index bbcdab3b0a990..0c4cdb77a4a2c 100644 --- a/tests/phpunit/tests/abilities-api/wpCoreAbilities.php +++ b/tests/phpunit/tests/abilities-api/wpCoreAbilities.php @@ -88,14 +88,9 @@ public function test_core_get_bloginfo_executes(): void { ); $this->assertIsArray( $result ); - $this->assertArrayHasKey( 'name', $result ); - $this->assertArrayHasKey( 'url', $result ); - $this->assertArrayNotHasKey( 'description', $result ); - $this->assertArrayNotHasKey( 'version', $result ); + $this->assertCount( 2, $result ); $this->assertSame( get_bloginfo( 'name' ), $result['name'] ); $this->assertSame( get_bloginfo( 'url' ), $result['url'] ); - - wp_set_current_user( 0 ); } /** @@ -135,8 +130,6 @@ public function test_core_get_current_user_info_returns_user_data(): void { $this->assertSame( 'fr_FR', $result['locale'] ); $this->assertSame( 'subscriber', $result['roles'][0] ); $this->assertSame( get_userdata( $user_id )->display_name, $result['display_name'] ); - - wp_set_current_user( 0 ); } /** @@ -158,7 +151,5 @@ public function test_core_get_environment_type_executes(): void { $this->assertArrayHasKey( 'db_server_info', $ability_data ); $this->assertArrayHasKey( 'wp_version', $ability_data ); $this->assertSame( $environment, $ability_data['environment'] ); - - wp_set_current_user( 0 ); } } From 688019f52d6881d5d27422b27888e75fd861e1bb Mon Sep 17 00:00:00 2001 From: Jorge Costa Date: Sat, 25 Oct 2025 18:16:21 +0100 Subject: [PATCH 17/20] remove duplicate variable --- src/wp-includes/abilities/wp-core-abilities.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/wp-includes/abilities/wp-core-abilities.php b/src/wp-includes/abilities/wp-core-abilities.php index a775964e1d36d..73ecd8e14fc49 100644 --- a/src/wp-includes/abilities/wp-core-abilities.php +++ b/src/wp-includes/abilities/wp-core-abilities.php @@ -114,10 +114,9 @@ function wp_register_core_abilities(): void { ), 'additionalProperties' => false, ), - 'execute_callback' => static function ( $input = array() ): array { + 'execute_callback' => static function ( $input = array() ) use ( $site_info_fields ): array { $input = is_array( $input ) ? $input : array(); - $all_fields = array( 'name', 'description', 'url', 'wpurl', 'admin_email', 'charset', 'language', 'version' ); - $requested_fields = ! empty( $input['fields'] ) ? $input['fields'] : $all_fields; + $requested_fields = ! empty( $input['fields'] ) ? $input['fields'] : $site_info_fields; $result = array(); foreach ( $requested_fields as $field ) { From 1ab6019667fe2769b03803defd8ed2adb38739d8 Mon Sep 17 00:00:00 2001 From: Jorge Costa Date: Sat, 25 Oct 2025 18:17:06 +0100 Subject: [PATCH 18/20] remove overprotective unnecessary check --- src/wp-includes/abilities/wp-core-abilities.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/abilities/wp-core-abilities.php b/src/wp-includes/abilities/wp-core-abilities.php index 73ecd8e14fc49..610cf68f27c69 100644 --- a/src/wp-includes/abilities/wp-core-abilities.php +++ b/src/wp-includes/abilities/wp-core-abilities.php @@ -242,7 +242,7 @@ function wp_register_core_abilities(): void { $env = wp_get_environment_type(); $php_version = phpversion(); $db_server_info = ''; - if ( isset( $wpdb ) && is_object( $wpdb ) && method_exists( $wpdb, 'db_server_info' ) ) { + if ( method_exists( $wpdb, 'db_server_info' ) ) { $db_server_info = $wpdb->db_server_info() ?? ''; } $wp_version = get_bloginfo( 'version' ); From c2d1b927ddbc46512b44ab84c32ff0e888cd107d Mon Sep 17 00:00:00 2001 From: Jorge Costa Date: Sat, 25 Oct 2025 18:17:30 +0100 Subject: [PATCH 19/20] Add since tag missed on set_up_before_class --- tests/phpunit/tests/abilities-api/wpCoreAbilities.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/phpunit/tests/abilities-api/wpCoreAbilities.php b/tests/phpunit/tests/abilities-api/wpCoreAbilities.php index 0c4cdb77a4a2c..789130d04b539 100644 --- a/tests/phpunit/tests/abilities-api/wpCoreAbilities.php +++ b/tests/phpunit/tests/abilities-api/wpCoreAbilities.php @@ -11,6 +11,8 @@ class Tests_Abilities_API_WpCoreAbilities extends WP_UnitTestCase { /** * Set up before the class. + * + * @since 6.9.0 */ public static function set_up_before_class(): void { parent::set_up_before_class(); From a9997d7e4533a12a0b02a0174a4c0da45b39f4f5 Mon Sep 17 00:00:00 2001 From: Jorge Costa Date: Sat, 25 Oct 2025 18:17:55 +0100 Subject: [PATCH 20/20] make test names match ability names they are testing --- tests/phpunit/tests/abilities-api/wpCoreAbilities.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/phpunit/tests/abilities-api/wpCoreAbilities.php b/tests/phpunit/tests/abilities-api/wpCoreAbilities.php index 789130d04b539..f87361f0e77f2 100644 --- a/tests/phpunit/tests/abilities-api/wpCoreAbilities.php +++ b/tests/phpunit/tests/abilities-api/wpCoreAbilities.php @@ -37,7 +37,7 @@ public static function set_up_before_class(): void { * Tests that the `core/get-site-info` ability is registered with the expected schema. * @ticket 64146 */ - public function test_core_get_bloginfo_ability_is_registered(): void { + public function test_core_get_site_info_ability_is_registered(): void { $ability = wp_get_ability( 'core/get-site-info' ); $this->assertInstanceOf( WP_Ability::class, $ability ); @@ -65,7 +65,7 @@ public function test_core_get_bloginfo_ability_is_registered(): void { * Tests executing the `core/get-site-info` ability returns all fields by default. * @ticket 64146 */ - public function test_core_get_bloginfo_executes(): void { + public function test_core_get_site_info_executes(): void { // Requires manage_options. $admin_id = self::factory()->user->create( array( 'role' => 'administrator' ) ); wp_set_current_user( $admin_id ); @@ -138,7 +138,7 @@ public function test_core_get_current_user_info_returns_user_data(): void { * Tests executing the environment info ability. * @ticket 64146 */ - public function test_core_get_environment_type_executes(): void { + public function test_core_get_environment_info_executes(): void { // Requires manage_options. $admin_id = self::factory()->user->create( array( 'role' => 'administrator' ) ); wp_set_current_user( $admin_id );