Commit 7cc97cbe19e for woocommerce

commit 7cc97cbe19ee08af58261775268393848e8e3761
Author: Michael Pretty <prettyboymp@users.noreply.github.com>
Date:   Thu Jun 11 06:23:27 2026 -0400

    Add OrderUtil::custom_orders_table_data_sync_is_enabled() accessor (#65649)

    * Add OrderUtil::custom_orders_table_data_sync_is_enabled() accessor

    Expose a cheap public check for whether HPOS real-time data sync is enabled,
    delegating to DataSynchronizer::data_sync_is_enabled() via COTMigrationUtil.

    Extensions currently call OrderUtil::is_custom_order_tables_in_sync() just to
    learn whether sync is turned on, which additionally runs an expensive
    posts<->orders pending-sync query on every call. This accessor answers the
    "is sync enabled" question with a single option read.

    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

    * Fix return type colon spacing for PSR12 (lint)

    Remove the space before the colon in the new accessor's return type
    declaration to satisfy PSR12.Functions.ReturnTypeDeclaration.SpaceBeforeColon.

    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

    ---------

    Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

diff --git a/plugins/woocommerce/changelog/wooplug-6190-order-util-data-sync-enabled-accessor b/plugins/woocommerce/changelog/wooplug-6190-order-util-data-sync-enabled-accessor
new file mode 100644
index 00000000000..78d4acc08ca
--- /dev/null
+++ b/plugins/woocommerce/changelog/wooplug-6190-order-util-data-sync-enabled-accessor
@@ -0,0 +1,4 @@
+Significance: minor
+Type: add
+
+Add OrderUtil::custom_orders_table_data_sync_is_enabled() so extensions can cheaply check whether HPOS data sync is enabled without running the expensive is_custom_order_tables_in_sync() query.
diff --git a/plugins/woocommerce/src/Internal/Utilities/COTMigrationUtil.php b/plugins/woocommerce/src/Internal/Utilities/COTMigrationUtil.php
index c6695e98286..b24cf82fc80 100644
--- a/plugins/woocommerce/src/Internal/Utilities/COTMigrationUtil.php
+++ b/plugins/woocommerce/src/Internal/Utilities/COTMigrationUtil.php
@@ -81,6 +81,21 @@ class COTMigrationUtil {
 		return ! $this->data_synchronizer->has_orders_pending_sync();
 	}

+	/**
+	 * Checks whether the real-time data sync between the posts and orders tables is enabled.
+	 *
+	 * Unlike is_custom_order_tables_in_sync(), this only reflects whether the sync setting is enabled and does
+	 * not run a query to determine whether the tables are currently fully synchronized, so it is much cheaper
+	 * to call. Use this when you only need to know if sync is turned on, not whether every order is in sync.
+	 *
+	 * @since 11.0.0
+	 *
+	 * @return bool True if data sync is enabled, false otherwise.
+	 */
+	public function custom_orders_table_data_sync_is_enabled(): bool {
+		return $this->data_synchronizer->data_sync_is_enabled();
+	}
+
 	/**
 	 * Gets value of a meta key from WC_Data object if passed, otherwise from the post object.
 	 * This helper function support backward compatibility for meta box functions, when moving from posts based store to custom tables.
diff --git a/plugins/woocommerce/src/Utilities/OrderUtil.php b/plugins/woocommerce/src/Utilities/OrderUtil.php
index 4e6fefd8cdd..e2d5a6811ea 100644
--- a/plugins/woocommerce/src/Utilities/OrderUtil.php
+++ b/plugins/woocommerce/src/Utilities/OrderUtil.php
@@ -67,6 +67,21 @@ final class OrderUtil {
 		return wc_get_container()->get( COTMigrationUtil::class )->is_custom_order_tables_in_sync();
 	}

+	/**
+	 * Checks whether the real-time data sync between the posts and orders tables is enabled.
+	 *
+	 * Unlike is_custom_order_tables_in_sync(), this only reflects whether the sync setting is enabled (a cheap
+	 * option read) and does not run a query to check whether the tables are currently fully synchronized. Use
+	 * this when you only need to know if sync is turned on, not whether every order is currently in sync.
+	 *
+	 * @since 11.0.0
+	 *
+	 * @return bool True if data sync is enabled, false otherwise.
+	 */
+	public static function custom_orders_table_data_sync_is_enabled(): bool {
+		return wc_get_container()->get( COTMigrationUtil::class )->custom_orders_table_data_sync_is_enabled();
+	}
+
 	/**
 	 * Gets value of a meta key from WC_Data object if passed, otherwise from the post object.
 	 * This helper function support backward compatibility for meta box functions, when moving from posts based store to custom tables.
diff --git a/plugins/woocommerce/tests/php/src/Internal/Utilities/COTMigrationUtilTest.php b/plugins/woocommerce/tests/php/src/Internal/Utilities/COTMigrationUtilTest.php
index 08aca344c70..0493ff5867b 100644
--- a/plugins/woocommerce/tests/php/src/Internal/Utilities/COTMigrationUtilTest.php
+++ b/plugins/woocommerce/tests/php/src/Internal/Utilities/COTMigrationUtilTest.php
@@ -137,6 +137,67 @@ class COTMigrationUtilTest extends \WC_Unit_Test_Case {
 		$this->assertFalse( $this->sut->is_custom_order_tables_in_sync() );
 	}

+	/**
+	 * @testdox `custom_orders_table_data_sync_is_enabled` should return true when data sync is enabled.
+	 */
+	public function test_custom_orders_table_data_sync_is_enabled_is_true() {
+		$data_sync_mock = $this->getMockBuilder( DataSynchronizer::class )
+			->setMethods( array( 'data_sync_is_enabled' ) )
+			->getMock();
+
+		$data_sync_mock->method( 'data_sync_is_enabled' )->willReturn( true );
+
+		// This is needed to prevent "Call to private method Mock_DataSynchronizer_xxxx::process_added_option" errors.
+		remove_filter( 'updated_option', array( $data_sync_mock, 'process_updated_option' ), 999, 3 );
+		remove_filter( 'added_option', array( $data_sync_mock, 'process_added_option' ), 999, 2 );
+
+		$cot_controller = wc_get_container()->get( CustomOrdersTableController::class );
+		$this->sut      = new COTMigrationUtil();
+		$this->sut->init( $cot_controller, $data_sync_mock );
+		$this->assertTrue( $this->sut->custom_orders_table_data_sync_is_enabled() );
+	}
+
+	/**
+	 * @testdox `custom_orders_table_data_sync_is_enabled` should return false when data sync is disabled.
+	 */
+	public function test_custom_orders_table_data_sync_is_enabled_is_false() {
+		$data_sync_mock = $this->getMockBuilder( DataSynchronizer::class )
+			->setMethods( array( 'data_sync_is_enabled' ) )
+			->getMock();
+
+		$data_sync_mock->method( 'data_sync_is_enabled' )->willReturn( false );
+
+		// This is needed to prevent "Call to private method Mock_DataSynchronizer_xxxx::process_added_option" errors.
+		remove_filter( 'updated_option', array( $data_sync_mock, 'process_updated_option' ), 999, 3 );
+		remove_filter( 'added_option', array( $data_sync_mock, 'process_added_option' ), 999, 2 );
+
+		$cot_controller = wc_get_container()->get( CustomOrdersTableController::class );
+		$this->sut      = new COTMigrationUtil();
+		$this->sut->init( $cot_controller, $data_sync_mock );
+		$this->assertFalse( $this->sut->custom_orders_table_data_sync_is_enabled() );
+	}
+
+	/**
+	 * @testdox `custom_orders_table_data_sync_is_enabled` should not run the expensive pending-sync query.
+	 */
+	public function test_custom_orders_table_data_sync_is_enabled_does_not_query_pending_sync() {
+		$data_sync_mock = $this->getMockBuilder( DataSynchronizer::class )
+			->setMethods( array( 'has_orders_pending_sync', 'data_sync_is_enabled' ) )
+			->getMock();
+
+		$data_sync_mock->method( 'data_sync_is_enabled' )->willReturn( true );
+		$data_sync_mock->expects( $this->never() )->method( 'has_orders_pending_sync' );
+
+		// This is needed to prevent "Call to private method Mock_DataSynchronizer_xxxx::process_added_option" errors.
+		remove_filter( 'updated_option', array( $data_sync_mock, 'process_updated_option' ), 999, 3 );
+		remove_filter( 'added_option', array( $data_sync_mock, 'process_added_option' ), 999, 2 );
+
+		$cot_controller = wc_get_container()->get( CustomOrdersTableController::class );
+		$this->sut      = new COTMigrationUtil();
+		$this->sut->init( $cot_controller, $data_sync_mock );
+		$this->sut->custom_orders_table_data_sync_is_enabled();
+	}
+
 	/**
 	 * @testdox `get_table_for_orders` should return the name of the posts table when HPOS is not in use.
 	 */