Commit 67909e8f6b for woocommerce

commit 67909e8f6b6165a57cbb5bc68f24d26995568475
Author: malinajirka <malinajirka@gmail.com>
Date:   Thu Jan 15 20:52:56 2026 +0100

    Update variation date_modified when toggling POS visibility (#62824)

    * Update variation date_modified when toggling POS visibility

    When toggling POS visibility on a variable product, variations' date_modified was not being updated because only wp_set_object_terms() was called without saving the variation.

    Now each variation is loaded and saved when visibility changes, ensuring date_modified is updated. Also adds an early return optimization to skip all updates when visibility state hasn't changed.

    * Add changefile(s) from automation for the following project(s): woocommerce

    * Update plugins/woocommerce/tests/php/src/Internal/ProductFeed/Integrations/POSCatalog/POSProductVisibilitySyncTest.php

    Co-authored-by: Radoslav Georgiev <rageorgiev@gmail.com>

    * Update plugins/woocommerce/tests/php/src/Internal/ProductFeed/Integrations/POSCatalog/POSProductVisibilitySyncTest.php

    Co-authored-by: Radoslav Georgiev <rageorgiev@gmail.com>

    * Fix WC_Product class reference in test mock

    Use fully qualified class name (\WC_Product) to reference the global WooCommerce product class instead of looking in the test's namespace.

    ---------

    Co-authored-by: woocommercebot <woocommercebot@users.noreply.github.com>
    Co-authored-by: Radoslav Georgiev <rageorgiev@gmail.com>

diff --git a/plugins/woocommerce/changelog/62824-wooplug-6145-addingremoving-pos-hidden-taxonomy-on-variations-doesnt b/plugins/woocommerce/changelog/62824-wooplug-6145-addingremoving-pos-hidden-taxonomy-on-variations-doesnt
new file mode 100644
index 0000000000..842c72f9b1
--- /dev/null
+++ b/plugins/woocommerce/changelog/62824-wooplug-6145-addingremoving-pos-hidden-taxonomy-on-variations-doesnt
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Fix variation date_modified not updating when toggling POS visibility on variable products.
\ No newline at end of file
diff --git a/plugins/woocommerce/src/Internal/ProductFeed/Integrations/POSCatalog/POSProductVisibilitySync.php b/plugins/woocommerce/src/Internal/ProductFeed/Integrations/POSCatalog/POSProductVisibilitySync.php
index 4781f06c9c..d88e0a85d5 100644
--- a/plugins/woocommerce/src/Internal/ProductFeed/Integrations/POSCatalog/POSProductVisibilitySync.php
+++ b/plugins/woocommerce/src/Internal/ProductFeed/Integrations/POSCatalog/POSProductVisibilitySync.php
@@ -49,6 +49,12 @@ class POSProductVisibilitySync {
 	 * @return void
 	 */
 	public function set_product_pos_visibility( int $product_id, bool $visible_in_pos ): void {
+		$is_currently_visible = ! has_term( 'pos-hidden', 'pos_product_visibility', $product_id );
+
+		if ( $is_currently_visible === $visible_in_pos ) {
+			return; // No change detected.
+		}
+
 		if ( $visible_in_pos ) {
 			wp_remove_object_terms( $product_id, 'pos-hidden', 'pos_product_visibility' );
 		} else {
@@ -78,6 +84,12 @@ class POSProductVisibilitySync {
 			} else {
 				wp_set_object_terms( $variation_id, 'pos-hidden', 'pos_product_visibility' );
 			}
+
+			// Save variation to update date_modified.
+			$variation = wc_get_product( $variation_id );
+			if ( $variation ) {
+				$variation->save();
+			}
 		}
 	}

diff --git a/plugins/woocommerce/tests/php/src/Internal/ProductFeed/Integrations/POSCatalog/POSProductVisibilitySyncTest.php b/plugins/woocommerce/tests/php/src/Internal/ProductFeed/Integrations/POSCatalog/POSProductVisibilitySyncTest.php
index 312010775c..06b390d4e3 100644
--- a/plugins/woocommerce/tests/php/src/Internal/ProductFeed/Integrations/POSCatalog/POSProductVisibilitySyncTest.php
+++ b/plugins/woocommerce/tests/php/src/Internal/ProductFeed/Integrations/POSCatalog/POSProductVisibilitySyncTest.php
@@ -155,4 +155,51 @@ class POSProductVisibilitySyncTest extends \WC_Unit_Test_Case {
 		// No exception should be thrown - test passes if we reach this point.
 		$this->assertTrue( true );
 	}
+
+	/**
+	 * Test that variations are saved when POS visibility changes.
+	 */
+	public function test_variations_saved_when_visibility_changes(): void {
+		$product       = WC_Helper_Product::create_variation_product();
+		$variation_ids = $product->get_children();
+
+		// Track which variations have save() called.
+		$saved_variation_ids = array();
+		$callback            = function ( $variation_id ) use ( &$saved_variation_ids ) {
+			$saved_variation_ids[] = $variation_id;
+		};
+		add_action( 'woocommerce_update_product_variation', $callback );
+
+		// Change visibility to hidden.
+		$this->sut->set_product_pos_visibility( $product->get_id(), false );
+
+		remove_action( 'woocommerce_update_product_variation', $callback );
+
+		// Verify save() was called for all variations.
+		$this->assertEquals(
+			$variation_ids,
+			$saved_variation_ids,
+			'save() should be called for each variation'
+		);
+	}
+
+	/**
+	 * Test that no updates occur when visibility state hasn't changed.
+	 */
+	public function test_no_updates_when_visibility_unchanged(): void {
+		$product = WC_Helper_Product::create_variation_product();
+
+		// Set product as hidden first.
+		$this->sut->set_product_pos_visibility( $product->get_id(), false );
+
+		// Track if any variations have save() called.
+		// Make sure that `save` is never called.
+		$mock_callback = $this->createMock( \WC_Product::class );
+		$mock_callback->expects( $this->never() )->method( 'save' );
+
+		// Try to set hidden again (no change).
+		add_action( 'woocommerce_update_product_variation', array( $mock_callback, 'save' ) );
+		$this->sut->set_product_pos_visibility( $product->get_id(), false );
+		remove_action( 'woocommerce_update_product_variation', array( $mock_callback, 'save' ) );
+	}
 }