Commit ef336e3bbd3 for woocommerce
commit ef336e3bbd3400598dd56f9e1b0e71d53c852418
Author: Lucio Giannotta <lucio.giannotta@a8c.com>
Date: Mon Jul 6 23:55:53 2026 +0200
Flip variation gallery to the 5% canary cohort (#66218)
diff --git a/plugins/woocommerce/src/Internal/Features/FeaturesController.php b/plugins/woocommerce/src/Internal/Features/FeaturesController.php
index 1b748415324..1a88bc909cb 100644
--- a/plugins/woocommerce/src/Internal/Features/FeaturesController.php
+++ b/plugins/woocommerce/src/Internal/Features/FeaturesController.php
@@ -526,7 +526,7 @@ class FeaturesController {
),
'option_key' => \Automattic\WooCommerce\Internal\VariationGallery\Package::ENABLE_OPTION_NAME,
'is_experimental' => true,
- 'enabled_by_default' => false,
+ 'enabled_by_default' => \Automattic\WooCommerce\Internal\VariationGallery\Package::is_in_canary_cohort(),
'skip_compatibility_checks' => true,
'default_plugin_compatibility' => FeaturePluginCompatibility::COMPATIBLE,
),
diff --git a/plugins/woocommerce/src/Internal/VariationGallery/Package.php b/plugins/woocommerce/src/Internal/VariationGallery/Package.php
index efeb7188d72..286d9fc5142 100644
--- a/plugins/woocommerce/src/Internal/VariationGallery/Package.php
+++ b/plugins/woocommerce/src/Internal/VariationGallery/Package.php
@@ -38,18 +38,49 @@ class Package {
*/
public const ENABLE_OPTION_NAME = 'wc_feature_woocommerce_additional_variation_images_enabled';
+ /**
+ * `woocommerce_remote_variant_assignment` option name.
+ */
+ private const REMOTE_VARIANT_OPTION_NAME = 'woocommerce_remote_variant_assignment';
+
+ /**
+ * Highest variant bucket in the canary cohort. Range is 1-120, so
+ * `<= 6` gets exactly 5%. Matches the Brands merge precedent.
+ */
+ public const CANARY_MAX_VARIANT = 6;
+
+ /**
+ * Whether the current store is in the canary cohort.
+ *
+ * @internal Removable once the feature is at 100% rollout.
+ * @return bool
+ */
+ public static function is_in_canary_cohort(): bool {
+ $variant_assignment = (int) get_option( self::REMOTE_VARIANT_OPTION_NAME, 0 );
+ return $variant_assignment > 0 && $variant_assignment <= self::CANARY_MAX_VARIANT;
+ }
+
/**
* Whether the merged variation gallery feature is enabled for the current
* request.
*
- * Reads the same option as the Features toggles, so the `FeaturesController`
- * and the merged-package machinery share a single source of truth. Defaults
- * to off for the 10.9 canary period.
+ * Explicit `yes`/`no` on the option wins; unset falls back to the canary
+ * cohort.
*
* @return bool
*/
public static function is_enabled() {
- return 'yes' === get_option( self::ENABLE_OPTION_NAME, 'no' );
+ $option_value = get_option( self::ENABLE_OPTION_NAME, '' );
+
+ if ( 'yes' === $option_value ) {
+ return true;
+ }
+
+ if ( 'no' === $option_value ) {
+ return false;
+ }
+
+ return self::is_in_canary_cohort();
}
/**
diff --git a/plugins/woocommerce/src/Internal/VariationGallery/Telemetry.php b/plugins/woocommerce/src/Internal/VariationGallery/Telemetry.php
index ff706ccb4e7..940c5d656a0 100644
--- a/plugins/woocommerce/src/Internal/VariationGallery/Telemetry.php
+++ b/plugins/woocommerce/src/Internal/VariationGallery/Telemetry.php
@@ -52,7 +52,7 @@ class Telemetry implements RegisterHooksInterface {
$option_value = get_option( Package::ENABLE_OPTION_NAME, '' );
$variant_assignment = (int) get_option( 'woocommerce_remote_variant_assignment', 0 );
- $cohort = ( $variant_assignment > 0 && $variant_assignment <= 5 ) ? 'treatment' : 'control';
+ $cohort = Package::is_in_canary_cohort() ? 'treatment' : 'control';
$legacy_plugin_active = self::is_legacy_plugin_active();
$legacy_plugin_file = WP_PLUGIN_DIR . '/' . self::LEGACY_PLUGIN_FILE;
@@ -105,8 +105,9 @@ class Telemetry implements RegisterHooksInterface {
);
return array(
- 'feature_enabled' => 'yes' === $option_value ? 'yes' : 'no',
+ 'feature_enabled' => Package::is_enabled() ? 'yes' : 'no',
'feature_option_explicit' => '' === $option_value ? 'no' : 'yes',
+ 'remote_variant_assignment' => $variant_assignment,
'remote_variant_cohort' => $cohort,
'legacy_avi_plugin_active' => $legacy_plugin_active ? 'yes' : 'no',
'legacy_avi_plugin_installed' => file_exists( $legacy_plugin_file ) ? 'yes' : 'no',
diff --git a/plugins/woocommerce/tests/php/src/Internal/VariationGallery/PackageTest.php b/plugins/woocommerce/tests/php/src/Internal/VariationGallery/PackageTest.php
index c2d9be64c89..3b2286d15b0 100644
--- a/plugins/woocommerce/tests/php/src/Internal/VariationGallery/PackageTest.php
+++ b/plugins/woocommerce/tests/php/src/Internal/VariationGallery/PackageTest.php
@@ -27,10 +27,85 @@ class PackageTest extends \WC_Unit_Test_Case {
'woocommerce-db-updates'
);
delete_option( Migration::COMPLETED_OPTION );
+ delete_option( Package::ENABLE_OPTION_NAME );
+ delete_option( 'woocommerce_remote_variant_assignment' );
parent::tearDown();
}
+ /**
+ * @testdox is_enabled honors an explicit 'yes' on the feature option.
+ */
+ public function test_is_enabled_returns_true_when_option_explicitly_yes(): void {
+ update_option( Package::ENABLE_OPTION_NAME, 'yes' );
+ update_option( 'woocommerce_remote_variant_assignment', 99 );
+
+ $this->assertTrue( Package::is_enabled() );
+ }
+
+ /**
+ * @testdox is_enabled honors an explicit 'no' on the feature option even when the store is in the canary cohort.
+ */
+ public function test_is_enabled_returns_false_when_option_explicitly_no(): void {
+ update_option( Package::ENABLE_OPTION_NAME, 'no' );
+ update_option( 'woocommerce_remote_variant_assignment', 1 );
+
+ $this->assertFalse( Package::is_enabled() );
+ }
+
+ /**
+ * @testdox is_enabled includes stores in the canary cohort when the option is unset.
+ */
+ public function test_is_enabled_returns_true_for_canary_cohort_when_option_unset(): void {
+ delete_option( Package::ENABLE_OPTION_NAME );
+ update_option( 'woocommerce_remote_variant_assignment', 1 );
+
+ $this->assertTrue( Package::is_enabled() );
+ }
+
+ /**
+ * @testdox is_enabled includes the last variant bucket in the canary cohort when the option is unset.
+ */
+ public function test_is_enabled_returns_true_for_canary_cohort_boundary_when_option_unset(): void {
+ delete_option( Package::ENABLE_OPTION_NAME );
+ update_option( 'woocommerce_remote_variant_assignment', Package::CANARY_MAX_VARIANT );
+
+ $this->assertTrue( Package::is_enabled() );
+ }
+
+ /**
+ * @testdox is_enabled excludes stores outside the canary cohort when the option is unset.
+ */
+ public function test_is_enabled_returns_false_for_control_cohort_when_option_unset(): void {
+ delete_option( Package::ENABLE_OPTION_NAME );
+ update_option( 'woocommerce_remote_variant_assignment', Package::CANARY_MAX_VARIANT + 1 );
+
+ $this->assertFalse( Package::is_enabled() );
+ }
+
+ /**
+ * @testdox is_enabled excludes stores with no variant assignment when the option is unset.
+ */
+ public function test_is_enabled_returns_false_when_option_and_variant_unset(): void {
+ delete_option( Package::ENABLE_OPTION_NAME );
+ delete_option( 'woocommerce_remote_variant_assignment' );
+
+ $this->assertFalse( Package::is_enabled() );
+ }
+
+ /**
+ * @testdox is_in_canary_cohort reports membership independently of the feature option.
+ */
+ public function test_is_in_canary_cohort_is_independent_of_option_value(): void {
+ update_option( 'woocommerce_remote_variant_assignment', 1 );
+ update_option( Package::ENABLE_OPTION_NAME, 'no' );
+ $this->assertTrue( Package::is_in_canary_cohort() );
+
+ update_option( 'woocommerce_remote_variant_assignment', Package::CANARY_MAX_VARIANT + 1 );
+ update_option( Package::ENABLE_OPTION_NAME, 'yes' );
+ $this->assertFalse( Package::is_in_canary_cohort() );
+ }
+
/**
* @testdox maybe_schedule_migration queues the migration.
*/