Commit 30077cb43aa for woocommerce

commit 30077cb43aa8f9f7a02c0709be22d10b6332cd1b
Author: Christopher Hertel <mail@christopher-hertel.de>
Date:   Mon Nov 2 12:49:56 2026 +0100

    Drop pre-6.9 Abilities API existence checks (#70368)

    * Drop Abilities API existence checks for pre-6.9 WordPress

    * Drop pre-6.9 Abilities API branches from tests

    * Add changelog entry

diff --git a/plugins/woocommerce/changelog/drop-pre-69-abilities-api-checks b/plugins/woocommerce/changelog/drop-pre-69-abilities-api-checks
new file mode 100644
index 00000000000..5271a9d820a
--- /dev/null
+++ b/plugins/woocommerce/changelog/drop-pre-69-abilities-api-checks
@@ -0,0 +1,4 @@
+Significance: patch
+Type: dev
+Comment: Drop Abilities API existence checks and test branches for pre-6.9 WordPress; no merchant-facing change.
+
diff --git a/plugins/woocommerce/src/Internal/Abilities/AbilitiesCategories.php b/plugins/woocommerce/src/Internal/Abilities/AbilitiesCategories.php
index 0f5e28f8561..84e594bcae3 100644
--- a/plugins/woocommerce/src/Internal/Abilities/AbilitiesCategories.php
+++ b/plugins/woocommerce/src/Internal/Abilities/AbilitiesCategories.php
@@ -32,12 +32,7 @@ class AbilitiesCategories {
 	 * @since 10.9.0
 	 */
 	public static function register_categories(): void {
-		// Only register if the function exists.
-		if ( ! function_exists( 'wp_register_ability_category' ) ) {
-			return;
-		}
-
-		if ( ! function_exists( 'wp_has_ability_category' ) || ! wp_has_ability_category( 'woocommerce' ) ) {
+		if ( ! wp_has_ability_category( 'woocommerce' ) ) {
 			wp_register_ability_category(
 				'woocommerce',
 				array(
@@ -47,7 +42,7 @@ class AbilitiesCategories {
 			);
 		}

-		if ( ! function_exists( 'wp_has_ability_category' ) || ! wp_has_ability_category( 'woocommerce-rest' ) ) {
+		if ( ! wp_has_ability_category( 'woocommerce-rest' ) ) {
 			wp_register_ability_category(
 				'woocommerce-rest',
 				array(
diff --git a/plugins/woocommerce/src/Internal/Abilities/AbilitiesLoader.php b/plugins/woocommerce/src/Internal/Abilities/AbilitiesLoader.php
index 33e5f762628..291775709dc 100644
--- a/plugins/woocommerce/src/Internal/Abilities/AbilitiesLoader.php
+++ b/plugins/woocommerce/src/Internal/Abilities/AbilitiesLoader.php
@@ -167,10 +167,6 @@ class AbilitiesLoader {
 	 * @since 10.9.0
 	 */
 	public static function register_abilities(): void {
-		if ( ! function_exists( 'wp_register_ability' ) ) {
-			return;
-		}
-
 		foreach ( self::get_ability_definition_classes() as $class_name ) {
 			if ( ! is_string( $class_name ) || ! class_exists( $class_name ) ) {
 				continue;
@@ -195,8 +191,8 @@ class AbilitiesLoader {
 				continue;
 			}

-			if ( function_exists( 'wp_has_ability' ) && wp_has_ability( $ability_name ) ) {
-				$existing_ability = function_exists( 'wp_get_ability' ) ? wp_get_ability( $ability_name ) : null;
+			if ( wp_has_ability( $ability_name ) ) {
+				$existing_ability = wp_get_ability( $ability_name );

 				if (
 					$is_core_ability
@@ -206,7 +202,7 @@ class AbilitiesLoader {
 					continue;
 				}

-				if ( ! $is_core_ability || ! function_exists( 'wp_unregister_ability' ) ) {
+				if ( ! $is_core_ability ) {
 					continue;
 				}

diff --git a/plugins/woocommerce/src/Internal/Abilities/AbilitiesRegistry.php b/plugins/woocommerce/src/Internal/Abilities/AbilitiesRegistry.php
index 18626c512e8..972e2c46da9 100644
--- a/plugins/woocommerce/src/Internal/Abilities/AbilitiesRegistry.php
+++ b/plugins/woocommerce/src/Internal/Abilities/AbilitiesRegistry.php
@@ -34,13 +34,6 @@ class AbilitiesRegistry {
 	 * @return array Array of all ability IDs.
 	 */
 	public function get_abilities_ids(): array {
-		// Check if the abilities API is available.
-		if ( ! function_exists( 'wp_get_abilities' ) ) {
-			return array();
-		}
-
-		$all_abilities = wp_get_abilities();
-
-		return array_keys( $all_abilities );
+		return array_keys( wp_get_abilities() );
 	}
 }
diff --git a/plugins/woocommerce/tests/php/src/Internal/Abilities/AbilitiesLoaderTest.php b/plugins/woocommerce/tests/php/src/Internal/Abilities/AbilitiesLoaderTest.php
index ccc92e34100..598872a3cc9 100644
--- a/plugins/woocommerce/tests/php/src/Internal/Abilities/AbilitiesLoaderTest.php
+++ b/plugins/woocommerce/tests/php/src/Internal/Abilities/AbilitiesLoaderTest.php
@@ -113,7 +113,7 @@ class AbilitiesLoaderTest extends \WC_Unit_Test_Case {
 			$this->original_action_counts[ $action ] = $wp_actions[ $action ] ?? null;
 		}

-		// WordPress 6.9+ requires init to have fired before the Abilities API registry can be initialized.
+		// The Abilities API registry can only be initialized after init has fired.
 		$wp_actions['init'] = max( 1, (int) ( $wp_actions['init'] ?? 0 ) ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited

 		wp_set_current_user( self::$administrator_id );
@@ -145,13 +145,13 @@ class AbilitiesLoaderTest extends \WC_Unit_Test_Case {
 		}

 		foreach ( $this->registered_ability_ids as $ability_id ) {
-			if ( function_exists( 'wp_has_ability' ) && wp_has_ability( $ability_id ) ) {
+			if ( wp_has_ability( $ability_id ) ) {
 				wp_unregister_ability( $ability_id );
 			}
 		}

 		foreach ( $this->registered_category_ids as $category_id ) {
-			if ( function_exists( 'wp_has_ability_category' ) && wp_has_ability_category( $category_id ) ) {
+			if ( wp_has_ability_category( $category_id ) ) {
 				wp_unregister_ability_category( $category_id );
 			}
 		}
@@ -805,10 +805,6 @@ class AbilitiesLoaderTest extends \WC_Unit_Test_Case {
 	 * @testdox Should register WooCommerce ability categories idempotently.
 	 */
 	public function test_ability_category_registration_is_idempotent(): void {
-		if ( ! function_exists( 'wp_register_ability_category' ) || ! function_exists( 'wp_has_ability_category' ) ) {
-			$this->markTestSkipped( 'Abilities API category registry is not available.' );
-		}
-
 		$callback = static function () {
 			AbilitiesCategories::register_categories();
 			AbilitiesCategories::register_categories();
@@ -2697,10 +2693,6 @@ class AbilitiesLoaderTest extends \WC_Unit_Test_Case {
 	 * Register the WooCommerce ability category for this test.
 	 */
 	private function register_woocommerce_category(): void {
-		if ( ! function_exists( 'wp_register_ability_category' ) || ! function_exists( 'wp_has_ability_category' ) ) {
-			return;
-		}
-
 		if ( wp_has_ability_category( 'woocommerce' ) ) {
 			return;
 		}
@@ -2738,7 +2730,7 @@ class AbilitiesLoaderTest extends \WC_Unit_Test_Case {
 	 */
 	private function unregister_domain_abilities(): void {
 		foreach ( self::CANONICAL_ABILITY_IDS as $ability_id ) {
-			if ( function_exists( 'wp_has_ability' ) && wp_has_ability( $ability_id ) ) {
+			if ( wp_has_ability( $ability_id ) ) {
 				wp_unregister_ability( $ability_id );
 			}
 		}
diff --git a/plugins/woocommerce/tests/php/src/Internal/Abilities/AbilitiesTrackingTest.php b/plugins/woocommerce/tests/php/src/Internal/Abilities/AbilitiesTrackingTest.php
index 08e9ddaaf7d..d5a75f02d63 100644
--- a/plugins/woocommerce/tests/php/src/Internal/Abilities/AbilitiesTrackingTest.php
+++ b/plugins/woocommerce/tests/php/src/Internal/Abilities/AbilitiesTrackingTest.php
@@ -118,10 +118,6 @@ class AbilitiesTrackingTest extends WC_Unit_Test_Case {

 		parent::setUp();

-		if ( ! function_exists( 'wp_register_ability' ) ) {
-			$this->markTestSkipped( 'The Abilities API is not available.' );
-		}
-
 		foreach ( array( 'init', 'wp_abilities_api_init', 'wp_abilities_api_categories_init', 'rest_api_init' ) as $action ) {
 			$this->original_action_counts[ $action ] = $wp_actions[ $action ] ?? null;
 		}
@@ -154,7 +150,7 @@ class AbilitiesTrackingTest extends WC_Unit_Test_Case {

 			// The abilities registry is a singleton that outlives the test.
 			foreach ( array_merge( array( self::ABILITY_ID, self::INNER_ABILITY_ID, self::UNTRACKED_ABILITY_ID, self::LONG_ABILITY_ID, self::NO_SCHEMA_ABILITY_ID ), $this->registered_adapter_ids ) as $ability_id ) {
-				if ( function_exists( 'wp_has_ability' ) && wp_has_ability( $ability_id ) ) {
+				if ( wp_has_ability( $ability_id ) ) {
 					wp_unregister_ability( $ability_id );
 				}
 			}
diff --git a/plugins/woocommerce/tests/php/src/Internal/Abilities/RemovedRestAbilitiesTest.php b/plugins/woocommerce/tests/php/src/Internal/Abilities/RemovedRestAbilitiesTest.php
index 3ad62f14dba..6bf0381a8fd 100644
--- a/plugins/woocommerce/tests/php/src/Internal/Abilities/RemovedRestAbilitiesTest.php
+++ b/plugins/woocommerce/tests/php/src/Internal/Abilities/RemovedRestAbilitiesTest.php
@@ -24,11 +24,11 @@ class RemovedRestAbilitiesTest extends WC_Unit_Test_Case {
 	 */
 	public function test_removed_methods_report_incorrect_usage( string $method, callable $callback ): void {
 		$this->setExpectedIncorrectUsage( $method );
-		$abilities_before = function_exists( 'wp_get_abilities' ) ? array_keys( wp_get_abilities() ) : array();
+		$abilities_before = array_keys( wp_get_abilities() );

 		$callback();

-		$abilities_after = function_exists( 'wp_get_abilities' ) ? array_keys( wp_get_abilities() ) : array();
+		$abilities_after = array_keys( wp_get_abilities() );
 		$this->assertSame( $abilities_before, $abilities_after, 'Removed methods should not register abilities' );
 	}

diff --git a/plugins/woocommerce/tests/php/src/Internal/AbilitiesApi/AbilitiesApiIntegrationTest.php b/plugins/woocommerce/tests/php/src/Internal/AbilitiesApi/AbilitiesApiIntegrationTest.php
index 01a36fea0d0..e7f5fb7efe2 100644
--- a/plugins/woocommerce/tests/php/src/Internal/AbilitiesApi/AbilitiesApiIntegrationTest.php
+++ b/plugins/woocommerce/tests/php/src/Internal/AbilitiesApi/AbilitiesApiIntegrationTest.php
@@ -45,18 +45,6 @@ class AbilitiesApiIntegrationTest extends \WC_REST_Unit_Test_Case {
 	 */
 	private $original_init_action_count;

-	/**
-	 * Check if Abilities API is in WordPress core.
-	 *
-	 * WordPress 6.9+ has the Abilities API in core with different class names than the vendor package.
-	 * We detect this by checking for the core class name (plural "Categories" instead of singular "Category").
-	 *
-	 * @return bool True if Abilities API is in core, false if using vendor package.
-	 */
-	private function are_abilities_in_wp_core(): bool {
-		return class_exists( 'WP_Ability_Categories_Registry' );
-	}
-
 	/**
 	 * Set up before each test
 	 */
@@ -67,30 +55,11 @@ class AbilitiesApiIntegrationTest extends \WC_REST_Unit_Test_Case {
 		$this->abilities_categories_init_action = 'wp_abilities_api_categories_init';
 		$this->category_registry_class          = 'WP_Ability_Categories_Registry';

-		// WordPress 6.9+ requires did_action('init') to return truthy before abilities API can be used.
-		// Save the original value and set to 1. Doesn't hurt pre-6.9 versions.
+		// The Abilities API requires did_action('init') to return truthy before it can be used.
 		$this->original_init_action_count = $wp_actions['init'] ?? null;
 		$wp_actions['init']               = 1; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited

 		parent::setUp();
-
-		// Ensure Abilities API REST routes are registered if needed.
-		if ( function_exists( 'wp_register_ability' ) && class_exists( 'WP_REST_Abilities_Init' ) ) {
-			$routes = $this->server->get_routes();
-
-			// Check if any Abilities API routes are already registered.
-			$has_abilities_routes = false;
-			foreach ( $routes as $route => $handlers ) {
-				if ( strpos( $route, '/wp-abilities/v1/' ) === 0 ) {
-					$has_abilities_routes = true;
-					break;
-				}
-			}
-
-			if ( ! $has_abilities_routes ) {
-				\WP_REST_Abilities_Init::register_routes( $this->server );
-			}
-		}
 	}

 	/**
@@ -381,14 +350,6 @@ class AbilitiesApiIntegrationTest extends \WC_REST_Unit_Test_Case {
 	 * @group abilities-api
 	 */
 	public function test_rest_endpoints_are_registered() {
-		// WordPress 6.9+ uses core controllers with different namespace, earlier versions use vendor package.
-		$are_abilities_in_wp_core = $this->are_abilities_in_wp_core();
-		if ( $are_abilities_in_wp_core ) {
-			$this->assertTrue( class_exists( 'WP_REST_Abilities_V1_List_Controller' ), 'WordPress 6.9+ should have WP_REST_Abilities_V1_List_Controller class' );
-		} else {
-			$this->assertTrue( class_exists( '\WP_REST_Abilities_Init' ), 'Bootstrap should load WP_REST_Abilities_Init class' );
-		}
-
 		$list_endpoint = '/wp-abilities/v1/abilities';
 		$run_endpoint  = '/wp-abilities/v1/abilities/(?P<name>[a-zA-Z0-9\\-\\/]+?)/run';

@@ -690,9 +651,7 @@ class AbilitiesApiIntegrationTest extends \WC_REST_Unit_Test_Case {
 	 * @param string $ability_id The ability ID to clean up.
 	 */
 	private function cleanup_ability( $ability_id ) {
-		if ( function_exists( 'wp_unregister_ability' ) ) {
-			wp_unregister_ability( $ability_id );
-		}
+		wp_unregister_ability( $ability_id );
 	}

 	/**
@@ -701,8 +660,6 @@ class AbilitiesApiIntegrationTest extends \WC_REST_Unit_Test_Case {
 	 * @param string $category_id The category ID to clean up.
 	 */
 	private function cleanup_category( $category_id ) {
-		if ( function_exists( 'wp_unregister_ability_category' ) ) {
-			wp_unregister_ability_category( $category_id );
-		}
+		wp_unregister_ability_category( $category_id );
 	}
 }
diff --git a/plugins/woocommerce/tests/php/src/Internal/AbilitiesApi/ExtensibleAbilitiesTest.php b/plugins/woocommerce/tests/php/src/Internal/AbilitiesApi/ExtensibleAbilitiesTest.php
index fe0afac6f76..68cb5b41185 100644
--- a/plugins/woocommerce/tests/php/src/Internal/AbilitiesApi/ExtensibleAbilitiesTest.php
+++ b/plugins/woocommerce/tests/php/src/Internal/AbilitiesApi/ExtensibleAbilitiesTest.php
@@ -81,19 +81,11 @@ class ExtensibleAbilitiesTest extends \WC_REST_Unit_Test_Case {
 	public function setUp(): void {
 		global $wp_actions;

-		if ( ! function_exists( 'wp_register_ability' ) ) {
-			require_once WC_ABSPATH . 'vendor/wordpress/abilities-api/includes/bootstrap.php';
-		}
-
 		$this->original_init_count = $wp_actions['init'] ?? null;
 		$wp_actions['init']        = max( 1, (int) ( $wp_actions['init'] ?? 0 ) ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited

 		parent::setUp();

-		if ( class_exists( 'WP_REST_Abilities_Init' ) && ! isset( $this->server->get_routes()['/wp-abilities/v1/abilities'] ) ) {
-			\WP_REST_Abilities_Init::register_routes( $this->server );
-		}
-
 		AbilitiesLoader::init();
 		$this->reset_registries();
 		self::$received = array();