Commit bf74658ba5c for woocommerce
commit bf74658ba5ce3806b0694d1bca4414d1ad69c62f
Author: Karol Manijak <20098064+kmanijak@users.noreply.github.com>
Date: Fri Aug 21 14:47:41 2026 +0200
Enable variation galleries for all stores (#67884)
* Enable variation galleries for all stores
* Add changelog entry for variation gallery rollout
* Correct variation gallery rollout version
* Preserve variation gallery rollout telemetry
* Preserve variation gallery compatibility while enforcing rollout
* Simplify variation gallery rollout compatibility
* Restore variation gallery package declaration order
* Report effective variation gallery state in telemetry
* Fix variation gallery migration test isolation
* Force enable variation gallery on upgrade
* Refine variation gallery rollout migration
* Update variation gallery rollout changelog significance
* Fix variation gallery migration test isolation
* Preserve variation gallery feature compatibility
* Restore variation gallery legacy option mapping
* Handle network-active merged feature plugins
* Normalize active plugin option before merging
* Remove deprecated variation gallery feature option
* Remove obsolete variation gallery enablement checks
* Remove obsolete variation gallery option checks
diff --git a/plugins/woocommerce/changelog/codex-variation-gallery-100 b/plugins/woocommerce/changelog/codex-variation-gallery-100
new file mode 100644
index 00000000000..050220b6ed6
--- /dev/null
+++ b/plugins/woocommerce/changelog/codex-variation-gallery-100
@@ -0,0 +1,4 @@
+Significance: major
+Type: update
+
+Enable variation galleries for all stores and remove the experimental feature toggle.
diff --git a/plugins/woocommerce/includes/class-wc-install.php b/plugins/woocommerce/includes/class-wc-install.php
index 61f76e0445f..86cfde7f0f9 100644
--- a/plugins/woocommerce/includes/class-wc-install.php
+++ b/plugins/woocommerce/includes/class-wc-install.php
@@ -347,6 +347,9 @@ class WC_Install {
'wc_update_1110_cleanup_block_email_posts',
'wc_update_1110_flush_product_count_cache',
),
+ '11.1.0-1' => array(
+ 'wc_update_11101_remove_deprecated_variation_gallery_option',
+ ),
);
/**
diff --git a/plugins/woocommerce/includes/class-wc-product-variable.php b/plugins/woocommerce/includes/class-wc-product-variable.php
index c0a418c5dc8..9c0bb2a8b87 100644
--- a/plugins/woocommerce/includes/class-wc-product-variable.php
+++ b/plugins/woocommerce/includes/class-wc-product-variable.php
@@ -11,7 +11,6 @@
use Automattic\WooCommerce\Enums\ProductStockStatus;
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\Internal\Utilities\ProductUtil;
-use Automattic\WooCommerce\Internal\VariationGallery\Package as VariationGalleryPackage;
defined( 'ABSPATH' ) || exit;
@@ -442,18 +441,14 @@ class WC_Product_Variable extends WC_Product {
$parent_featured_id = (int) $this->get_image_id();
$parent_featured_valid = $parent_featured_id && wp_attachment_is_image( $parent_featured_id );
- $variation_gallery_image_ids = array();
+ $variation_gallery_image_ids = array_values(
+ array_filter(
+ array_map( 'intval', $variation->get_gallery_image_ids() ),
+ 'wp_attachment_is_image'
+ )
+ );
$variation_gallery_html = '';
- if ( VariationGalleryPackage::is_enabled() ) {
- $variation_gallery_image_ids = array_values(
- array_filter(
- array_map( 'intval', $variation->get_gallery_image_ids() ),
- 'wp_attachment_is_image'
- )
- );
- }
-
// Prefer variation-owned images over the parent fallback.
if ( $variation_featured_valid ) {
$selected_image_id = $variation_featured_id;
diff --git a/plugins/woocommerce/includes/wc-template-functions.php b/plugins/woocommerce/includes/wc-template-functions.php
index 4deae04646e..0307f89d3a1 100644
--- a/plugins/woocommerce/includes/wc-template-functions.php
+++ b/plugins/woocommerce/includes/wc-template-functions.php
@@ -2211,11 +2211,8 @@ if ( ! function_exists( 'woocommerce_variable_add_to_cart' ) ) {
// Enqueue variation scripts.
wp_enqueue_script( 'wc-add-to-cart-variation' );
- // Attach a reset snapshot only when variation-gallery swaps are enabled.
- if (
- \Automattic\WooCommerce\Internal\VariationGallery\Package::is_enabled() &&
- ! isset( $attached_gallery_defaults[ $product->get_id() ] )
- ) {
+ // Attach the reset snapshot once per product.
+ if ( ! isset( $attached_gallery_defaults[ $product->get_id() ] ) ) {
wp_add_inline_script(
'wc-add-to-cart-variation',
sprintf(
diff --git a/plugins/woocommerce/includes/wc-update-functions.php b/plugins/woocommerce/includes/wc-update-functions.php
index dff8e3a251a..06b5fda6f14 100644
--- a/plugins/woocommerce/includes/wc-update-functions.php
+++ b/plugins/woocommerce/includes/wc-update-functions.php
@@ -40,6 +40,7 @@ use Automattic\WooCommerce\Internal\ProductDownloads\ApprovedDirectories\Synchro
use Automattic\WooCommerce\Internal\Utilities\DatabaseUtil;
use Automattic\WooCommerce\Internal\Utilities\FilesystemUtil;
use Automattic\WooCommerce\Internal\Utilities\ProductUtil;
+use Automattic\WooCommerce\Internal\VariationGallery\Package as VariationGalleryPackage;
use Automattic\WooCommerce\Utilities\StringUtil;
use Automattic\WooCommerce\Blocks\Options as BlockOptions;
use Automattic\WooCommerce\Blocks\Utils\BlockTemplateUtils;
@@ -3584,6 +3585,21 @@ function wc_update_1100_enable_point_of_sale_feature() {
update_option( 'woocommerce_feature_point_of_sale_enabled', 'yes' );
}
+/**
+ * Remove the deprecated variation gallery feature option from the database.
+ *
+ * The variation gallery feature flag is deprecated as of 11.1.0 and is now always enabled.
+ * The option is no longer needed as FeaturesUtil::feature_is_enabled('variation_gallery')
+ * returns the deprecated_value directly without reading from the database.
+ *
+ * @since 11.1.0
+ *
+ * @return void
+ */
+function wc_update_11101_remove_deprecated_variation_gallery_option(): void {
+ delete_option( VariationGalleryPackage::ENABLE_OPTION_NAME );
+}
+
/**
* Delete the cached dashboard out-of-stock product count.
*
diff --git a/plugins/woocommerce/src/Blocks/Utils/ProductGalleryUtils.php b/plugins/woocommerce/src/Blocks/Utils/ProductGalleryUtils.php
index 0c1082d767b..422cc2a8bab 100644
--- a/plugins/woocommerce/src/Blocks/Utils/ProductGalleryUtils.php
+++ b/plugins/woocommerce/src/Blocks/Utils/ProductGalleryUtils.php
@@ -2,7 +2,6 @@
namespace Automattic\WooCommerce\Blocks\Utils;
use Automattic\WooCommerce\Internal\ProductGallery\ProductMediaGallery;
-use Automattic\WooCommerce\Internal\VariationGallery\Package as VariationGalleryPackage;
/**
* Utility methods used for the Product Gallery block.
@@ -442,7 +441,7 @@ class ProductGalleryUtils {
* Decision tree (variation chosen):
* - no variation images → parent featured + parent gallery
* - own featured only → variation featured + parent gallery extras
- * - own featured + gallery (flag on) → variation images only
+ * - own featured + gallery → variation images only
* - gallery only, no own featured (potential AVI shape) → parent featured + variation gallery
*
* @param int $variation_id Variation post ID.
@@ -460,12 +459,9 @@ class ProductGalleryUtils {
$featured_id = (int) $variation->get_image_id();
$featured_valid = $featured_id && wp_attachment_is_image( $featured_id );
- $variation_gallery_ids = array();
- if ( VariationGalleryPackage::is_enabled() ) {
- $variation_gallery_ids = array_map( 'intval', $variation->get_gallery_image_ids() );
- $variation_gallery_ids = array_filter( $variation_gallery_ids, 'wp_attachment_is_image' );
- $variation_gallery_ids = array_values( $variation_gallery_ids );
- }
+ $variation_gallery_ids = array_map( 'intval', $variation->get_gallery_image_ids() );
+ $variation_gallery_ids = array_filter( $variation_gallery_ids, 'wp_attachment_is_image' );
+ $variation_gallery_ids = array_values( $variation_gallery_ids );
// No images from variation - full parent fallback.
if ( ! $featured_valid && empty( $variation_gallery_ids ) ) {
diff --git a/plugins/woocommerce/src/Internal/Features/FeaturesController.php b/plugins/woocommerce/src/Internal/Features/FeaturesController.php
index 4fdbacdbc87..d61a80d585b 100644
--- a/plugins/woocommerce/src/Internal/Features/FeaturesController.php
+++ b/plugins/woocommerce/src/Internal/Features/FeaturesController.php
@@ -541,15 +541,14 @@ class FeaturesController {
),
\Automattic\WooCommerce\Internal\VariationGallery\Package::FEATURE_ID => array(
'name' => __( 'Variation gallery', 'woocommerce' ),
- 'description' => __(
- 'Add multiple images per product variation. Once enabled, the Additional Variation Images extension will be deactivated and its data migrated.',
- 'woocommerce'
- ),
- 'option_key' => \Automattic\WooCommerce\Internal\VariationGallery\Package::ENABLE_OPTION_NAME,
- 'is_experimental' => true,
- 'enabled_by_default' => \Automattic\WooCommerce\Internal\VariationGallery\Package::is_in_canary_cohort(),
+ 'description' => __( 'Add multiple images per product variation.', 'woocommerce' ),
+ 'is_experimental' => false,
+ 'enabled_by_default' => true,
+ 'disable_ui' => true,
'skip_compatibility_checks' => true,
'default_plugin_compatibility' => FeaturePluginCompatibility::COMPATIBLE,
+ 'deprecated_since' => '11.1.0',
+ 'deprecated_value' => true,
),
'wc-visual-attribute' => array(
'name' => __( 'Color swatches for attributes', 'woocommerce' ),
diff --git a/plugins/woocommerce/src/Internal/VariationGallery/Package.php b/plugins/woocommerce/src/Internal/VariationGallery/Package.php
index 286d9fc5142..700697abbd2 100644
--- a/plugins/woocommerce/src/Internal/VariationGallery/Package.php
+++ b/plugins/woocommerce/src/Internal/VariationGallery/Package.php
@@ -39,48 +39,30 @@ 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.
+ * Highest variant bucket in the former canary cohort.
+ *
+ * @deprecated 11.1.0 The variation gallery is enabled for all users.
*/
public const CANARY_MAX_VARIANT = 6;
/**
- * Whether the current store is in the canary cohort.
+ * Whether the current store is in the former canary cohort.
*
- * @internal Removable once the feature is at 100% rollout.
+ * @deprecated 11.1.0 Use Package::is_enabled() instead.
* @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;
+ wc_deprecated_function( __METHOD__, '11.1.0', __CLASS__ . '::is_enabled' );
+ return self::is_enabled();
}
/**
- * Whether the merged variation gallery feature is enabled for the current
- * request.
- *
- * Explicit `yes`/`no` on the option wins; unset falls back to the canary
- * cohort.
+ * As of WooCommerce 11.1, the variation gallery is enabled for all users.
*
* @return bool
*/
public static function is_enabled() {
- $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();
+ return true;
}
/**
@@ -98,10 +80,6 @@ class Package {
* @internal
*/
final public static function init(): void {
- if ( ! self::is_enabled() ) {
- return;
- }
-
$container = wc_get_container();
$container->get( ClassicVariationGalleryAdmin::class )->register();
$container->get( LegacyVariationGalleryCompatibility::class )->register();
diff --git a/plugins/woocommerce/src/Internal/VariationGallery/Telemetry.php b/plugins/woocommerce/src/Internal/VariationGallery/Telemetry.php
index 940c5d656a0..7d5523c1af4 100644
--- a/plugins/woocommerce/src/Internal/VariationGallery/Telemetry.php
+++ b/plugins/woocommerce/src/Internal/VariationGallery/Telemetry.php
@@ -50,9 +50,6 @@ class Telemetry implements RegisterHooksInterface {
public static function collect_snapshot(): array {
global $wpdb;
- $option_value = get_option( Package::ENABLE_OPTION_NAME, '' );
- $variant_assignment = (int) get_option( 'woocommerce_remote_variant_assignment', 0 );
- $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,10 +102,7 @@ class Telemetry implements RegisterHooksInterface {
);
return array(
- 'feature_enabled' => Package::is_enabled() ? 'yes' : 'no',
- 'feature_option_explicit' => '' === $option_value ? 'no' : 'yes',
- 'remote_variant_assignment' => $variant_assignment,
- 'remote_variant_cohort' => $cohort,
+ 'feature_enabled' => 'yes',
'legacy_avi_plugin_active' => $legacy_plugin_active ? 'yes' : 'no',
'legacy_avi_plugin_installed' => file_exists( $legacy_plugin_file ) ? 'yes' : 'no',
'migrated_variation_count' => $migrated_variation_count,
diff --git a/plugins/woocommerce/src/Packages.php b/plugins/woocommerce/src/Packages.php
index 9952fd64b69..45d1b52c120 100644
--- a/plugins/woocommerce/src/Packages.php
+++ b/plugins/woocommerce/src/Packages.php
@@ -193,7 +193,16 @@ class Packages {
}
// Scroll through all of the active plugins and disable them if they're merged packages.
- $active_plugins = get_option( 'active_plugins', array() );
+ $active_plugins = (array) get_option( 'active_plugins', array() );
+ if ( is_multisite() ) {
+ $active_plugins = array_unique(
+ array_merge(
+ $active_plugins,
+ array_keys( (array) get_site_option( 'active_sitewide_plugins', array() ) )
+ )
+ );
+ }
+
// Deactivate the plugin if possible so that there are no conflicts.
foreach ( $active_plugins as $active_plugin_path ) {
$plugin_file = basename( plugin_basename( $active_plugin_path ), '.php' );
diff --git a/plugins/woocommerce/templates/single-product/add-to-cart/variable.php b/plugins/woocommerce/templates/single-product/add-to-cart/variable.php
index e2291b43b14..f262ac5c613 100644
--- a/plugins/woocommerce/templates/single-product/add-to-cart/variable.php
+++ b/plugins/woocommerce/templates/single-product/add-to-cart/variable.php
@@ -12,7 +12,7 @@
*
* @see https://woocommerce.com/document/template-structure/
* @package WooCommerce\Templates
- * @version 10.9.0
+ * @version 11.1.0
*/
defined( 'ABSPATH' ) || exit;
@@ -62,12 +62,8 @@ do_action( 'woocommerce_before_add_to_cart_form' ); ?>
<div class="reset_variations_alert screen-reader-text" role="alert" aria-live="polite" aria-relevant="all"></div>
<?php
// Reset snapshot for cases where a theme/plugin loads the variation form later, like quick-view modals.
- if ( \Automattic\WooCommerce\Internal\VariationGallery\Package::is_enabled() ) :
- ?>
- <script type="text/template" class="wc-product-gallery-default-template"><?php echo wc_get_product_gallery_html( $product ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></script>
- <?php
- endif;
?>
+ <script type="text/template" class="wc-product-gallery-default-template"><?php echo wc_get_product_gallery_html( $product ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></script>
<?php do_action( 'woocommerce_after_variations_table' ); ?>
<div class="single_variation_wrap">
diff --git a/plugins/woocommerce/tests/legacy/bootstrap.php b/plugins/woocommerce/tests/legacy/bootstrap.php
index 40fac14d320..faa162bfbff 100644
--- a/plugins/woocommerce/tests/legacy/bootstrap.php
+++ b/plugins/woocommerce/tests/legacy/bootstrap.php
@@ -7,6 +7,7 @@
*/
use Automattic\WooCommerce\Internal\Admin\FeaturePlugin;
+use Automattic\WooCommerce\Internal\VariationGallery\Migration as VariationGalleryMigration;
use Automattic\WooCommerce\Testing\Tools\CodeHacking\CodeHacker;
use Automattic\WooCommerce\Testing\Tools\CodeHacking\Hacks\StaticMockerHack;
use Automattic\WooCommerce\Testing\Tools\CodeHacking\Hacks\FunctionsMockerHack;
@@ -70,6 +71,9 @@ class WC_Unit_Tests_Bootstrap {
// Set up WC-Admin config.
tests_add_filter( 'woocommerce_admin_get_feature_config', array( $this, 'add_development_features' ) );
+ // Keep the shared DB update queue clean outside the variation gallery package tests.
+ tests_add_filter( 'init', array( $this, 'cancel_variation_gallery_migration_action' ), 21 );
+
// Speed things up by turning down the password hashing cost.
tests_add_filter(
'wp_hash_password_options',
@@ -307,6 +311,20 @@ class WC_Unit_Tests_Bootstrap {
echo esc_html( 'Installing WooCommerce...' . PHP_EOL );
}
+ /**
+ * Cancel the variation gallery migration scheduled during test bootstrap.
+ *
+ * The package scheduler is covered directly by its own tests. Leaving its
+ * bootstrap action pending leaks into unrelated tests of the shared DB update queue.
+ */
+ public function cancel_variation_gallery_migration_action(): void {
+ WC()->queue()->cancel_all(
+ 'woocommerce_run_update_callback',
+ array( 'update_callback' => array( VariationGalleryMigration::class, 'run' ) ),
+ 'woocommerce-db-updates'
+ );
+ }
+
/**
* Load WC-specific test cases and factories.
*
diff --git a/plugins/woocommerce/tests/php/includes/class-wc-product-variable-test.php b/plugins/woocommerce/tests/php/includes/class-wc-product-variable-test.php
index 17ea8395de8..da5e45fbd42 100644
--- a/plugins/woocommerce/tests/php/includes/class-wc-product-variable-test.php
+++ b/plugins/woocommerce/tests/php/includes/class-wc-product-variable-test.php
@@ -1,19 +1,9 @@
<?php
-use Automattic\WooCommerce\Internal\VariationGallery\Package;
-
/**
* Tests for WC_Product_Variable.
*/
class WC_Product_Variable_Test extends \WC_Unit_Test_Case {
- /**
- * Reset variation gallery feature-flag option leaked by individual tests.
- */
- public function tearDown(): void {
- delete_option( Package::ENABLE_OPTION_NAME );
- parent::tearDown();
- }
-
/**
* @testdox 'get_available_variations' returns the variations as arrays if no parameters is passed.
*/
@@ -177,8 +167,6 @@ class WC_Product_Variable_Test extends \WC_Unit_Test_Case {
* @testdox 'get_available_variations' with 'array' return includes image and gallery data for variations that have images set.
*/
public function test_get_available_variations_array_includes_image_data_when_variation_has_images(): void {
- update_option( Package::ENABLE_OPTION_NAME, 'yes' );
-
$image_id = $this->create_image_attachment( 'Variation Image', 'variation-image.jpg' );
$gallery_id = $this->create_image_attachment( 'Variation Gallery Image', 'variation-gallery.jpg' );
@@ -200,8 +188,6 @@ class WC_Product_Variable_Test extends \WC_Unit_Test_Case {
* @testdox 'get_available_variation' exposes typed variation gallery image IDs.
*/
public function test_get_available_variation_includes_gallery_image_ids() {
- update_option( Package::ENABLE_OPTION_NAME, 'yes' );
-
$product = WC_Helper_Product::create_variation_product();
$variation = wc_get_product( $product->get_children()[0] );
$image_id = wp_insert_attachment(
@@ -243,57 +229,10 @@ class WC_Product_Variable_Test extends \WC_Unit_Test_Case {
$this->assertNotEmpty( $available_variation['gallery_images_html'] );
}
- /**
- * @testdox 'get_available_variation' omits multi-image gallery data when the variation gallery feature flag is disabled.
- */
- public function test_get_available_variation_returns_single_image_shape_when_feature_flag_disabled() {
- update_option( Package::ENABLE_OPTION_NAME, 'no' );
-
- $product = WC_Helper_Product::create_variation_product();
- $variation = wc_get_product( $product->get_children()[0] );
- $image_id = wp_insert_attachment(
- array(
- 'post_title' => 'Variation Image',
- 'post_type' => 'attachment',
- 'post_mime_type' => 'image/jpeg',
- )
- );
- $image_ids = array(
- wp_insert_attachment(
- array(
- 'post_title' => 'Variation Gallery Image 1',
- 'post_type' => 'attachment',
- 'post_mime_type' => 'image/jpeg',
- )
- ),
- wp_insert_attachment(
- array(
- 'post_title' => 'Variation Gallery Image 2',
- 'post_type' => 'attachment',
- 'post_mime_type' => 'image/jpeg',
- )
- ),
- );
-
- update_post_meta( $image_id, '_wp_attached_file', 'variation-disabled.jpg' );
-
- $variation->set_image_id( $image_id );
- $variation->set_gallery_image_ids( $image_ids );
- $variation->save();
-
- $available_variation = $product->get_available_variation( $variation );
-
- $this->assertSame( array(), $available_variation['gallery_image_ids'] );
- $this->assertSame( '', $available_variation['gallery_images_html'] );
- $this->assertSame( $image_id, $available_variation['image_id'] );
- }
-
/**
* @testdox 'get_available_variation' falls back to the variation's own gallery when the variation featured image is stale.
*/
public function test_get_available_variation_falls_back_to_variation_gallery_when_featured_is_stale() {
- update_option( Package::ENABLE_OPTION_NAME, 'yes' );
-
$product = WC_Helper_Product::create_variation_product();
$variation = wc_get_product( $product->get_children()[0] );
$parent_featured_id = $this->create_image_attachment( 'Parent Featured Image', 'parent-featured.jpg' );
@@ -325,8 +264,6 @@ class WC_Product_Variable_Test extends \WC_Unit_Test_Case {
* @testdox 'get_available_variation' falls back to the parent featured image when both the variation featured image and gallery are absent.
*/
public function test_get_available_variation_falls_back_to_parent_featured_when_variation_has_no_images() {
- update_option( Package::ENABLE_OPTION_NAME, 'yes' );
-
$product = WC_Helper_Product::create_variation_product();
$variation = wc_get_product( $product->get_children()[0] );
$parent_featured_id = $this->create_image_attachment( 'Parent Featured Image', 'parent-featured.jpg' );
diff --git a/plugins/woocommerce/tests/php/includes/wc-product-functions-test.php b/plugins/woocommerce/tests/php/includes/wc-product-functions-test.php
index ea2930da408..d475f8f5d5a 100644
--- a/plugins/woocommerce/tests/php/includes/wc-product-functions-test.php
+++ b/plugins/woocommerce/tests/php/includes/wc-product-functions-test.php
@@ -30,12 +30,9 @@ class WC_Product_Functions_Tests extends \WC_Unit_Test_Case {
private $reviews_setting_changed = false;
/**
- * Reset the variation gallery feature-flag option after each test so
- * individual cases that flip it on don't leak global state.
+ * Restore settings modified by tests.
*/
public function tearDown(): void {
- delete_option( \Automattic\WooCommerce\Internal\VariationGallery\Package::ENABLE_OPTION_NAME );
-
if ( $this->reviews_setting_changed ) {
delete_option( 'woocommerce_product_lookup_table_is_generating' );
as_unschedule_all_actions( '', array(), 'wc_update_product_lookup_tables' );
@@ -1543,11 +1540,9 @@ class WC_Product_Functions_Tests extends \WC_Unit_Test_Case {
}
/**
- * @testdox Variable add-to-cart attaches a pristine gallery snapshot to the variation script when the feature is on.
+ * @testdox Variable add-to-cart attaches a pristine gallery snapshot to the variation script.
*/
public function test_woocommerce_variable_add_to_cart_attaches_gallery_snapshot() {
- update_option( \Automattic\WooCommerce\Internal\VariationGallery\Package::ENABLE_OPTION_NAME, 'yes' );
-
$inline_js = $this->capture_variable_add_to_cart_inline_js();
$this->assertStringContainsString( 'wc_variation_gallery_defaults', $inline_js );
@@ -1560,21 +1555,6 @@ class WC_Product_Functions_Tests extends \WC_Unit_Test_Case {
$this->assertStringContainsString( 'woocommerce-product-gallery', $decoded_snapshot );
}
- /**
- * @testdox Variable add-to-cart skips the gallery snapshot when the feature is off.
- */
- public function test_woocommerce_variable_add_to_cart_skips_gallery_snapshot_when_feature_off() {
- // Set the option to 'no' explicitly rather than deleting it: an empty option makes
- // Package::is_enabled() fall through to the canary cohort, which reads a separate
- // option (woocommerce_remote_variant_assignment) that other tests in the same worker
- // may have left set, non-deterministically re-enabling the feature. 'no' short-circuits.
- update_option( \Automattic\WooCommerce\Internal\VariationGallery\Package::ENABLE_OPTION_NAME, 'no' );
-
- $inline_js = $this->capture_variable_add_to_cart_inline_js();
-
- $this->assertStringNotContainsString( 'wc_variation_gallery_defaults', $inline_js );
- }
-
/**
* Render the variable add-to-cart template and return the inline JS
* attached to the variation script.
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 85fada1a252..70455142608 100644
--- a/plugins/woocommerce/tests/php/includes/wc-update-functions-test.php
+++ b/plugins/woocommerce/tests/php/includes/wc-update-functions-test.php
@@ -7,6 +7,7 @@
use Automattic\WooCommerce\Blocks\Options as BlockOptions;
use Automattic\WooCommerce\Blocks\Utils\BlockTemplateUtils;
+use Automattic\WooCommerce\Internal\VariationGallery\Package as VariationGalleryPackage;
/**
* Class WC_Core_Functions_Test
@@ -339,6 +340,29 @@ class WC_Update_Functions_Test extends \WC_Unit_Test_Case {
$this->assertSame( 'yes', get_option( 'woocommerce_feature_point_of_sale_enabled' ) );
}
+ /**
+ * @testdox Migration registers and 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 ) );
+
+ update_option( VariationGalleryPackage::ENABLE_OPTION_NAME, 'no' );
+ wc_update_11101_remove_deprecated_variation_gallery_option();
+ $this->assertFalse( get_option( VariationGalleryPackage::ENABLE_OPTION_NAME ) );
+
+ update_option( VariationGalleryPackage::ENABLE_OPTION_NAME, 'yes' );
+ wc_update_11101_remove_deprecated_variation_gallery_option();
+ $this->assertFalse( get_option( VariationGalleryPackage::ENABLE_OPTION_NAME ) );
+ }
+
/**
* @testdox Migration registers and deletes the cached dashboard out-of-stock count.
*/
diff --git a/plugins/woocommerce/tests/php/src/Blocks/Utils/ProductGalleryUtilsTest.php b/plugins/woocommerce/tests/php/src/Blocks/Utils/ProductGalleryUtilsTest.php
index b8e4a58c756..130345c8603 100644
--- a/plugins/woocommerce/tests/php/src/Blocks/Utils/ProductGalleryUtilsTest.php
+++ b/plugins/woocommerce/tests/php/src/Blocks/Utils/ProductGalleryUtilsTest.php
@@ -16,7 +16,6 @@ class ProductGalleryUtilsTest extends \WP_UnitTestCase {
*/
public function tearDown(): void {
delete_option( ProductMediaGallery::ENABLE_OPTION_NAME );
- delete_option( \Automattic\WooCommerce\Internal\VariationGallery\Package::ENABLE_OPTION_NAME );
parent::tearDown();
}
@@ -24,8 +23,6 @@ class ProductGalleryUtilsTest extends \WP_UnitTestCase {
* Test get_product_gallery_image_data method.
*/
public function test_get_product_gallery_image_data() {
- update_option( \Automattic\WooCommerce\Internal\VariationGallery\Package::ENABLE_OPTION_NAME, 'yes' );
-
// Create the variable product.
$variable_product = \WC_Helper_Product::create_variation_product();
@@ -140,59 +137,10 @@ class ProductGalleryUtilsTest extends \WP_UnitTestCase {
}
}
- /**
- * Test that get_product_variation_gallery_data returns the single-image
- * shape when the variation gallery feature flag is disabled, even when
- * the variation has multiple gallery images saved.
- */
- public function test_get_product_variation_gallery_data_returns_single_image_when_feature_flag_disabled() {
- update_option( \Automattic\WooCommerce\Internal\VariationGallery\Package::ENABLE_OPTION_NAME, 'no' );
-
- $variable_product = \WC_Helper_Product::create_variation_product();
-
- $variation_image_id = wp_insert_attachment(
- array(
- 'post_title' => 'Variation Featured Image',
- 'post_type' => 'attachment',
- 'post_mime_type' => 'image/jpeg',
- )
- );
- update_post_meta( $variation_image_id, '_wp_attached_file', 'variation-featured.jpg' );
-
- $variation_gallery_image_ids = array(
- wp_insert_attachment(
- array(
- 'post_title' => 'Variation Gallery Image 1',
- 'post_type' => 'attachment',
- 'post_mime_type' => 'image/jpeg',
- )
- ),
- wp_insert_attachment(
- array(
- 'post_title' => 'Variation Gallery Image 2',
- 'post_type' => 'attachment',
- 'post_mime_type' => 'image/jpeg',
- )
- ),
- );
-
- $variation = wc_get_product( $variable_product->get_children()[0] );
- $variation->set_image_id( $variation_image_id );
- $variation->set_gallery_image_ids( $variation_gallery_image_ids );
- $variation->save();
-
- $variation_entry = ProductGalleryUtils::get_product_variation_gallery_data( $variable_product )[ $variation->get_id() ];
-
- $this->assertSame( $variation_image_id, $variation_entry['image_id'] );
- $this->assertSame( array( $variation_image_id ), $variation_entry['image_ids'] );
- }
-
/**
* Test that variation gallery data falls back to the variation's own gallery when the variation featured image is stale.
*/
public function test_get_product_variation_gallery_data_falls_back_to_variation_gallery_when_featured_is_stale() {
- update_option( \Automattic\WooCommerce\Internal\VariationGallery\Package::ENABLE_OPTION_NAME, 'yes' );
-
$variable_product = \WC_Helper_Product::create_variation_product();
$parent_featured_id = $this->create_image_attachment( 'Parent Featured Image', 'parent-featured.jpg' );
$stale_featured_id = $this->create_image_attachment( 'Stale Variation Image', 'stale-featured.jpg' );
@@ -224,7 +172,7 @@ class ProductGalleryUtilsTest extends \WP_UnitTestCase {
/**
* Variation has only its own featured image (no gallery) → the
* variation featured replaces the parent's hero, parent gallery extras
- * stay. Applies whether the feature flag is on or off.
+ * stay.
*/
public function test_get_product_variation_gallery_data_case_3_single_image_appends_parent_gallery_extras() {
$parent_featured_id = $this->create_image_attachment( 'Parent Featured', 'parent-featured.jpg' );
@@ -246,8 +194,8 @@ class ProductGalleryUtilsTest extends \WP_UnitTestCase {
}
/**
- * Variation has its own featured plus gallery images (feature flag
- * on) → the variation's images replace the parent's entirely.
+ * Variation has its own featured plus gallery images, so the variation's
+ * images replace the parent's entirely.
*/
public function test_get_product_variation_gallery_data_case_4_multiple_images_replaces_parent_set() {
$parent_featured_id = $this->create_image_attachment( 'Parent Featured', 'parent-featured.jpg' );
@@ -315,31 +263,6 @@ class ProductGalleryUtilsTest extends \WP_UnitTestCase {
);
}
- /**
- * Feature flag off: Variation gallery is treated as empty even if rows exist in postmeta,
- * so the single-image rule applies (variation featured + parent gallery extras).
- */
- public function test_get_product_variation_gallery_data_case_3_applies_with_feature_flag_off() {
- $parent_featured_id = $this->create_image_attachment( 'Parent Featured', 'parent-featured.jpg' );
- $parent_gallery_extra = $this->create_image_attachment( 'Parent Gallery Extra', 'parent-gallery-extra.jpg' );
- $variation_featured_id = $this->create_image_attachment( 'Variation Featured', 'variation-featured.jpg' );
- $variation_gallery_id_a = $this->create_image_attachment( 'Variation Gallery A (ignored)', 'variation-gallery-a.jpg' );
-
- $entry = $this->create_variation_gallery_entry(
- $parent_featured_id,
- array( $parent_gallery_extra ),
- $variation_featured_id,
- array( $variation_gallery_id_a ),
- 'no'
- );
-
- $this->assertSame( $variation_featured_id, $entry['image_id'] );
- $this->assertSame(
- array( $variation_featured_id, $parent_gallery_extra ),
- $entry['image_ids']
- );
- }
-
/**
* The variation featured is also present in the parent gallery — output
* must dedup so the image doesn't render twice in a row.
@@ -365,22 +288,18 @@ class ProductGalleryUtilsTest extends \WP_UnitTestCase {
/**
* Create a variation gallery fixture and return the selected variation entry.
*
- * @param int $parent_featured_id Parent product featured image ID.
- * @param int[] $parent_gallery_ids Parent product gallery image IDs.
- * @param int $variation_featured_id Variation featured image ID.
- * @param int[] $variation_gallery_ids Variation gallery image IDs.
- * @param string $feature_flag Variation gallery feature flag value.
+ * @param int $parent_featured_id Parent product featured image ID.
+ * @param int[] $parent_gallery_ids Parent product gallery image IDs.
+ * @param int $variation_featured_id Variation featured image ID.
+ * @param int[] $variation_gallery_ids Variation gallery image IDs.
* @return array<string, mixed>
*/
private function create_variation_gallery_entry(
int $parent_featured_id,
array $parent_gallery_ids = array(),
int $variation_featured_id = 0,
- array $variation_gallery_ids = array(),
- string $feature_flag = 'yes'
+ array $variation_gallery_ids = array()
): array {
- update_option( \Automattic\WooCommerce\Internal\VariationGallery\Package::ENABLE_OPTION_NAME, $feature_flag );
-
$variable_product = \WC_Helper_Product::create_variation_product();
$variable_product->set_image_id( $parent_featured_id );
$variable_product->set_gallery_image_ids( $parent_gallery_ids );
diff --git a/plugins/woocommerce/tests/php/src/Internal/VariationGallery/PackageTest.php b/plugins/woocommerce/tests/php/src/Internal/VariationGallery/PackageTest.php
index 3b2286d15b0..2e07f10b32d 100644
--- a/plugins/woocommerce/tests/php/src/Internal/VariationGallery/PackageTest.php
+++ b/plugins/woocommerce/tests/php/src/Internal/VariationGallery/PackageTest.php
@@ -11,11 +11,29 @@ use Automattic\WooCommerce\Internal\VariationGallery\Package;
*/
class PackageTest extends \WC_Unit_Test_Case {
+ /**
+ * Reset migration-related state before each test.
+ */
+ public function setUp(): void {
+ parent::setUp();
+
+ $this->reset_migration_state();
+ }
+
/**
* Reset migration-related state between tests so action queue and
* completion option don't leak across cases.
*/
public function tearDown(): void {
+ $this->reset_migration_state();
+
+ parent::tearDown();
+ }
+
+ /**
+ * Reset migration-related options and scheduled actions.
+ */
+ private function reset_migration_state(): void {
WC()->queue()->cancel_all(
'woocommerce_run_update_callback',
$this->get_migration_action_args(),
@@ -28,84 +46,24 @@ class PackageTest extends \WC_Unit_Test_Case {
);
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.
+ * @testdox is_enabled returns true now that the variation gallery is fully rolled out.
*/
- 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 );
-
+ public function test_is_enabled_returns_true(): void {
$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.
+ * @testdox is_enabled returns true for a former explicit opt-out.
*/
- public function test_is_enabled_returns_false_when_option_explicitly_no(): void {
+ public function test_is_enabled_returns_true_for_former_explicit_opt_out(): 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.
*/