Commit ac604a4e4bd for woocommerce

commit ac604a4e4bd3001b5c9cac6ca2c5662a94be2c4c
Author: Mike Jolley <mike.jolley@me.com>
Date:   Wed May 13 14:14:54 2026 +0100

    Remove Legacy REST API options, nudges, and auto-install logic (#64076)

    * Remove Legacy REST API options, nudges, and auto-install from WooCommerce core

    The Legacy REST API was removed from WooCommerce core in 9.0 and moved to a
    dedicated extension. This change removes all remaining UI nudges, settings,
    admin notices, and auto-installation logic that pointed users toward the
    legacy extension, reducing confusion during HPOS migration.

    Key changes:
    - Remove "Legacy API" settings section and woocommerce_api_enabled option references
    - Remove legacy webhook warnings, admin notices, and legacy_v3 dropdown option
    - Remove auto-install/activate logic for the legacy REST API plugin
    - Remove Legacy REST API row from system status report
    - Clean up dead imports, unused test cases, and orphaned code

    The Legacy REST API extension still works if manually installed — webhook
    delivery with legacy payloads is supported via deprecated fallback with
    wc_deprecated_function notice. The LegacyRestApiStub remains to handle
    wc-api endpoint routing and WC()->api compatibility.

    Closes #53157

    Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

    * Add changefile(s) from automation for the following project(s): woocommerce-beta-tester, woocommerce, woocommerce/client/admin

    * Improve webhook handling for unsupported API versions

    - Throw exception for unsupported webhook API versions instead of silently
      sending minimal payloads. Message is generic rather than nudging toward
      the Legacy REST API plugin.
    - Show Legacy API v3 (deprecated) option in webhook edit dropdown when the
      Legacy REST API plugin is installed.
    - Show current unsupported version in dropdown when a webhook already uses
      a legacy version but the plugin is not installed, so users can see the
      problem and switch to a modern version.

    Co-Authored-By: Mastra Code (anthropic/claude-opus-4-6) <noreply@mastra.ai>

    * Restore plugin install API tests using hello-dolly as fixture

    The tests were removed because they used woocommerce-legacy-rest-api as the
    fixture plugin. The tests cover the general /wc-admin/plugins/install endpoint
    which is still used by onboarding and other flows, so they should be retained
    with a different fixture plugin.

    Co-Authored-By: Mastra Code (anthropic/claude-opus-4-6) <noreply@mastra.ai>

    * Add missing @throws tag to build_payload() docblock

    Co-Authored-By: Mastra Code (anthropic/claude-opus-4-6) <noreply@mastra.ai>

    * Remove require for deleted class-wc-api-unit-test-case and clean up PHPStan baseline

    The test bootstrap still required the deleted WC_API_Unit_Test_Case file,
    causing a fatal error in the entire test suite. No tests extend this class
    so the require can simply be removed.

    Also removes the now-stale PHPStan baseline entry for the deleted
    WC_Admin_Webhooks::maybe_display_legacy_rest_api_warning() method.

    Co-Authored-By: Mastra Code (anthropic/claude-opus-4-6) <noreply@mastra.ai>

    * Regenerate PHPStan baseline after legacy REST API removal

    Remove stale baseline entries for deleted status report code and
    update html-webhooks-edit.php variable count for new dropdown logic.

    Co-Authored-By: Mastra Code (anthropic/claude-opus-4-6) <noreply@mastra.ai>

    * Address code review feedback for legacy REST API removal

    - Wrap build_payload() in try/finally to restore user context on exception
    - Gate legacy payload path on exact 'legacy_v3' version match
    - Only show legacy_v3 dropdown option when webhook actually uses that version
    - Fix PHPDoc return type for pre_option_woocommerce_api_enabled callback
    - Update PluginUtil docblock to remove stale core reference
    - Add @var WC_Webhook annotation to webhook edit template
    - Regenerate PHPStan baseline (resolves 19 undefined variable suppressions)

    Co-Authored-By: Mastra Code (anthropic/claude-opus-4-6) <noreply@mastra.ai>

    * Show legacy_v3 dropdown option whenever Legacy REST API extension is active

    Users with the extension installed should be able to select legacy_v3
    for any webhook, not just ones already using it.

    Co-Authored-By: Mastra Code (anthropic/claude-opus-4-6) <noreply@mastra.ai>

    * Add missing hook docblock comment for woocommerce_webhook_payload filter

    Co-Authored-By: Mastra Code (anthropic/claude-opus-4-6) <noreply@mastra.ai>

    * Restore api_enabled in system_status, tracker, and webhook count shim

    * Restore woocommerce_settings_rest_api filter as conditional extension point

    * Make get_plugins_excluded_from_compatibility_ui() a noop

    * Add changefile(s) from automation for the following project(s): woocommerce-beta-tester, woocommerce, woocommerce/client/admin

    * Add missing hook docblock for woocommerce_settings_rest_api filter

    ---------

    Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
    Co-authored-by: woocommercebot <woocommercebot@users.noreply.github.com>
    Co-authored-by: Mastra Code (anthropic/claude-opus-4-6) <noreply@mastra.ai>

diff --git a/plugins/woocommerce-beta-tester/changelog/64076-remove-legacy-rest-api-options b/plugins/woocommerce-beta-tester/changelog/64076-remove-legacy-rest-api-options
new file mode 100644
index 00000000000..b5bbf3ef35a
--- /dev/null
+++ b/plugins/woocommerce-beta-tester/changelog/64076-remove-legacy-rest-api-options
@@ -0,0 +1,4 @@
+Significance: minor
+Type: dev
+
+Remove Legacy REST API settings section, admin notices, auto-install logic, and UI nudges from WooCommerce core. The Legacy REST API extension continues to work if manually installed.
\ No newline at end of file
diff --git a/plugins/woocommerce-beta-tester/includes/class-wc-beta-tester-admin-menus.php b/plugins/woocommerce-beta-tester/includes/class-wc-beta-tester-admin-menus.php
index 08bdeb3be11..52064399528 100644
--- a/plugins/woocommerce-beta-tester/includes/class-wc-beta-tester-admin-menus.php
+++ b/plugins/woocommerce-beta-tester/includes/class-wc-beta-tester-admin-menus.php
@@ -168,11 +168,6 @@ Copy and paste the system status report from **WooCommerce > System Status** in
 		$ssr            = get_transient( $transient_name );

 		if ( false === $ssr ) {
-			// When running WC 3.6 or greater it is necessary to manually load the REST API classes.
-			if ( ! did_action( 'rest_api_init' ) ) {
-				WC()->api->rest_api_includes();
-			}
-
 			if ( ! class_exists( 'WC_REST_System_Status_Controller' ) ) {
 				return '';
 			}
diff --git a/plugins/woocommerce-beta-tester/includes/wc-beta-tester-settings-list.php b/plugins/woocommerce-beta-tester/includes/wc-beta-tester-settings-list.php
index 4cecf45f9b5..a605c7706c5 100644
--- a/plugins/woocommerce-beta-tester/includes/wc-beta-tester-settings-list.php
+++ b/plugins/woocommerce-beta-tester/includes/wc-beta-tester-settings-list.php
@@ -24,7 +24,6 @@ function wc_beta_tester_setting_list() {
 		'timezone_string',
 		'woocommerce_all_except_countries',
 		'woocommerce_allowed_countries',
-		'woocommerce_api_enabled',
 		'woocommerce_calc_discounts_sequentially',
 		'woocommerce_calc_shipping',
 		'woocommerce_calc_taxes',
diff --git a/plugins/woocommerce/changelog/64076-remove-legacy-rest-api-options b/plugins/woocommerce/changelog/64076-remove-legacy-rest-api-options
new file mode 100644
index 00000000000..b5bbf3ef35a
--- /dev/null
+++ b/plugins/woocommerce/changelog/64076-remove-legacy-rest-api-options
@@ -0,0 +1,4 @@
+Significance: minor
+Type: dev
+
+Remove Legacy REST API settings section, admin notices, auto-install logic, and UI nudges from WooCommerce core. The Legacy REST API extension continues to work if manually installed.
\ No newline at end of file
diff --git a/plugins/woocommerce/client/admin/client/blueprint/components/get-option-groups.ts b/plugins/woocommerce/client/admin/client/blueprint/components/get-option-groups.ts
index ef08a6f1cdf..d8dcbd9ef5f 100644
--- a/plugins/woocommerce/client/admin/client/blueprint/components/get-option-groups.ts
+++ b/plugins/woocommerce/client/admin/client/blueprint/components/get-option-groups.ts
@@ -104,7 +104,6 @@ const OPTIONS_GROUPS = {
 	woocommerce_myaccount_payment_methods_endpoint: 'Advanced',
 	woocommerce_myaccount_lost_password_endpoint: 'Advanced',
 	woocommerce_logout_endpoint: 'Advanced',
-	woocommerce_api_enabled: 'Advanced',
 	woocommerce_allow_tracking: 'Advanced',
 	woocommerce_show_marketplace_suggestions: 'Advanced',
 	woocommerce_custom_orders_table_enabled: 'Advanced',
diff --git a/plugins/woocommerce/includes/admin/class-wc-admin-notices.php b/plugins/woocommerce/includes/admin/class-wc-admin-notices.php
index 3894c017977..1e1254aaa6b 100644
--- a/plugins/woocommerce/includes/admin/class-wc-admin-notices.php
+++ b/plugins/woocommerce/includes/admin/class-wc-admin-notices.php
@@ -9,7 +9,6 @@
 use Automattic\Jetpack\Constants;
 use Automattic\WooCommerce\Enums\DefaultCustomerAddress;
 use Automattic\WooCommerce\Internal\Utilities\Users;
-use Automattic\WooCommerce\Internal\Utilities\WebhookUtil;

 defined( 'ABSPATH' ) || exit;

@@ -69,7 +68,6 @@ class WC_Admin_Notices {
 		add_action( 'woocommerce_installed', array( __CLASS__, 'reset_admin_notices' ) );
 		add_action( 'update_option_woocommerce_file_download_method', array( __CLASS__, 'add_redirect_download_method_notice' ) );
 		add_action( 'admin_init', array( __CLASS__, 'hide_notices' ), 20 );
-		add_action( 'admin_init', array( __CLASS__, 'maybe_remove_legacy_api_removal_notice' ), 20 );

 		// @TODO: This prevents Action Scheduler async jobs from storing empty list of notices during WC installation.
 		// That could lead to OBW not starting and 'Run setup wizard' notice not appearing in WP admin, which we want
@@ -176,47 +174,6 @@ class WC_Admin_Notices {
 		self::add_notice( 'template_files' );
 		self::add_min_version_notice();
 		self::add_maxmind_missing_license_key_notice();
-		self::maybe_add_legacy_api_removal_notice();
-	}
-
-	/**
-	 * Add an admin notice about unsupported webhooks with Legacy API payload if at least one of these exist
-	 * and the Legacy REST API plugin is not installed.
-	 *
-	 * @return void
-	 */
-	private static function maybe_add_legacy_api_removal_notice() {
-		if ( wc_get_container()->get( WebhookUtil::class )->get_legacy_webhooks_count() > 0 && ! WC()->legacy_rest_api_is_available() ) {
-			self::add_custom_notice(
-				'legacy_webhooks_unsupported_in_woo_90',
-				sprintf(
-					'%s%s',
-					sprintf(
-						'<h4>%s</h4>',
-						esc_html__( 'WooCommerce webhooks that use the Legacy REST API are unsupported', 'woocommerce' )
-					),
-					sprintf(
-					// translators: Placeholders are URLs.
-						wpautop( __( '⚠️ The WooCommerce Legacy REST API has been removed from WooCommerce, this will cause <a href="%1$s">webhooks on this site that are configured to use the Legacy REST API</a> to stop working. <a target="_blank" href="%2$s">A separate WooCommerce extension is available</a> to allow these webhooks to keep using the Legacy REST API without interruption. You can also edit these webhooks to use the current REST API version to generate the payload instead. <b><a target="_blank" href="%3$s">Learn more about this change.</a></b>', 'woocommerce' ) ),
-						admin_url( 'admin.php?page=wc-settings&tab=advanced&section=webhooks&legacy=true' ),
-						'https://wordpress.org/plugins/woocommerce-legacy-rest-api/',
-						'https://developer.woocommerce.com/2023/10/03/the-legacy-rest-api-will-move-to-a-dedicated-extension-in-woocommerce-9-0/'
-					)
-				)
-			);
-		}
-	}
-
-	/**
-	 * Remove the admin notice about the unsupported webhooks if the Legacy REST API plugin is installed.
-	 *
-	 * @internal For exclusive usage of WooCommerce core, backwards compatibility not guaranteed.
-	 * @return void
-	 */
-	public static function maybe_remove_legacy_api_removal_notice() {
-		if ( self::has_notice( 'legacy_webhooks_unsupported_in_woo_90' ) && ( WC()->legacy_rest_api_is_available() || 0 === wc_get_container()->get( WebhookUtil::class )->get_legacy_webhooks_count() ) ) {
-			self::remove_notice( 'legacy_webhooks_unsupported_in_woo_90' );
-		}
 	}

 	/**
diff --git a/plugins/woocommerce/includes/admin/class-wc-admin-webhooks-table-list.php b/plugins/woocommerce/includes/admin/class-wc-admin-webhooks-table-list.php
index e2cb92fe690..c1b6f504784 100644
--- a/plugins/woocommerce/includes/admin/class-wc-admin-webhooks-table-list.php
+++ b/plugins/woocommerce/includes/admin/class-wc-admin-webhooks-table-list.php
@@ -6,8 +6,6 @@
  * @version 3.3.0
  */

-use Automattic\WooCommerce\Internal\Utilities\WebhookUtil;
-
 defined( 'ABSPATH' ) || exit;

 if ( ! class_exists( 'WP_List_Table' ) ) {
@@ -72,16 +70,7 @@ class WC_Admin_Webhooks_Table_List extends WP_List_Table {
 	 */
 	public function column_title( $webhook ) {
 		$edit_link = admin_url( 'admin.php?page=wc-settings&amp;tab=advanced&amp;section=webhooks&amp;edit-webhook=' . $webhook->get_id() );
-		$output    = '';
-
-		// Title.
-		$warning_prefix =
-			$this->uses_legacy_rest_api( $webhook ) && ! WC()->legacy_rest_api_is_available() ?
-			sprintf(
-				"<span title='%s'>⚠️</span>️ ",
-				esc_html__( 'This webhook is configured to be delivered using the Legacy REST API, but the Legacy REST API plugin is not installed on this site.', 'woocommerce' )
-			) : '';
-		$output        .= '<strong>' . $warning_prefix . '<a href="' . esc_url( $edit_link ) . '" class="row-title">' . esc_html( $webhook->get_name() ) . '</a></strong>';
+		$output    = '<strong><a href="' . esc_url( $edit_link ) . '" class="row-title">' . esc_html( $webhook->get_name() ) . '</a></strong>';

 		// Get actions.
 		$actions = array(
@@ -205,20 +194,6 @@ class WC_Admin_Webhooks_Table_List extends WP_List_Table {
 			$status_links[ $status_name ] = "<a href='admin.php?page=wc-settings&amp;tab=advanced&amp;section=webhooks&amp;status=$status_name'$class>" . sprintf( translate_nooped_plural( $label, $num_webhooks[ $status_name ] ), number_format_i18n( $num_webhooks[ $status_name ] ) ) . '</a>';
 		}

-		$legacy_webhooks_count = wc_get_container()->get( WebhookUtil::class )->get_legacy_webhooks_count();
-		if ( $legacy_webhooks_count > 0 ) {
-			$class = '';
-
-			// phpcs:ignore WordPress.Security.NonceVerification.Recommended
-			if ( 'true' === sanitize_key( wp_unslash( $_REQUEST['legacy'] ?? '' ) ) ) {
-				$class = ' class="current"';
-			}
-
-			$label = $this->get_status_label( __( 'Legacy', 'woocommerce' ), $legacy_webhooks_count );
-
-			$status_links['legacy'] = "<a href='admin.php?page=wc-settings&amp;tab=advanced&amp;section=webhooks&amp;legacy=true'$class>" . sprintf( translate_nooped_plural( $label, $legacy_webhooks_count ), number_format_i18n( $legacy_webhooks_count ) ) . '</a>';
-		}
-
 		return $status_links;
 	}

@@ -350,21 +325,13 @@ class WC_Admin_Webhooks_Table_List extends WP_List_Table {
 	/**
 	 * Get how many of the existing webhooks are configured to use the legacy payload format.
 	 *
-	 * @since 9.0.0
+	 * @since      9.0.0
+	 * @deprecated 10.8.0 The Legacy REST API has been removed from WooCommerce core. This always returns 0.
 	 *
-	 * @return int Count of existing webhooks are configured to use the legacy payload format.
+	 * @return int Always 0.
 	 */
 	public function get_legacy_api_webhooks_count() {
-		return count( array_filter( $this->items, array( $this, 'uses_legacy_rest_api' ) ) );
-	}
-
-	/**
-	 * Check if a given webhook is configured to use the legacy payload format.
-	 *
-	 * @param WC_Webhook $webhook Webhook object.
-	 * @return bool True if the webhook is configured to use the legacy payload format.
-	 */
-	private function uses_legacy_rest_api( $webhook ) {
-		return 0 === strpos( $webhook->get_api_version(), 'legacy' );
+		wc_deprecated_function( __METHOD__, '10.8.0' );
+		return 0;
 	}
 }
diff --git a/plugins/woocommerce/includes/admin/class-wc-admin-webhooks.php b/plugins/woocommerce/includes/admin/class-wc-admin-webhooks.php
index 0407ff4fffa..d447a3a3d1d 100644
--- a/plugins/woocommerce/includes/admin/class-wc-admin-webhooks.php
+++ b/plugins/woocommerce/includes/admin/class-wc-admin-webhooks.php
@@ -310,8 +310,6 @@ class WC_Admin_Webhooks {
 			echo '<input type="hidden" name="tab" value="advanced" />';
 			echo '<input type="hidden" name="section" value="webhooks" />';

-			self::maybe_display_legacy_rest_api_warning();
-
 			$webhooks_table_list->views();
 			$webhooks_table_list->search_box( __( 'Search webhooks', 'woocommerce' ), 'webhook' );
 			$webhooks_table_list->display();
@@ -325,81 +323,6 @@ class WC_Admin_Webhooks {
 		}
 	}

-	/**
-	 * Display a warning message if the Legacy REST API extension is not installed
-	 * and there are webhooks configured to use the legacy payload format.
-	 */
-	private static function maybe_display_legacy_rest_api_warning() {
-		global $webhooks_table_list;
-
-		if ( WC()->legacy_rest_api_is_available() ) {
-			return;
-		}
-
-		$legacy_api_webhooks_count = $webhooks_table_list->get_legacy_api_webhooks_count();
-		if ( 0 === $legacy_api_webhooks_count ) {
-			return;
-		}
-
-		?>
-		<div class='error inline'>
-			<p><strong>
-				<?php echo esc_html__( 'Incompatible webhooks warning', 'woocommerce' ); ?>
-			</strong></p>
-			<p>
-				<?php
-				echo wp_kses_data(
-					sprintf(
-						/* translators: %s = webhooks count */
-						_n(
-							"There's %d webhook that is configured to be delivered using the Legacy REST API, which has been removed from WooCommerce. This webhook will fail to be sent.",
-							'There are %d webhooks that are configured to be delivered using the Legacy REST API, which has been removed from WooCommerce. These webhooks will fail to be sent.',
-							$legacy_api_webhooks_count,
-							'woocommerce'
-						),
-						$legacy_api_webhooks_count,
-						'woocommerce'
-					)
-				);
-				?>
-			</p>
-			<p>
-				<?php
-				echo wp_kses(
-					sprintf(
-						/* translators: %s = URL */
-						_n(
-							'This webhook has the ⚠️ symbol in front of its name in the list below. Please either edit the webhook to use a different delivery format, or install and activate <a href="%s" target="_blank">the WooCommerce Legacy REST API extension</a>.',
-							'These webhooks have the ⚠️ symbol in front of their names in the list below. Please either edit the webhooks to use a different delivery format, or install and activate <a href="%s" target="_blank">the WooCommerce Legacy REST API extension</a>.',
-							$legacy_api_webhooks_count,
-							'woocommerce'
-						),
-						'https://wordpress.org/plugins/woocommerce-legacy-rest-api/'
-					),
-					array(
-						'a' => array(
-							'href'   => array(),
-							'target' => array(),
-						),
-					)
-				);
-				?>
-			</p>
-			<p><strong>
-				<?php
-				echo wp_kses_data(
-					sprintf(
-						/* translators: %s is an URL */
-						__( "<a href='%s'>More information</a>", 'woocommerce' ),
-						'https://developer.woocommerce.com/2023/10/03/the-legacy-rest-api-will-move-to-a-dedicated-extension-in-woocommerce-9-0/'
-					)
-				);
-				?>
-			</strong></p>
-		</div>
-		<?php
-	}
-
 	/**
 	 * Logs output.
 	 *
diff --git a/plugins/woocommerce/includes/admin/settings/class-wc-settings-advanced.php b/plugins/woocommerce/includes/admin/settings/class-wc-settings-advanced.php
index 6c0c347a0cc..631f3459890 100644
--- a/plugins/woocommerce/includes/admin/settings/class-wc-settings-advanced.php
+++ b/plugins/woocommerce/includes/admin/settings/class-wc-settings-advanced.php
@@ -56,8 +56,12 @@ class WC_Settings_Advanced extends WC_Settings_Page {
 			$sections['rest_api_caching'] = __( 'REST API caching', 'woocommerce' );
 		}

-		$sections['webhooks']        = __( 'Webhooks', 'woocommerce' );
-		$sections['legacy_api']      = __( 'Legacy API', 'woocommerce' );
+		$sections['webhooks'] = __( 'Webhooks', 'woocommerce' );
+
+		if ( has_filter( 'woocommerce_settings_rest_api' ) ) {
+			$sections['legacy_api'] = __( 'Legacy API', 'woocommerce' );
+		}
+
 		$sections['woocommerce_com'] = __( 'WooCommerce.com', 'woocommerce' );

 		if ( FeaturesUtil::feature_is_enabled( 'blueprint' ) ) {
@@ -402,48 +406,23 @@ class WC_Settings_Advanced extends WC_Settings_Page {
 	/**
 	 * Get settings for the legacy API section.
 	 *
+	 * The section is only registered when an extension has hooked into the
+	 * `woocommerce_settings_rest_api` filter, so this acts purely as an
+	 * extension point — core no longer ships any settings of its own here.
+	 *
 	 * @return array
 	 */
 	protected function get_settings_for_legacy_api_section() {
-		$legacy_api_setting_desc =
-			'yes' === get_option( 'woocommerce_api_enabled' ) ?
-			__( 'The legacy REST API is enabled', 'woocommerce' ) :
-			__( 'The legacy REST API is NOT enabled', 'woocommerce' );
-
-		$legacy_api_setting_tip =
-			WC()->legacy_rest_api_is_available() ?
-			__( 'ℹ️️ The WooCommerce Legacy REST API extension is installed and active.', 'woocommerce' ) :
-			sprintf(
-				/* translators: placeholders are URLs */
-				__( '⚠️ The WooCommerce Legacy REST API has been moved to <a target=”_blank” href="%1$s">a dedicated extension</a>. <b><a target=”_blank” href="%2$s">Learn more about this change</a></b>', 'woocommerce' ),
-				'https://wordpress.org/plugins/woocommerce-legacy-rest-api/',
-				'https://developer.woocommerce.com/2023/10/03/the-legacy-rest-api-will-move-to-a-dedicated-extension-in-woocommerce-9-0/'
-			);
-
-		$settings =
-			array(
-				array(
-					'title' => '',
-					'type'  => 'title',
-					'desc'  => '',
-					'id'    => 'legacy_api_options',
-				),
-				array(
-					'title'    => __( 'Legacy API', 'woocommerce' ),
-					'desc'     => $legacy_api_setting_desc,
-					'id'       => 'woocommerce_api_enabled',
-					'type'     => 'checkbox',
-					'default'  => 'no',
-					'disabled' => true,
-					'desc_tip' => $legacy_api_setting_tip,
-				),
-				array(
-					'type' => 'sectionend',
-					'id'   => 'legacy_api_options',
-				),
-			);
-
-		return apply_filters( 'woocommerce_settings_rest_api', $settings );
+		/**
+		 * Filter the settings rendered in the Legacy API section of the Advanced settings tab.
+		 *
+		 * Core no longer ships any settings in this section; the section itself is only
+		 * registered when at least one callback is hooked into this filter.
+		 *
+		 * @since 3.4.0
+		 * @param array $settings Settings array. Empty by default.
+		 */
+		return apply_filters( 'woocommerce_settings_rest_api', array() );
 	}

 	/**
diff --git a/plugins/woocommerce/includes/admin/settings/views/html-webhooks-edit.php b/plugins/woocommerce/includes/admin/settings/views/html-webhooks-edit.php
index e4f2e4d12c6..81cebe5778b 100644
--- a/plugins/woocommerce/includes/admin/settings/views/html-webhooks-edit.php
+++ b/plugins/woocommerce/includes/admin/settings/views/html-webhooks-edit.php
@@ -2,6 +2,8 @@
 /**
  * Admin View: Edit Webhooks
  *
+ * @var WC_Webhook $webhook Webhook object.
+ *
  * @package WooCommerce\Admin\Webhooks\Views
  */

@@ -146,13 +148,18 @@ if ( ! defined( 'ABSPATH' ) ) {
 								?>
 							</option>
 						<?php endforeach; ?>
-						<?php
-						$legacy_api_option_name =
-							WC()->legacy_rest_api_is_available() ?
-							__( 'Legacy API v3 (deprecated)', 'woocommerce' ) :
-							__( 'Legacy API v3 (⚠️ NOT AVAILABLE)', 'woocommerce' );
-						?>
-						<option value="legacy_v3" <?php selected( 'legacy_v3', $webhook->get_api_version(), true ); ?>><?php echo esc_html( $legacy_api_option_name ); ?></option>
+						<?php if ( WC()->legacy_rest_api_is_available() ) : ?>
+							<option value="legacy_v3" <?php selected( 'legacy_v3', $webhook->get_api_version(), true ); ?>>
+								<?php esc_html_e( 'Legacy API v3 (deprecated)', 'woocommerce' ); ?>
+							</option>
+						<?php elseif ( ! in_array( $webhook->get_api_version(), wc_get_webhook_rest_api_versions(), true ) ) : ?>
+							<option value="<?php echo esc_attr( $webhook->get_api_version() ); ?>" selected="selected">
+								<?php
+									/* translators: %s: unsupported api version identifier e.g. legacy_v3 */
+									echo esc_html( sprintf( __( '%s (unsupported)', 'woocommerce' ), $webhook->get_api_version() ) );
+								?>
+							</option>
+						<?php endif; ?>
 					</select>
 				</td>
 			</tr>
diff --git a/plugins/woocommerce/includes/admin/views/html-admin-page-status-report.php b/plugins/woocommerce/includes/admin/views/html-admin-page-status-report.php
index 5c99761c603..95807e1fe13 100644
--- a/plugins/woocommerce/includes/admin/views/html-admin-page-status-report.php
+++ b/plugins/woocommerce/includes/admin/views/html-admin-page-status-report.php
@@ -97,21 +97,6 @@ if ( file_exists( $plugin_path ) ) {
 			<td><?php echo esc_html( ! empty( $wc_version ) ? $wc_version : $environment['version'] ); ?></td>

 		</tr>
-		<tr>
-			<td data-export-label="Legacy REST API Package Version"><?php esc_html_e( 'WooCommerce Legacy REST API package', 'woocommerce' ); ?>:</td>
-			<td class="help"><?php echo wc_help_tip( esc_html__( 'The WooCommerce Legacy REST API plugin running on this site.', 'woocommerce' ) ); ?></td>
-			<td>
-				<?php
-				if ( WC()->legacy_rest_api_is_available() ) {
-					$plugin_path = wc_get_container()->get( \Automattic\WooCommerce\Utilities\PluginUtil::class )->get_wp_plugin_id( 'woocommerce-legacy-rest-api' );
-					$version     = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin_path )['Version'] ?? '';
-					echo '<mark class="yes"><span class="dashicons dashicons-yes"></span> ' . esc_html( $version ) . ' <code class="private">' . esc_html( wc()->api->get_rest_api_package_path() ) . '</code></mark> ';
-				} else {
-					echo '<mark class="info-icon"><span class="dashicons dashicons-info"></span> ' . esc_html__( 'The Legacy REST API plugin is not installed on this site.', 'woocommerce' ) . '</mark>';
-				}
-				?>
-			</td>
-		</tr>
 		<tr>
 			<td data-export-label="Action Scheduler Version"><?php esc_html_e( 'Action Scheduler package', 'woocommerce' ); ?>:</td>
 			<td class="help"><?php echo wc_help_tip( esc_html__( 'Action Scheduler package running on your site.', 'woocommerce' ) ); ?></td>
@@ -704,11 +689,6 @@ if ( 0 < $mu_plugins_count ) :
 		</tr>
 	</thead>
 	<tbody>
-		<tr>
-			<td data-export-label="Legacy API Enabled"><?php esc_html_e( 'Legacy API enabled', 'woocommerce' ); ?>:</td>
-			<td class="help"><?php echo wc_help_tip( esc_html__( 'Does your site have the Legacy REST API enabled?', 'woocommerce' ) ); /* phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped */ ?></td>
-			<td><?php echo $settings['api_enabled'] ? '<mark class="yes"><span class="dashicons dashicons-yes"></span></mark>' : '<mark class="no">&ndash;</mark>'; ?></td>
-		</tr>
 		<tr>
 			<td data-export-label="Force SSL"><?php esc_html_e( 'Force SSL', 'woocommerce' ); ?>:</td>
 			<td class="help"><?php echo wc_help_tip( esc_html__( 'Does your site force a SSL Certificate for transactions?', 'woocommerce' ) ); /* phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped */ ?></td>
diff --git a/plugins/woocommerce/includes/class-wc-install.php b/plugins/woocommerce/includes/class-wc-install.php
index 556833f2105..8b7fb5fa5df 100644
--- a/plugins/woocommerce/includes/class-wc-install.php
+++ b/plugins/woocommerce/includes/class-wc-install.php
@@ -21,7 +21,6 @@ use Automattic\WooCommerce\Utilities\FeaturesUtil;
 use Automattic\WooCommerce\Internal\Utilities\DatabaseUtil;
 use Automattic\WooCommerce\Internal\WCCom\ConnectionHelper as WCConnectionHelper;
 use Automattic\WooCommerce\Utilities\{ OrderUtil, PluginUtil };
-use Automattic\WooCommerce\Internal\Utilities\PluginInstaller;

 defined( 'ABSPATH' ) || exit;

@@ -383,7 +382,6 @@ class WC_Install {
 		add_filter( 'wpmu_drop_tables', array( __CLASS__, 'wpmu_drop_tables' ) );
 		add_filter( 'cron_schedules', array( __CLASS__, 'cron_schedules' ) );
 		add_action( 'admin_init', array( __CLASS__, 'newly_installed' ) );
-		add_action( 'woocommerce_activate_legacy_rest_api_plugin', array( __CLASS__, 'maybe_install_legacy_api_plugin' ) );

 		// DB update notice.
 		add_filter( 'woocommerce_get_note_from_db', array( \WC_Notes_Run_Db_Update::class, 'maybe_update_notice' ), 10 );
@@ -692,8 +690,6 @@ class WC_Install {
 		self::update_wc_version();
 		self::maybe_update_db_version();
 		self::maybe_set_store_id();
-		self::maybe_install_legacy_api_plugin();
-		self::maybe_activate_legacy_api_enabled_option();
 	}

 	/**
@@ -1615,177 +1611,6 @@ class WC_Install {
 		}
 	}

-	/**
-	 * Install and activate the WooCommerce Legacy REST API plugin from the WordPress.org directory if all the following is true:
-	 *
-	 * 1. We are in a WooCommerce upgrade process (not a new install).
-	 * 2. The 'woocommerce_skip_legacy_rest_api_plugin_auto_install' filter returns false (which is the default).
-	 * 3. The plugin is not installed and active already (but see note about multisite below).
-	 * 4. The Legacy REST API is enabled in the site OR the site has at least one webhook defined that uses the Legacy REST API payload format (disabled webhooks also count).
-	 *
-	 * In multisite setups it could happen that the plugin was installed by an installation process performed in another site.
-	 * In this case we check if the plugin was autoinstalled in such a way, and if so we activate it if the conditions are fulfilled.
-	 *
-	 * @internal For exclusive usage of WooCommerce core, backwards compatibility not guaranteed.
-	 *
-	 * @return void
-	 */
-	public static function maybe_install_legacy_api_plugin() {
-		if ( self::is_new_install() ) {
-			return;
-		}
-
-		// Did we previously install this plugin?
-		// We check both the woocommerce_history_of_autoinstalled_plugins options (introduced in 9.0)
-		// and the woocommerce_autoinstalled_plugins option (info should still exist here if the plugin has been uninstalled but not manually reinstalled).
-		$legacy_api_plugin          = 'woocommerce-legacy-rest-api/woocommerce-legacy-rest-api.php';
-		$autoinstalled_plugins      = (array) get_site_option( 'woocommerce_history_of_autoinstalled_plugins', array() );
-		$previously_installed_by_us = isset( $autoinstalled_plugins[ $legacy_api_plugin ] );
-		if ( ! $previously_installed_by_us ) {
-			$autoinstalled_plugins      = (array) get_site_option( 'woocommerce_autoinstalled_plugins', array() );
-			$previously_installed_by_us = isset( $autoinstalled_plugins[ $legacy_api_plugin ] );
-		}
-
-		/**
-		 * Filter to skip the automatic installation of the WooCommerce Legacy REST API plugin
-		 * from the WordPress.org plugins directory.
-		 *
-		 * By default, this is true (skip installation) if we have a record of previously installing the legacy plugin,
-		 * and false (do not skip) if we have no record of previously installing the plugin.
-		 *
-		 * @since 8.8.0
-		 *
-		 * @param bool $skip_auto_install False, defaulting to "don't skip the plugin automatic installation".
-		 * @returns bool True to skip the plugin automatic installation, false to install the plugin if necessary.
-		 */
-		if ( apply_filters( 'woocommerce_skip_legacy_rest_api_plugin_auto_install', $previously_installed_by_us ) ) {
-			return;
-		}
-
-		if ( ( 'yes' !== get_option( 'woocommerce_api_enabled' ) &&
-			0 === wc_get_container()->get( Automattic\WooCommerce\Internal\Utilities\WebhookUtil::class )->get_legacy_webhooks_count( true ) ) ) {
-			return;
-		}
-
-		wp_clean_plugins_cache();
-		if ( ! function_exists( 'get_plugins' ) ) {
-			require_once ABSPATH . 'wp-admin/includes/plugin.php';
-		}
-		if ( isset( get_plugins()[ $legacy_api_plugin ] ) ) {
-			if ( ! $previously_installed_by_us ) {
-				// The plugin was installed manually so let's not interfere.
-				return;
-			}
-
-			$active_valid_plugins = wc_get_container()->get( PluginUtil::class )->get_all_active_valid_plugins();
-			if ( in_array( $legacy_api_plugin, $active_valid_plugins, true ) ) {
-				return;
-			}
-
-			// The plugin was automatically installed in a different installation process - can happen in multisite.
-			$install_ok = true;
-		} else {
-			try {
-				$install_result = wc_get_container()->get( PluginInstaller::class )->install_plugin(
-					'https://downloads.wordpress.org/plugin/woocommerce-legacy-rest-api.latest-stable.zip',
-					array(
-						'info_link' => 'https://developer.woocommerce.com/2023/10/03/the-legacy-rest-api-will-move-to-a-dedicated-extension-in-woocommerce-9-0/',
-					)
-				);
-
-				if ( $install_result['already_installing'] ?? null ) {
-					// The plugin is in the process of being installed already (can happen in multisite),
-					// but we still need to activate it for ourselves once it's installed.
-					as_schedule_single_action( time() + 10, 'woocommerce_activate_legacy_rest_api_plugin' );
-					return;
-				}
-
-				$install_ok = $install_result['install_ok'];
-			} catch ( \Exception $ex ) {
-				wc_get_logger()->error(
-					'The autoinstall of the WooCommerce Legacy REST API plugin failed: ' . $ex->getMessage(),
-					array(
-						'source'    => 'plugin_auto_installs',
-						'exception' => $ex,
-					)
-				);
-				$install_ok = false;
-			}
-		}
-
-		$plugin_page_url              = 'https://wordpress.org/plugins/woocommerce-legacy-rest-api/';
-		$blog_post_url                = 'https://developer.woocommerce.com/2023/10/03/the-legacy-rest-api-will-move-to-a-dedicated-extension-in-woocommerce-9-0/';
-		$site_legacy_api_settings_url = get_admin_url( null, '/admin.php?page=wc-settings&tab=advanced&section=legacy_api' );
-		$site_webhooks_settings_url   = get_admin_url( null, '/admin.php?page=wc-settings&tab=advanced&section=webhooks' );
-		$site_logs_url                = get_admin_url( null, '/admin.php?page=wc-status&tab=logs' );
-
-		if ( $install_ok ) {
-			$activation_result = activate_plugin( $legacy_api_plugin );
-			if ( $activation_result instanceof \WP_Error ) {
-				$message = sprintf(
-				/* translators: 1 = URL of Legacy REST API plugin page, 2 = URL of Legacy API settings in current site, 3 = URL of webhooks settings in current site, 4 = URL of logs page in current site, 5 = URL of plugins page in current site, 6 = URL of blog post about the Legacy REST API removal */
-					__( '⚠️ WooCommerce installed <a href="%1$s">the Legacy REST API plugin</a> because this site has <a href="%2$s">the Legacy REST API enabled</a> or has <a href="%3$s">legacy webhooks defined</a>, but it failed to activate it (see error details in <a href="%4$s">the WooCommerce logs</a>). Please go to <a href="%5$s">the plugins page</a> and activate it manually. <a href="%6$s">More information</a>', 'woocommerce' ),
-					$plugin_page_url,
-					$site_legacy_api_settings_url,
-					$site_webhooks_settings_url,
-					$site_logs_url,
-					get_admin_url( null, '/plugins.php' ),
-					$blog_post_url
-				);
-				$notice_name = 'woocommerce_legacy_rest_api_plugin_activation_failed';
-				wc_get_logger()->error(
-					__( 'WooCommerce installed the Legacy REST API plugin but failed to activate it, see context for more details.', 'woocommerce' ),
-					array(
-						'source' => 'plugin_auto_installs',
-						'error'  => $activation_result,
-					)
-				);
-			} else {
-				$message = sprintf(
-				/* translators: 1 = URL of Legacy REST API plugin page, 2 = URL of Legacy API settings in current site, 3 = URL of webhooks settings in current site, 4 = URL of blog post about the Legacy REST API removal */
-					__( 'ℹ️ WooCommerce installed and activated <a href="%1$s">the Legacy REST API plugin</a> because this site has <a href="%2$s">the Legacy REST API enabled</a> or has <a href="%3$s">legacy webhooks defined</a>. <a href="%4$s">More information</a>', 'woocommerce' ),
-					$plugin_page_url,
-					$site_legacy_api_settings_url,
-					$site_webhooks_settings_url,
-					$blog_post_url
-				);
-				$notice_name = 'woocommerce_legacy_rest_api_plugin_activated';
-				wc_get_logger()->info( 'WooCommerce activated the Legacy REST API plugin in this site.', array( 'source' => 'plugin_auto_installs' ) );
-			}
-
-			\WC_Admin_Notices::add_custom_notice( $notice_name, $message );
-		} else {
-			$message = sprintf(
-				/* translators: 1 = URL of Legacy REST API plugin page, 2 = URL of Legacy API settings in current site, 3 = URL of webhooks settings in current site, 4 = URL of logs page in current site, 5 = URL of blog post about the Legacy REST API removal */
-				__( '⚠️ WooCommerce attempted to install <a href="%1$s">the Legacy REST API plugin</a> because this site has <a href="%2$s">the Legacy REST API enabled</a> or has <a href="%3$s">legacy webhooks defined</a>, but the installation failed (see error details in <a href="%4$s">the WooCommerce logs</a>). Please install and activate the plugin manually. <a href="%5$s">More information</a>', 'woocommerce' ),
-				$plugin_page_url,
-				$site_legacy_api_settings_url,
-				$site_webhooks_settings_url,
-				$site_logs_url,
-				$blog_post_url
-			);
-
-			\WC_Admin_Notices::add_custom_notice( 'woocommerce_legacy_rest_api_plugin_install_failed', $message );
-
-			// Note that we aren't adding an entry to the error log because PluginInstaller->install_plugin will have done that already.
-		}
-
-		\WC_Admin_Notices::store_notices();
-	}
-
-	/**
-	 * If in a previous version of WooCommerce the Legacy REST API plugin was installed manually but the core Legacy REST API was kept disabled,
-	 * now the Legacy API is still disabled and can't be manually enabled from settings UI (the plugin, which is now in control, won't allow that),
-	 * which is weird and confusing. So we detect this case and explicitly enable it.
-	 *
-	 * @return void
-	 */
-	private static function maybe_activate_legacy_api_enabled_option() {
-		if ( ! self::is_new_install() && is_plugin_active( 'woocommerce-legacy-rest-api/woocommerce-legacy-rest-api.php' ) && 'yes' !== get_option( 'woocommerce_api_enabled' ) ) {
-			update_option( 'woocommerce_api_enabled', 'yes' );
-		}
-	}
-
 	/**
 	 * Set up the database tables which the plugin needs to function.
 	 * WARNING: If you are modifying this method, make sure that its safe to call regardless of the state of database.
diff --git a/plugins/woocommerce/includes/class-wc-tracker.php b/plugins/woocommerce/includes/class-wc-tracker.php
index 6b563abeaa3..432e1d3c966 100644
--- a/plugins/woocommerce/includes/class-wc-tracker.php
+++ b/plugins/woocommerce/includes/class-wc-tracker.php
@@ -1062,7 +1062,7 @@ class WC_Tracker {
 			'base_state'                            => WC()->countries->get_base_state(),
 			'base_postcode'                         => WC()->countries->get_base_postcode(),
 			'selling_locations'                     => WC()->countries->get_allowed_countries(),
-			'api_enabled'                           => get_option( 'woocommerce_api_enabled', 'no' ),
+			'api_enabled'                           => WC()->legacy_rest_api_is_available() ? 'yes' : 'no',
 			'weight_unit'                           => get_option( 'woocommerce_weight_unit' ),
 			'dimension_unit'                        => get_option( 'woocommerce_dimension_unit' ),
 			'download_method'                       => get_option( 'woocommerce_file_download_method' ),
diff --git a/plugins/woocommerce/includes/class-wc-webhook.php b/plugins/woocommerce/includes/class-wc-webhook.php
index edacb650477..dbff8f68dbd 100644
--- a/plugins/woocommerce/includes/class-wc-webhook.php
+++ b/plugins/woocommerce/includes/class-wc-webhook.php
@@ -416,7 +416,7 @@ class WC_Webhook extends WC_Legacy_Webhook {
 	 *
 	 * @param mixed $resource_id First hook argument, typically the resource ID.
 	 * @return mixed              Payload data.
-	 * @throws \Exception The webhook is configured to use the Legacy REST API, but the Legacy REST API plugin is not available.
+	 * @throws \Exception If the webhook uses an unsupported API version.
 	 * @since  2.2.0
 	 */
 	public function build_payload( $resource_id ) {
@@ -426,27 +426,42 @@ class WC_Webhook extends WC_Legacy_Webhook {
 		$current_user = get_current_user_id();
 		wp_set_current_user( $this->get_user_id() );

-		$resource = $this->get_resource();
-		$event    = $this->get_event();
+		try {
+			$resource = $this->get_resource();
+			$event    = $this->get_event();

-		// If a resource has been deleted, just include the ID.
-		if ( 'deleted' === $event ) {
+			// If a resource has been deleted, just include the ID in the payload.
 			$payload = array(
 				'id' => $resource_id,
 			);
-		} elseif ( in_array( $this->get_api_version(), wc_get_webhook_rest_api_versions(), true ) ) {
-				$payload = $this->get_wp_api_payload( $resource, $resource_id, $event );
-		} else {
-			if ( ! WC()->legacy_rest_api_is_available() ) {
-				throw new \Exception( 'The Legacy REST API plugin is not installed on this site. More information: https://developer.woocommerce.com/2023/10/03/the-legacy-rest-api-will-move-to-a-dedicated-extension-in-woocommerce-9-0/ ' );
-			}
-			$payload = wc()->api->get_webhook_api_payload( $resource, $resource_id, $event );
-		}

-		// Restore the current user.
-		wp_set_current_user( $current_user );
+			if ( 'deleted' !== $event ) {
+				$api_version = $this->get_api_version();

-		return apply_filters( 'woocommerce_webhook_payload', $payload, $resource, $resource_id, $this->get_id() );
+				if ( in_array( $api_version, wc_get_webhook_rest_api_versions(), true ) ) {
+					$payload = $this->get_wp_api_payload( $resource, $resource_id, $event );
+				} elseif ( 'legacy_v3' === $api_version && WC()->legacy_rest_api_is_available() ) {
+					wc_deprecated_function( 'Webhook delivery via the Legacy REST API', '9.0.0', 'editing the webhook to use a current API version' );
+					$payload = wc()->api->get_webhook_api_payload( $resource, $resource_id, $event );
+				} else {
+					throw new \Exception( esc_html__( 'Unsupported webhook API version. Please edit this webhook to use a current REST API version.', 'woocommerce' ) );
+				}
+			}
+
+			/**
+			 * Filters the webhook payload before delivery.
+			 *
+			 * @since 2.2.0
+			 * @param mixed  $payload     Payload data.
+			 * @param string $resource    Resource type (e.g. 'order').
+			 * @param mixed  $resource_id Resource ID.
+			 * @param int    $webhook_id  Webhook ID.
+			 */
+			return apply_filters( 'woocommerce_webhook_payload', $payload, $resource, $resource_id, $this->get_id() );
+		} finally {
+			// Restore the current user.
+			wp_set_current_user( $current_user );
+		}
 	}

 	/**
diff --git a/plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-system-status-v2-controller.php b/plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-system-status-v2-controller.php
index 42fa79da1ec..ada2e354e73 100644
--- a/plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-system-status-v2-controller.php
+++ b/plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-system-status-v2-controller.php
@@ -1470,7 +1470,7 @@ class WC_REST_System_Status_V2_Controller extends WC_REST_Controller {

 		// Return array of useful settings for debugging.
 		return array(
-			'api_enabled'                    => 'yes' === get_option( 'woocommerce_api_enabled' ),
+			'api_enabled'                    => WC()->legacy_rest_api_is_available(),
 			'force_ssl'                      => 'yes' === get_option( 'woocommerce_force_ssl_checkout' ),
 			'currency'                       => get_woocommerce_currency(),
 			'currency_symbol'                => get_woocommerce_currency_symbol(),
diff --git a/plugins/woocommerce/includes/wc-deprecated-functions.php b/plugins/woocommerce/includes/wc-deprecated-functions.php
index dc50045d502..855b60c3b25 100644
--- a/plugins/woocommerce/includes/wc-deprecated-functions.php
+++ b/plugins/woocommerce/includes/wc-deprecated-functions.php
@@ -1416,3 +1416,16 @@ function get_woocommerce_api_url( $path ) {

 	return $url;
 }
+
+/**
+ * Legacy REST API detection.
+ *
+ * This option used to be used to detect if the Legacy REST API was enabled, but the functionality was moved into a separate extension and deprecated.
+ * The extension itself toggles this option between `yes` and `no` depending on whether the extension is active or not, but since this is the only
+ * way to enable or disable the legacy API now, all we actually need to do is detect if the extension is active.
+ *
+ * @return string 'yes' or 'no'.
+ */
+add_filter( 'pre_option_woocommerce_api_enabled', function() {
+	return WC()->legacy_rest_api_is_available() ? 'yes' : 'no';
+} );
diff --git a/plugins/woocommerce/phpstan-baseline.neon b/plugins/woocommerce/phpstan-baseline.neon
index 5704d657d5f..9fbecb56f3e 100644
--- a/plugins/woocommerce/phpstan-baseline.neon
+++ b/plugins/woocommerce/phpstan-baseline.neon
@@ -3288,12 +3288,6 @@ parameters:
 			count: 1
 			path: includes/admin/class-wc-admin-webhooks.php

-		-
-			message: '#^Method WC_Admin_Webhooks\:\:maybe_display_legacy_rest_api_warning\(\) has no return type specified\.$#'
-			identifier: missingType.return
-			count: 1
-			path: includes/admin/class-wc-admin-webhooks.php
-
 		-
 			message: '#^Method WC_Admin_Webhooks\:\:notices\(\) has no return type specified\.$#'
 			identifier: missingType.return
@@ -7951,9 +7945,9 @@ parameters:
 			path: includes/admin/settings/views/html-settings-tax.php

 		-
-			message: '#^Variable \$webhook might not be defined\.$#'
-			identifier: variable.undefined
-			count: 17
+			message: '#^Parameter \#1 \$text of function esc_attr expects string, int given\.$#'
+			identifier: argument.type
+			count: 1
 			path: includes/admin/settings/views/html-webhooks-edit.php

 		-
@@ -8034,18 +8028,6 @@ parameters:
 			count: 1
 			path: includes/admin/views/html-admin-page-status-logs.php

-		-
-			message: '#^Access to private property WooCommerce\:\:\$api\.$#'
-			identifier: property.private
-			count: 1
-			path: includes/admin/views/html-admin-page-status-report.php
-
-		-
-			message: '#^Call to method get_rest_api_package_path\(\) on an unknown class WC_API\.$#'
-			identifier: class.notFound
-			count: 1
-			path: includes/admin/views/html-admin-page-status-report.php
-
 		-
 			message: '#^Calling self\:\:output_plugins_info\(\) outside of class scope\.$#'
 			identifier: outOfClass.self
diff --git a/plugins/woocommerce/src/Admin/PageController.php b/plugins/woocommerce/src/Admin/PageController.php
index f17e0bf1252..0a05f4535a5 100644
--- a/plugins/woocommerce/src/Admin/PageController.php
+++ b/plugins/woocommerce/src/Admin/PageController.php
@@ -327,7 +327,6 @@ class PageController {
 					'',
 					'keys',
 					'webhooks',
-					'legacy_api',
 					'woocommerce_com',
 					'features',
 					'blueprint',
diff --git a/plugins/woocommerce/src/Internal/Utilities/LegacyRestApiStub.php b/plugins/woocommerce/src/Internal/Utilities/LegacyRestApiStub.php
index 79133d21694..21a018dbd8a 100644
--- a/plugins/woocommerce/src/Internal/Utilities/LegacyRestApiStub.php
+++ b/plugins/woocommerce/src/Internal/Utilities/LegacyRestApiStub.php
@@ -186,7 +186,7 @@ class LegacyRestApiStub implements RegisterHooksInterface {
 	public function get_endpoint_data( $endpoint, $params = array() ) {
 		wc_doing_it_wrong(
 			'get_endpoint_data',
-			"'WC()->api->get_endpoint_data' is deprecated, please use the following instead: wc_get_container()->get(Automattic\WooCommerce\Utilities\RestApiUtil::class)->get_endpoint_data",
+			'Deprecated, please use the following instead: wc_get_container()->get(Automattic\WooCommerce\Utilities\RestApiUtil::class)->get_endpoint_data',
 			'9.1.0'
 		);

diff --git a/plugins/woocommerce/src/Internal/Utilities/WebhookUtil.php b/plugins/woocommerce/src/Internal/Utilities/WebhookUtil.php
index 60b1b2cc5fa..3aeed925f54 100644
--- a/plugins/woocommerce/src/Internal/Utilities/WebhookUtil.php
+++ b/plugins/woocommerce/src/Internal/Utilities/WebhookUtil.php
@@ -5,8 +5,6 @@

 namespace Automattic\WooCommerce\Internal\Utilities;

-use WC_Cache_Helper;
-
 /**
  * Class with utility methods for dealing with webhooks.
  */
@@ -135,29 +133,4 @@ class WebhookUtil {
 			)
 		);
 	}
-
-	/**
-	 * Gets the count of webhooks that are configured to use the Legacy REST API to compose their payloads.
-	 *
-	 * @param bool $clear_cache If true, the previously cached value of the count will be discarded if it exists.
-	 *
-	 * @return int
-	 */
-	public function get_legacy_webhooks_count( bool $clear_cache = false ): int {
-		global $wpdb;
-
-		$cache_key = WC_Cache_Helper::get_cache_prefix( 'webhooks' ) . 'legacy_count';
-		if ( $clear_cache ) {
-			wp_cache_delete( $cache_key, 'webhooks' );
-		}
-
-		$count = wp_cache_get( $cache_key, 'webhooks' );
-
-		if ( false === $count ) {
-			$count = absint( $wpdb->get_var( "SELECT count( webhook_id ) FROM {$wpdb->prefix}wc_webhooks WHERE `api_version` < 1;" ) );
-			wp_cache_add( $cache_key, $count, 'webhooks' );
-		}
-
-		return $count;
-	}
 }
diff --git a/plugins/woocommerce/src/Utilities/PluginUtil.php b/plugins/woocommerce/src/Utilities/PluginUtil.php
index f55bbf00f37..8877122a0b8 100644
--- a/plugins/woocommerce/src/Utilities/PluginUtil.php
+++ b/plugins/woocommerce/src/Utilities/PluginUtil.php
@@ -36,21 +36,12 @@ class PluginUtil {
 	 */
 	private $woocommerce_aware_active_plugins = null;

-	/**
-	 * List of plugins excluded from feature compatibility warnings in UI.
-	 *
-	 * @var string[]
-	 */
-	private $plugins_excluded_from_compatibility_ui;
-
 	/**
 	 * Creates a new instance of the class.
 	 */
 	public function __construct() {
 		add_action( 'activated_plugin', array( $this, 'handle_plugin_de_activation' ), 10, 0 );
 		add_action( 'deactivated_plugin', array( $this, 'handle_plugin_de_activation' ), 10, 0 );
-
-		$this->plugins_excluded_from_compatibility_ui = array( 'woocommerce-legacy-rest-api/woocommerce-legacy-rest-api.php' );
 	}

 	/**
@@ -227,31 +218,21 @@ class PluginUtil {
 	 */
 	public function generate_incompatible_plugin_feature_warning( string $feature_id, array $plugin_feature_info ): string {
 		$incompatibles      = $this->get_items_considered_incompatible( $feature_id, $plugin_feature_info );
-		$incompatibles      = array_filter( $incompatibles, 'is_plugin_active' );
-		$incompatibles      = array_values( array_diff( $incompatibles, $this->get_plugins_excluded_from_compatibility_ui() ) );
+		$incompatibles      = array_values( array_filter( $incompatibles, 'is_plugin_active' ) );
 		$incompatible_count = count( $incompatibles );

 		$feature_warnings = array();
-		if ( 'custom_order_tables' === $feature_id && 'yes' === get_option( 'woocommerce_api_enabled' ) ) {
-			if ( is_plugin_active( 'woocommerce-legacy-rest-api/woocommerce-legacy-rest-api.php' ) ) {
-				$legacy_api_and_hpos_incompatibility_warning_text =
-					sprintf(
-						// translators: %s is a URL.
-						__( '⚠ <b><a target="_blank" href="%s">The Legacy REST API plugin</a> is installed and active on this site.</b> Please be aware that the WooCommerce Legacy REST API is <b>not</b> compatible with HPOS.', 'woocommerce' ),
-						'https://wordpress.org/plugins/woocommerce-legacy-rest-api/'
-					);
-			} else {
-				$legacy_api_and_hpos_incompatibility_warning_text =
+		if ( 'custom_order_tables' === $feature_id && WC()->legacy_rest_api_is_available() ) {
+			$legacy_api_and_hpos_incompatibility_warning_text =
 				sprintf(
 					// translators: %s is a URL.
-					__( '⚠ <b><a target="_blank" href="%s">The Legacy REST API</a> is active on this site.</b> Please be aware that the WooCommerce Legacy REST API is <b>not</b> compatible with HPOS.', 'woocommerce' ),
-					admin_url( 'admin.php?page=wc-settings&tab=advanced&section=legacy_api' )
+					__( '⚠ <b><a target="_blank" href="%s">The Legacy REST API plugin</a> is installed and active on this site.</b> Please be aware that the WooCommerce Legacy REST API is <b>not</b> compatible with HPOS.', 'woocommerce' ),
+					'https://wordpress.org/plugins/woocommerce-legacy-rest-api/'
 				);
-			}

 			/**
 			 * Filter to modify the warning text that appears in the HPOS section of the features settings page
-			 * when both the Legacy REST API is active (via WooCommerce core or via the Legacy REST API plugin)
+			 * when the Legacy REST API plugin is active
 			 * and the orders table is in use as the primary data store for orders.
 			 *
 			 * @param string $legacy_api_and_hpos_incompatibility_warning_text Original warning text.
@@ -330,12 +311,14 @@ class PluginUtil {

 	/**
 	 * Get the names of the plugins that are excluded from the feature compatibility UI.
-	 * These plugins won't be considered as incompatible with any existing feature for the purposes
-	 * of displaying compatibility warning in UI, even if they declare incompatibilities explicitly.
 	 *
-	 * @return string[] Plugin names relative to the root plugins directory.
+	 * Core no longer excludes any plugins from the compatibility UI, so this method
+	 * always returns an empty array. Retained as a stable public API for backwards
+	 * compatibility with any external callers.
+	 *
+	 * @return string[] Always an empty array.
 	 */
 	public function get_plugins_excluded_from_compatibility_ui() {
-		return $this->plugins_excluded_from_compatibility_ui;
+		return array();
 	}
 }
diff --git a/plugins/woocommerce/tests/e2e-pw/tests/api-tests/system-status/system-status-crud.test.ts b/plugins/woocommerce/tests/e2e-pw/tests/api-tests/system-status/system-status-crud.test.ts
index c81bc1dace4..edce462c109 100644
--- a/plugins/woocommerce/tests/e2e-pw/tests/api-tests/system-status/system-status-crud.test.ts
+++ b/plugins/woocommerce/tests/e2e-pw/tests/api-tests/system-status/system-status-crud.test.ts
@@ -152,7 +152,6 @@ const schemas = {
 		{ field: 'parent_author_url', type: any( String ) },
 	],
 	settings: [
-		{ field: 'api_enabled', type: any( Boolean ) },
 		{ field: 'force_ssl', type: any( Boolean ) },
 		{ field: 'currency', type: any( String ) },
 		{ field: 'currency_symbol', type: any( String ) },
diff --git a/plugins/woocommerce/tests/legacy/bootstrap.php b/plugins/woocommerce/tests/legacy/bootstrap.php
index 3f2e02d7d29..1f8a8495deb 100644
--- a/plugins/woocommerce/tests/legacy/bootstrap.php
+++ b/plugins/woocommerce/tests/legacy/bootstrap.php
@@ -301,7 +301,6 @@ class WC_Unit_Tests_Bootstrap {
 		// test cases.
 		require_once $this->tests_dir . '/includes/wp-http-testcase.php';
 		require_once $this->tests_dir . '/framework/class-wc-unit-test-case.php';
-		require_once $this->tests_dir . '/framework/class-wc-api-unit-test-case.php';
 		require_once $this->tests_dir . '/framework/class-wc-rest-unit-test-case.php';

 		// Helpers.
diff --git a/plugins/woocommerce/tests/legacy/framework/class-wc-api-unit-test-case.php b/plugins/woocommerce/tests/legacy/framework/class-wc-api-unit-test-case.php
deleted file mode 100644
index e5d386c3772..00000000000
--- a/plugins/woocommerce/tests/legacy/framework/class-wc-api-unit-test-case.php
+++ /dev/null
@@ -1,87 +0,0 @@
-<?php
-/**
- * Base class for REST API test classes.
- *
- * @package WooCommerce\Tests\Framework
- */
-
-/**
- * WC API Unit Test Case
- *
- * Provides REST API specific setup/tear down/assert methods, along with some helper.
- * functions.
- *
- * @since 2.2
- */
-class WC_API_Unit_Test_Case extends WC_Unit_Test_Case {
-
-	/**
-	 * Setup the test case case.
-	 *
-	 * @since 2.2
-	 * @see WC_Unit_Test_Case::setUp()
-	 * @throws Exception The Legacy REST API plugin is not installed.
-	 */
-	public function setUp(): void {
-		if ( is_null( wc()->api ) ) {
-			throw new Exception( 'The Legacy REST API plugin is not installed' );
-		}
-
-		parent::setUp();
-
-		// load API classes.
-		WC()->api->includes();
-
-		// set user.
-		$this->user_id = $this->login_as_role( 'shop_manager' );
-
-		// this isn't used, but it causes a warning unless set.
-		$_SERVER['REQUEST_METHOD'] = null;
-
-		// mock the API server to prevent headers from being sent.
-		$this->mock_server = $this->getMockBuilder( 'WC_API_Server' )->setMethods( array( 'header' ) )->disableOriginalConstructor()->getMock();
-
-		WC()->api->register_resources( $this->mock_server );
-	}
-
-	/**
-	 * Assert the given response is an API error with a specific code and status.
-	 *
-	 * @since 2.2
-	 * @param string   $code error code, e.g. `woocommerce_api_user_cannot_read_orders_count`.
-	 * @param int|null $status HTTP status code associated with error, e.g. 400.
-	 * @param WP_Error $response Response to assert.
-	 * @param string   $message optional message to render when assertion fails.
-	 */
-	public function assertHasAPIError( $code, $status, $response, $message = '' ) {
-
-		$this->assertWPError( $response, $message );
-
-		// code.
-		$this->assertEquals( $code, $response->get_error_code(), $message );
-
-		// status.
-		$data = $response->get_error_data();
-
-		$this->assertArrayHasKey( 'status', $data, $message );
-		$this->assertEquals( $status, $data['status'], $message );
-	}
-
-
-	/**
-	 * Disable the given capability for the current user, used for testing.
-	 * permission checking.
-	 *
-	 * @since 2.2
-	 * @param string $capability e.g. `read_private_shop_orders`.
-	 */
-	protected function disable_capability( $capability ) {
-
-		$user = wp_get_current_user();
-		$user->add_cap( $capability, false );
-
-		// flush capabilities, see https://core.trac.wordpress.org/ticket/28374.
-		$user->get_role_caps();
-		$user->update_user_level_from_caps();
-	}
-}
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version2/system-status.php b/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version2/system-status.php
index 82bebb46672..a38834cc58d 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version2/system-status.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version2/system-status.php
@@ -213,7 +213,7 @@ class WC_Tests_REST_System_Status_V2 extends WC_REST_Unit_Test_Case {
 		$settings = (array) $this->fetch_or_get_system_status_data_for_user( self::$administrator_user )['settings'];

 		$this->assertEquals( 17, count( $settings ) );
-		$this->assertEquals( ( 'yes' === get_option( 'woocommerce_api_enabled' ) ), $settings['api_enabled'] );
+		$this->assertEquals( WC()->legacy_rest_api_is_available(), $settings['api_enabled'] );
 		$this->assertEquals( get_woocommerce_currency(), $settings['currency'] );
 		$this->assertEquals( $term_response, $settings['taxonomies'] );
 	}
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version3/system-status.php b/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version3/system-status.php
index 91fda6f1a30..c5ffd545288 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version3/system-status.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version3/system-status.php
@@ -238,7 +238,7 @@ class WC_Tests_REST_System_Status extends WC_REST_Unit_Test_Case {
 		$settings = (array) $this->fetch_or_get_system_status_data_for_user( self::$administrator_user )['settings'];

 		$this->assertEquals( 17, count( $settings ) );
-		$this->assertEquals( ( 'yes' === get_option( 'woocommerce_api_enabled' ) ), $settings['api_enabled'] );
+		$this->assertEquals( WC()->legacy_rest_api_is_available(), $settings['api_enabled'] );
 		$this->assertEquals( get_woocommerce_currency(), $settings['currency'] );
 		$this->assertEquals( $term_response, $settings['taxonomies'] );
 	}
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/api/plugins.php b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/api/plugins.php
index 18ce2820e56..04ae94ae797 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/api/plugins.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/api/plugins.php
@@ -58,7 +58,7 @@ class WC_Admin_Tests_API_Plugins extends WC_REST_Unit_Test_Case {
 		$request = new WP_REST_Request( 'POST', $this->endpoint . '/install' );
 		$request->set_query_params(
 			array(
-				'plugins' => 'woocommerce-legacy-rest-api',
+				'plugins' => 'hello-dolly',
 			)
 		);
 		$response = $this->server->dispatch( $request );
@@ -69,9 +69,9 @@ class WC_Admin_Tests_API_Plugins extends WC_REST_Unit_Test_Case {
 		$plugins = get_plugins();

 		$this->assertEquals( 200, $response->get_status() );
-		$this->assertEquals( array( 'woocommerce-legacy-rest-api' ), $data['data']['installed'] );
+		$this->assertEquals( array( 'hello-dolly' ), $data['data']['installed'] );
 		$this->assertEquals( true, $data['success'] );
-		$this->assertArrayHasKey( 'woocommerce-legacy-rest-api/woocommerce-legacy-rest-api.php', $plugins );
+		$this->assertArrayHasKey( 'hello-dolly/hello.php', $plugins );
 	}

 	/**
@@ -84,7 +84,7 @@ class WC_Admin_Tests_API_Plugins extends WC_REST_Unit_Test_Case {
 		$request->set_query_params(
 			array(
 				'async'   => true,
-				'plugins' => 'woocommerce-legacy-rest-api',
+				'plugins' => 'hello-dolly',
 			)
 		);
 		$response = $this->server->dispatch( $request );
diff --git a/plugins/woocommerce/tests/php/includes/settings/class-wc-settings-advanced-test.php b/plugins/woocommerce/tests/php/includes/settings/class-wc-settings-advanced-test.php
index 2091fc2d0e0..0cbcc64fd14 100644
--- a/plugins/woocommerce/tests/php/includes/settings/class-wc-settings-advanced-test.php
+++ b/plugins/woocommerce/tests/php/includes/settings/class-wc-settings-advanced-test.php
@@ -29,7 +29,6 @@ class WC_Settings_Advanced_Test extends WC_Settings_Unit_Test_Case {
 			'',
 			'keys',
 			'webhooks',
-			'legacy_api',
 			'woocommerce_com',
 			'features',
 		);
@@ -47,7 +46,6 @@ class WC_Settings_Advanced_Test extends WC_Settings_Unit_Test_Case {
 	 *
 	 * @testWith ["", "woocommerce_settings_pages"]
 	 *           ["woocommerce_com", "woocommerce_com_integration_settings"]
-	 *           ["legacy_api", "woocommerce_settings_rest_api"]
 	 *
 	 * @param string $section_name The section name to test getting the settings for.
 	 * @param string $filter_name The name of the filter that is expected to be triggered.
@@ -142,23 +140,6 @@ class WC_Settings_Advanced_Test extends WC_Settings_Unit_Test_Case {
 		$this->assertEquals( $expected, $setting_ids_and_types );
 	}

-	/**
-	 * @testdox get_settings('legacy_api') should return all the settings for the legacy_api section.
-	 */
-	public function test_get_legacy_api_settings_returns_all_settings() {
-		$sut = new WC_Settings_Advanced();
-
-		$expected = array(
-			'legacy_api_options'      => array( 'title', 'sectionend' ),
-			'woocommerce_api_enabled' => 'checkbox',
-		);
-
-		$settings              = $sut->get_settings_for_section( 'legacy_api' );
-		$setting_ids_and_types = $this->get_ids_and_types( $settings );
-
-		$this->assertEquals( $expected, $setting_ids_and_types );
-	}
-
 	/**
 	 * @testdox output method should invoke the output method of the appropriate class depending on the section.
 	 *