Commit e1f386d059e for woocommerce
commit e1f386d059ebdcd34799fd97be62f4b463727344
Author: Jorge A. Torres <jorge.torres@automattic.com>
Date: Wed Sep 9 14:44:00 2026 +0100
Merge 11.2.0 database migrations under `11.2.0` (#68495)
diff --git a/AGENTS.md b/AGENTS.md
index 53138f5c28c..121ad660193 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -218,10 +218,12 @@ To rename subdivision codes, use `Automattic\WooCommerce\Database\Migrations\Mig
## Database Migrations
-Database migrations live in `WC_Install::$db_updates`; read that class for the current mechanics before adding one. Two invariants have broken real releases when violated:
+Database migrations live in `WC_Install::$db_updates`. Read that class for the current mechanics before adding one.
-- Migration keys are one-shot: sites that updated past a key never re-run it. A migration added after a prerelease of the same version has shipped needs a new suffixed key (see existing examples in `$db_updates`), and a key must never be ahead of the version it ships in.
-- Feature flag defaults are persisted, so changing `enabled_by_default` alone doesn't change behavior on existing sites; ship a migration or remove the flag.
+- Each key runs once per site. After a site's database version moves past a key, nothing added to that key later will run there. A key must also never be ahead of the version it ships in.
+- While the version is `X.Y.0-dev`, add new migrations to the plain `X.Y.0` key, even if it already has callbacks. Sequential keys (`X.Y.0-1`, `X.Y.0-2`) are only needed once beta 1 of `X.Y.0` has shipped, because testers on that beta already have their database at `X.Y.0` and would skip anything added to the plain key.
+- To test a migration locally, set the `woocommerce_db_version` and `woocommerce_version` options to the previous release, for example with `wp option update woocommerce_db_version 11.1.0` and the same for `woocommerce_version`. The next page load schedules every callback above that version through Action Scheduler. `wp wc update` runs them immediately instead.
+- Feature flag defaults are persisted, so changing `enabled_by_default` alone doesn't change behavior on existing sites. Ship a migration or remove the flag.
## Comments and Docblocks
diff --git a/plugins/woocommerce/includes/class-wc-install.php b/plugins/woocommerce/includes/class-wc-install.php
index 9ef661b20d1..a27be7d4b16 100644
--- a/plugins/woocommerce/includes/class-wc-install.php
+++ b/plugins/woocommerce/includes/class-wc-install.php
@@ -354,12 +354,8 @@ class WC_Install {
'wc_update_1120_remove_abandoned_cart_recovery',
'wc_update_1120_migrate_stock_notifications_alpha_constant',
'wc_update_1120_delete_surface_cart_checkout_note',
- ),
- '11.2.0-1' => array(
'wc_update_11201_migrate_tax_lookup_order_items',
'wc_update_11201_invalidate_analytics_reports_cache',
- ),
- '11.2.0-2' => array(
'wc_update_11202_reset_refund_returning_customer_markers',
),
);
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/install.php b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/install.php
index 6dacbcf264c..54e627bf2d8 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/install.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/install.php
@@ -66,17 +66,17 @@ class WC_Admin_Tests_Install extends WP_UnitTestCase {
* Ensure that a DB version callback is defined when there are updates.
*/
public function test_db_update_callbacks_exist() {
+ include_once WC_ABSPATH . 'includes/wc-update-functions.php';
+
$all_callbacks = \WC_Install::get_db_update_callbacks();
foreach ( $all_callbacks as $version => $version_callbacks ) {
// Verify all callbacks have been defined.
foreach ( $version_callbacks as $version_callback ) {
- if ( strpos( $version_callback, 'wc_admin_update' ) === 0 ) {
- $this->assertTrue(
- function_exists( $version_callback ),
- "Callback {$version_callback}() is not defined."
- );
- }
+ $this->assertTrue(
+ function_exists( $version_callback ),
+ "Callback {$version_callback}() is not defined."
+ );
}
}
}
diff --git a/plugins/woocommerce/tests/php/includes/class-wc-install-test.php b/plugins/woocommerce/tests/php/includes/class-wc-install-test.php
index 23f00ebc6fc..39fb3d4c52d 100644
--- a/plugins/woocommerce/tests/php/includes/class-wc-install-test.php
+++ b/plugins/woocommerce/tests/php/includes/class-wc-install-test.php
@@ -445,6 +445,14 @@ class WC_Install_Test extends \WC_Unit_Test_Case {
empty( $versions ) || version_compare( preg_replace( '/-.*$/', '', end( $versions ) ), WC()->stable_version(), '<=' ),
'WC_Install::$db_update_callbacks must not contain versions that are ahead of current stable (except, possibly, for suffix).',
);
+
+ // Sequential keys (X.Y.Z-1, X.Y.Z-2) are not needed for -dev versions.
+ if ( '-dev' === substr( WC()->version, -4 ) ) {
+ $this->assertEmpty(
+ preg_grep( '/^' . preg_quote( WC()->stable_version(), '/' ) . '-/', $versions ),
+ sprintf( 'WC_Install::$db_update_callbacks must not contain sequential keys for %1$s while the version is %2$s. Add the callbacks to the plain \'%1$s\' key instead.', WC()->stable_version(), WC()->version ),
+ );
+ }
}
/**
diff --git a/plugins/woocommerce/tests/php/includes/wc-update-functions-test.php b/plugins/woocommerce/tests/php/includes/wc-update-functions-test.php
index 62766af6084..8d24d758f87 100644
--- a/plugins/woocommerce/tests/php/includes/wc-update-functions-test.php
+++ b/plugins/woocommerce/tests/php/includes/wc-update-functions-test.php
@@ -13,8 +13,6 @@ use Automattic\WooCommerce\Blocks\InboxNotifications;
use Automattic\WooCommerce\Blocks\Options as BlockOptions;
use Automattic\WooCommerce\Blocks\Utils\BlockTemplateUtils;
use Automattic\WooCommerce\Enums\OrderStatus;
-use Automattic\WooCommerce\Internal\Admin\OrderTaxLookupMigrator;
-use Automattic\WooCommerce\Internal\BatchProcessing\BatchProcessingController;
use Automattic\WooCommerce\Internal\Features\FeaturesController;
use Automattic\WooCommerce\Internal\VariationGallery\Package as VariationGalleryPackage;
@@ -359,15 +357,11 @@ class WC_Update_Functions_Test extends \WC_Unit_Test_Case {
}
/**
- * @testdox Migration registers and removes the deprecated variation gallery feature option.
+ * @testdox Migration removes the deprecated variation gallery feature option.
*/
public function test_wc_update_11101_remove_deprecated_variation_gallery_option(): void {
include_once WC_ABSPATH . 'includes/wc-update-functions.php';
- $db_updates = WC_Install::get_db_update_callbacks();
- $this->assertArrayHasKey( '11.1.0-1', $db_updates );
- $this->assertContains( 'wc_update_11101_remove_deprecated_variation_gallery_option', $db_updates['11.1.0-1'] );
-
delete_option( VariationGalleryPackage::ENABLE_OPTION_NAME );
wc_update_11101_remove_deprecated_variation_gallery_option();
$this->assertFalse( get_option( VariationGalleryPackage::ENABLE_OPTION_NAME ) );
@@ -382,15 +376,11 @@ class WC_Update_Functions_Test extends \WC_Unit_Test_Case {
}
/**
- * @testdox Migration registers and deletes the cached dashboard out-of-stock count.
+ * @testdox Migration deletes the cached dashboard out-of-stock count.
*/
public function test_wc_update_1110_delete_dashboard_outofstock_count_transient(): void {
include_once WC_ABSPATH . 'includes/wc-update-functions.php';
- $db_updates = WC_Install::get_db_update_callbacks();
- $this->assertArrayHasKey( '11.1.0', $db_updates );
- $this->assertContains( 'wc_update_1110_delete_dashboard_outofstock_count_transient', $db_updates['11.1.0'] );
-
set_transient( 'wc_outofstock_count', 3, DAY_IN_SECONDS );
$this->assertSame( 3, get_transient( 'wc_outofstock_count' ) );
@@ -404,10 +394,6 @@ class WC_Update_Functions_Test extends \WC_Unit_Test_Case {
public function test_wc_update_1120_migrate_stock_notifications_alpha_constant_opts_in(): void {
include_once WC_ABSPATH . 'includes/wc-update-functions.php';
- $db_updates = WC_Install::get_db_update_callbacks();
- $this->assertArrayHasKey( '11.2.0', $db_updates );
- $this->assertContains( 'wc_update_1120_migrate_stock_notifications_alpha_constant', $db_updates['11.2.0'] );
-
delete_option( 'woocommerce_feature_customer_stock_notifications_enabled' );
Constants::set_constant( 'WOOCOMMERCE_BIS_ALPHA_ENABLED', true );
@@ -477,41 +463,11 @@ class WC_Update_Functions_Test extends \WC_Unit_Test_Case {
}
/**
- * @testdox Migration registers and queues the rebuild of the tax lookup table.
- */
- public function test_wc_update_11201_migrate_tax_lookup_order_items(): void {
- include_once WC_ABSPATH . 'includes/wc-update-functions.php';
-
- $db_updates = WC_Install::get_db_update_callbacks();
-
- // Under its own key, so that a store already on 11.2.0 from the batch that shipped beside
- // it still runs the rebuild.
- $this->assertArrayHasKey( '11.2.0-1', $db_updates );
- $this->assertContains( 'wc_update_11201_migrate_tax_lookup_order_items', $db_updates['11.2.0-1'] );
-
- $batch_processor = wc_get_container()->get( BatchProcessingController::class );
- $batch_processor->remove_processor( OrderTaxLookupMigrator::class );
-
- wc_update_11201_migrate_tax_lookup_order_items();
-
- $this->assertTrue(
- $batch_processor->is_enqueued( OrderTaxLookupMigrator::class ),
- 'The migration should hand the rebuild to the batch processing controller.'
- );
-
- $batch_processor->remove_processor( OrderTaxLookupMigrator::class );
- }
-
- /**
- * @testdox Migration registers for WooCommerce 11.2.0 and deletes the retired Surface Cart and Checkout note.
+ * @testdox Migration deletes the retired Surface Cart and Checkout note.
*/
public function test_wc_update_1120_delete_surface_cart_checkout_note(): void {
include_once WC_ABSPATH . 'includes/wc-update-functions.php';
- $db_updates = WC_Install::get_db_update_callbacks();
- $this->assertArrayHasKey( '11.2.0', $db_updates );
- $this->assertContains( 'wc_update_1120_delete_surface_cart_checkout_note', $db_updates['11.2.0'] );
-
$note = new Note();
$note->set_name( InboxNotifications::SURFACE_CART_CHECKOUT_NOTE_NAME );
$note->set_title( 'Surface Cart and Checkout' );
@@ -530,31 +486,6 @@ class WC_Update_Functions_Test extends \WC_Unit_Test_Case {
$this->assertFalse( Notes::get_note_by_name( InboxNotifications::SURFACE_CART_CHECKOUT_NOTE_NAME ), 'The update should remain safe when the note is already absent.' );
}
- /**
- * @testdox Migration invalidates the Analytics report cache, so a response cached before the update stops being served.
- */
- public function test_wc_update_11201_invalidate_analytics_reports_cache(): void {
- include_once WC_ABSPATH . 'includes/wc-update-functions.php';
-
- $db_updates = WC_Install::get_db_update_callbacks();
-
- // Under its own key, so that a store already on 11.2.0 from the batch that shipped beside
- // it still drops its stale responses.
- $this->assertArrayHasKey( '11.2.0-1', $db_updates );
- $this->assertContains( 'wc_update_11201_invalidate_analytics_reports_cache', $db_updates['11.2.0-1'] );
-
- // The cache version is a timestamp, so pin an old one rather than race the clock.
- set_transient( ReportsCache::VERSION_OPTION . '-transient-version', '1000000000' );
-
- $key = 'wc_report_products_pre_update';
- ReportsCache::set( $key, 'pre-update response' );
- $this->assertSame( 'pre-update response', ReportsCache::get( $key ), 'The response should be served from cache before the update runs' );
-
- wc_update_11201_invalidate_analytics_reports_cache();
-
- $this->assertFalse( ReportsCache::get( $key ), 'A response cached before the update should no longer be served' );
- }
-
/**
* @testdox Migration resets stale refund markers in batches and invalidates cached Analytics reports.
*/
@@ -563,11 +494,6 @@ class WC_Update_Functions_Test extends \WC_Unit_Test_Case {
include_once WC_ABSPATH . 'includes/wc-update-functions.php';
- $db_updates = WC_Install::get_db_update_callbacks();
- // Under its own key, so that a store already past the 11.2.0 batches still resets its markers.
- $this->assertArrayHasKey( '11.2.0-2', $db_updates );
- $this->assertContains( 'wc_update_11202_reset_refund_returning_customer_markers', $db_updates['11.2.0-2'] );
-
$order = WC_Helper_Order::create_order();
$order->set_status( OrderStatus::COMPLETED );
$order->save();
diff --git a/plugins/woocommerce/tests/php/src/Internal/Admin/OrderTaxLookupMigratorTest.php b/plugins/woocommerce/tests/php/src/Internal/Admin/OrderTaxLookupMigratorTest.php
index be4390990e6..486ce3aa1de 100644
--- a/plugins/woocommerce/tests/php/src/Internal/Admin/OrderTaxLookupMigratorTest.php
+++ b/plugins/woocommerce/tests/php/src/Internal/Admin/OrderTaxLookupMigratorTest.php
@@ -466,6 +466,18 @@ class OrderTaxLookupMigratorTest extends WC_Unit_Test_Case {
$this->assertFalse( $batch_processor->is_enqueued( OrderTaxLookupMigrator::class ), 'The tool should be able to stop the rebuild.' );
}
+ /**
+ * @testdox The database update queues the rebuild.
+ */
+ public function test_database_update_queues_the_rebuild(): void {
+ $batch_processor = wc_get_container()->get( BatchProcessingController::class );
+ $batch_processor->remove_processor( OrderTaxLookupMigrator::class );
+
+ wc_update_11201_migrate_tax_lookup_order_items();
+
+ $this->assertTrue( $batch_processor->is_enqueued( OrderTaxLookupMigrator::class ), 'The database update should hand the rebuild to the batch processing controller.' );
+ }
+
/**
* @testdox The tool is disabled on a store with nothing to rebuild.
*/