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 );
+	} );
+} );