Commit 75edcc0d720 for woocommerce
commit 75edcc0d720b19d08ddd1c67496228bfbd3ff400
Author: Lucio Giannotta <lucio.giannotta@a8c.com>
Date: Mon Nov 9 11:17:19 2026 -0500
Avoid rebuilding unchanged variation galleries (#70730)
diff --git a/plugins/woocommerce/changelog/fix-reuse-unchanged-variation-gallery b/plugins/woocommerce/changelog/fix-reuse-unchanged-variation-gallery
new file mode 100644
index 00000000000..610cc503bc2
--- /dev/null
+++ b/plugins/woocommerce/changelog/fix-reuse-unchanged-variation-gallery
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Keep the selected image when switching between variations that share the same gallery.
diff --git a/plugins/woocommerce/client/legacy/changelog/fix-reuse-unchanged-variation-gallery b/plugins/woocommerce/client/legacy/changelog/fix-reuse-unchanged-variation-gallery
new file mode 100644
index 00000000000..610cc503bc2
--- /dev/null
+++ b/plugins/woocommerce/client/legacy/changelog/fix-reuse-unchanged-variation-gallery
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Keep the selected image when switching between variations that share the same gallery.
diff --git a/plugins/woocommerce/client/legacy/js/frontend/add-to-cart-variation.js b/plugins/woocommerce/client/legacy/js/frontend/add-to-cart-variation.js
index b51d8d35450..2d951fee296 100644
--- a/plugins/woocommerce/client/legacy/js/frontend/add-to-cart-variation.js
+++ b/plugins/woocommerce/client/legacy/js/frontend/add-to-cart-variation.js
@@ -905,17 +905,30 @@
};
/**
- * Replace the current classic product gallery markup and reinitialize gallery behaviors.
+ * Replace the classic product gallery unless the same variation gallery is already displayed.
*/
$.fn.wc_variations_gallery_replace = function ( gallery_html, variation ) {
var $form = $( this ),
$product = $form.closest( '.product' ),
$current_gallery = $product.wc_find_gallery_root(),
- $parsed_gallery = $( $.parseHTML( $.trim( gallery_html ) ) ),
- $new_gallery = $parsed_gallery.wc_find_gallery_root(),
+ $new_gallery,
current_image_id =
variation && variation.image_id ? variation.image_id : '';
+ gallery_html = $.trim( gallery_html );
+
+ // Compare the source markup because gallery initialization changes the DOM.
+ if (
+ variation &&
+ $form.wc_variations_gallery_is_active() &&
+ $current_gallery.data( 'wc_variation_gallery_html' ) === gallery_html
+ ) {
+ $form.attr( 'current-image', current_image_id );
+ return true;
+ }
+
+ $new_gallery = $( $.parseHTML( gallery_html ) ).wc_find_gallery_root();
+
if ( ! $current_gallery.length || ! $new_gallery.length ) {
return false;
}
@@ -957,6 +970,7 @@
$new_gallery.css( 'opacity', 1 );
}
+ $new_gallery.data( 'wc_variation_gallery_html', gallery_html );
$form.attr( 'current-image', current_image_id );
$form.attr( 'data-product_gallery_active', 'yes' );
diff --git a/plugins/woocommerce/client/legacy/js/frontend/test/add-to-cart-variation.js b/plugins/woocommerce/client/legacy/js/frontend/test/add-to-cart-variation.js
new file mode 100644
index 00000000000..0d4469cddcf
--- /dev/null
+++ b/plugins/woocommerce/client/legacy/js/frontend/test/add-to-cart-variation.js
@@ -0,0 +1,152 @@
+/**
+ * @jest-environment jest-fixed-jsdom
+ */
+const $ = require( 'jquery' );
+
+const galleryHtml = ( secondImage = 'second.jpg' ) => `
+ <div class="woocommerce-product-gallery images">
+ <figure class="woocommerce-product-gallery__wrapper">
+ <div class="woocommerce-product-gallery__image">
+ <a href="first.jpg"><img class="wp-post-image" src="first.jpg"></a>
+ </div>
+ <div class="woocommerce-product-gallery__image"><img src="${ secondImage }"></div>
+ </figure>
+ </div>`;
+
+describe( 'Classic variation gallery updates', () => {
+ let $form;
+ let beforeDestroy;
+ let afterInit;
+
+ beforeAll( () => {
+ window.jQuery = $;
+ window.wc_single_product_params = {};
+ require( '../add-to-cart-variation' );
+ } );
+
+ beforeEach( () => {
+ document.body.innerHTML = `
+ <div class="product">
+ ${ galleryHtml() }
+ <form data-product_id="1"></form>
+ </div>`;
+ $form = $( 'form' );
+ window.wc_variation_gallery_defaults = { 1: galleryHtml() };
+ $.fn.wc_product_gallery = jest.fn( function () {
+ return this.data( 'testGalleryState', { slide: 0 } );
+ } );
+ beforeDestroy = jest.fn();
+ afterInit = jest.fn();
+ $( document ).on(
+ 'wc-product-gallery-before-destroy.gallery-test',
+ beforeDestroy
+ );
+ $( document ).on(
+ 'wc-product-gallery-after-init.gallery-test',
+ afterInit
+ );
+ } );
+
+ afterEach( () => {
+ $( document ).off( '.gallery-test' );
+ jest.restoreAllMocks();
+ } );
+
+ afterAll( () => {
+ delete window.wc_single_product_params;
+ delete window.wc_variation_gallery_defaults;
+ delete $.fn.wc_product_gallery;
+ } );
+
+ test( 'keeps the current gallery and slide when variations share its markup', () => {
+ $form.wc_variations_image_update( {
+ image_id: 1,
+ gallery_images_html: galleryHtml(),
+ } );
+ const $gallery = $( '.woocommerce-product-gallery' );
+ $gallery.data( 'testGalleryState' ).slide = 1;
+ $gallery.append( '<span class="extension-content"></span>' );
+
+ $form.wc_variations_image_update( {
+ image_id: 1,
+ gallery_images_html: galleryHtml(),
+ } );
+
+ expect( $( '.woocommerce-product-gallery' )[ 0 ] ).toBe( $gallery[ 0 ] );
+ expect( $gallery.data( 'testGalleryState' ).slide ).toBe( 1 );
+ expect( $gallery.find( '.extension-content' ) ).toHaveLength( 1 );
+ expect( $.fn.wc_product_gallery ).toHaveBeenCalledTimes( 1 );
+ expect( beforeDestroy ).toHaveBeenCalledTimes( 1 );
+ expect( afterInit ).toHaveBeenCalledTimes( 1 );
+ } );
+
+ test( 'replaces changed gallery markup even when the featured image is unchanged', () => {
+ $form.wc_variations_gallery_replace( galleryHtml(), { image_id: 1 } );
+ const gallery = $( '.woocommerce-product-gallery' )[ 0 ];
+
+ $form.wc_variations_gallery_replace( galleryHtml( 'different.jpg' ), {
+ image_id: 1,
+ } );
+
+ expect( $( '.woocommerce-product-gallery' )[ 0 ] ).not.toBe( gallery );
+ expect( $( '.woocommerce-product-gallery img' ).last().attr( 'src' ) ).toBe(
+ 'different.jpg'
+ );
+ expect( beforeDestroy ).toHaveBeenCalledTimes( 2 );
+ expect( afterInit ).toHaveBeenCalledTimes( 2 );
+ } );
+
+ test( 'updates the current image when equivalent gallery markup is reused', () => {
+ $form.wc_variations_gallery_replace( galleryHtml(), { image_id: 1 } );
+ const gallery = $( '.woocommerce-product-gallery' )[ 0 ];
+
+ expect(
+ $form.wc_variations_gallery_replace( galleryHtml(), { image_id: 2 } )
+ ).toBe( true );
+
+ expect( $( '.woocommerce-product-gallery' )[ 0 ] ).toBe( gallery );
+ expect( $form.attr( 'current-image' ) ).toBe( '2' );
+ expect( $form.wc_variations_gallery_is_active() ).toBe( true );
+ } );
+
+ test( 'clears the selection by restoring the default gallery even when its markup matches', () => {
+ $form.wc_variations_gallery_replace( galleryHtml(), { image_id: 1 } );
+ const $gallery = $( '.woocommerce-product-gallery' );
+ $gallery.data( 'testGalleryState' ).slide = 1;
+
+ $form.wc_variations_image_update( false );
+
+ expect( $( '.woocommerce-product-gallery' )[ 0 ] ).not.toBe( $gallery[ 0 ] );
+ expect( $( '.woocommerce-product-gallery' ).data( 'testGalleryState' ).slide ).toBe( 0 );
+ expect( $form.attr( 'current-image' ) ).toBe( '' );
+ expect( $form.wc_variations_gallery_is_active() ).toBe( false );
+ } );
+
+ test( 'restores gallery images after a variation changes only the featured image', () => {
+ $form.wc_variations_gallery_replace( galleryHtml(), { image_id: 1 } );
+ $form.wc_variations_image_update( {
+ image_id: 3,
+ image: { src: 'featured-only.jpg', full_src: 'featured-only.jpg' },
+ } );
+ expect( $( '.wp-post-image' ).attr( 'src' ) ).toBe( 'featured-only.jpg' );
+
+ $form.wc_variations_image_update( {
+ image_id: 1,
+ gallery_images_html: galleryHtml(),
+ } );
+
+ expect( $( '.wp-post-image' ).attr( 'src' ) ).toBe( 'first.jpg' );
+ expect( $form.wc_variations_gallery_is_active() ).toBe( true );
+ } );
+
+ test( 'initializes an externally replaced gallery instead of reusing stale markup', () => {
+ $form.wc_variations_gallery_replace( galleryHtml(), { image_id: 1 } );
+ $( '.woocommerce-product-gallery' ).replaceWith( galleryHtml() );
+ const externalGallery = $( '.woocommerce-product-gallery' )[ 0 ];
+
+ $form.wc_variations_gallery_replace( galleryHtml(), { image_id: 1 } );
+
+ expect( $( '.woocommerce-product-gallery' )[ 0 ] ).not.toBe( externalGallery );
+ expect( $.fn.wc_product_gallery ).toHaveBeenCalledTimes( 2 );
+ } );
+} );