Commit d957bf7a6fa for woocommerce

commit d957bf7a6fa6202677f31ff59e93d55f267691fc
Author: Tung Du <dinhtungdu@gmail.com>
Date:   Wed May 20 16:35:22 2026 +0700

    Move wc-visual attribute to WC feature toggle (#65169)

    * Update wc-visual attribute feature toggle

    * Add changelog for wc-visual feature toggle

    * Hide wc-visual feature toggle for classic themes

diff --git a/plugins/woocommerce/changelog/update-wc-visual-attribute-feature-toggle b/plugins/woocommerce/changelog/update-wc-visual-attribute-feature-toggle
new file mode 100644
index 00000000000..fb49657a31e
--- /dev/null
+++ b/plugins/woocommerce/changelog/update-wc-visual-attribute-feature-toggle
@@ -0,0 +1,4 @@
+Significance: patch
+Type: tweak
+
+Expose the wc-visual attribute type through WooCommerce feature settings instead of the wc-admin beta feature list.
diff --git a/plugins/woocommerce/client/admin/config/core.json b/plugins/woocommerce/client/admin/config/core.json
index a585520efc3..e23a9cd8e42 100644
--- a/plugins/woocommerce/client/admin/config/core.json
+++ b/plugins/woocommerce/client/admin/config/core.json
@@ -39,7 +39,6 @@
 		"woo-mobile-welcome": true,
 		"wc-pay-promotion": true,
 		"wc-pay-welcome-page": true,
-		"wc-visual-attribute": false,
 		"async-product-editor-category-field": false,
 		"launch-your-store": true,
 		"product-editor-template-system": false,
diff --git a/plugins/woocommerce/client/admin/config/development.json b/plugins/woocommerce/client/admin/config/development.json
index 29de91b1d7f..309d026dfd8 100644
--- a/plugins/woocommerce/client/admin/config/development.json
+++ b/plugins/woocommerce/client/admin/config/development.json
@@ -39,7 +39,6 @@
 		"woo-mobile-welcome": true,
 		"wc-pay-promotion": true,
 		"wc-pay-welcome-page": true,
-		"wc-visual-attribute": true,
 		"async-product-editor-category-field": true,
 		"launch-your-store": true,
 		"product-editor-template-system": false,
diff --git a/plugins/woocommerce/includes/wc-attribute-functions.php b/plugins/woocommerce/includes/wc-attribute-functions.php
index c91f9ca9fa6..2197630c3fa 100644
--- a/plugins/woocommerce/includes/wc-attribute-functions.php
+++ b/plugins/woocommerce/includes/wc-attribute-functions.php
@@ -7,6 +7,7 @@
  */

 use Automattic\WooCommerce\Enums\ProductType;
+use Automattic\WooCommerce\Utilities\FeaturesUtil;

 defined( 'ABSPATH' ) || exit;

@@ -259,7 +260,7 @@ function wc_get_attribute_types() {

 	$allow_visual_attribute_type =
 		wp_is_block_theme() &&
-		\Automattic\WooCommerce\Admin\Features\Features::is_enabled( 'wc-visual-attribute' );
+		FeaturesUtil::feature_is_enabled( 'wc-visual-attribute' );

 	// If the store already has some visual attributes, let's allow them even
 	// if the current theme is not a block theme.
diff --git a/plugins/woocommerce/src/Internal/Features/FeaturesController.php b/plugins/woocommerce/src/Internal/Features/FeaturesController.php
index 1ddbc738ab6..1cc46589994 100644
--- a/plugins/woocommerce/src/Internal/Features/FeaturesController.php
+++ b/plugins/woocommerce/src/Internal/Features/FeaturesController.php
@@ -524,6 +524,19 @@ class FeaturesController {
 				'skip_compatibility_checks'    => true,
 				'default_plugin_compatibility' => FeaturePluginCompatibility::COMPATIBLE,
 			),
+			'wc-visual-attribute'                => array(
+				'name'                         => __( 'Color swatches for attributes', 'woocommerce' ),
+				'description'                  => __(
+					'Add color swatches to product attribute values.',
+					'woocommerce'
+				),
+				'option_key'                   => 'woocommerce_feature_wc_visual_attribute_enabled',
+				'is_experimental'              => true,
+				'enabled_by_default'           => false,
+				'disable_ui'                   => false,
+				'skip_compatibility_checks'    => true,
+				'default_plugin_compatibility' => FeaturePluginCompatibility::COMPATIBLE,
+			),
 			'point_of_sale'                      => array(
 				'name'                         => __( 'Point of Sale', 'woocommerce' ),
 				'description'                  => __(
@@ -801,6 +814,10 @@ class FeaturesController {
 			$features['product_block_editor']['disable_ui'] = true;
 		}

+		if ( isset( $features['wc-visual-attribute'] ) && ! wp_is_block_theme() ) {
+			$features['wc-visual-attribute']['disable_ui'] = true;
+		}
+
 		return $features;
 	}

diff --git a/plugins/woocommerce/tests/php/includes/class-wc-ajax-test.php b/plugins/woocommerce/tests/php/includes/class-wc-ajax-test.php
index 9240b998ca2..ddb16c9c167 100644
--- a/plugins/woocommerce/tests/php/includes/class-wc-ajax-test.php
+++ b/plugins/woocommerce/tests/php/includes/class-wc-ajax-test.php
@@ -145,15 +145,13 @@ class WC_AJAX_Test extends \WP_Ajax_UnitTestCase {
 		$text_term_id        = 0;
 		$suffix              = (string) wp_rand( 1000, 9999 );

-		$enable_visual_attribute_feature = function ( $features ) {
-			$features[] = 'wc-visual-attribute';
-			return array_unique( $features );
-		};
-
-		add_filter( 'woocommerce_admin_features', $enable_visual_attribute_feature );
-
 		try {
 			switch_theme( 'twentytwentyfour' );
+			delete_option( 'woocommerce_feature_wc_visual_attribute_enabled' );
+			$this->assertTrue(
+				wc_get_container()->get( \Automattic\WooCommerce\Internal\Features\FeaturesController::class )->change_feature_enable( 'wc-visual-attribute', true ),
+				'The visual attribute feature should be toggled on.'
+			);

 			$visual_attribute_id = wc_create_attribute(
 				array(
@@ -224,7 +222,7 @@ class WC_AJAX_Test extends \WP_Ajax_UnitTestCase {
 				unset( $wc_product_attributes[ $taxonomy ] );
 			}

-			remove_filter( 'woocommerce_admin_features', $enable_visual_attribute_feature );
+			delete_option( 'woocommerce_feature_wc_visual_attribute_enabled' );
 			switch_theme( $original_theme );
 		}//end try
 	}
diff --git a/plugins/woocommerce/tests/php/includes/wc-attribute-functions-test.php b/plugins/woocommerce/tests/php/includes/wc-attribute-functions-test.php
index fefa46bbcb4..aaa3df29c91 100644
--- a/plugins/woocommerce/tests/php/includes/wc-attribute-functions-test.php
+++ b/plugins/woocommerce/tests/php/includes/wc-attribute-functions-test.php
@@ -7,6 +7,7 @@

 declare( strict_types=1 );

+use Automattic\WooCommerce\Utilities\FeaturesUtil;
 use PHPUnit\Framework\MockObject\Matcher\InvokedRecorder;

 /**
@@ -226,15 +227,15 @@ class WC_Attribute_Functions_Test extends \WC_Unit_Test_Case {
 		$original_theme = wp_get_theme()->get_stylesheet();
 		$attribute_id   = null;

-		$enable_visual_attribute_feature = function ( $features ) {
-			$features[] = 'wc-visual-attribute';
-			return array_unique( $features );
-		};
-
-		add_filter( 'woocommerce_admin_features', $enable_visual_attribute_feature );
 		try {
 			switch_theme( 'twentytwentyfour' );

+			delete_option( 'woocommerce_feature_wc_visual_attribute_enabled' );
+			$this->assertArrayNotHasKey( 'wc-visual', wc_get_attribute_types(), 'The visual attribute type should require the feature setting.' );
+			$this->assertTrue(
+				wc_get_container()->get( \Automattic\WooCommerce\Internal\Features\FeaturesController::class )->change_feature_enable( 'wc-visual-attribute', true ),
+				'The visual attribute feature should be toggled on.'
+			);
 			$this->assertArrayHasKey( 'wc-visual', wc_get_attribute_types(), 'The visual attribute type should be available in block themes.' );

 			$attribute_id = wc_create_attribute(
@@ -260,11 +261,36 @@ class WC_Attribute_Functions_Test extends \WC_Unit_Test_Case {
 				wc_delete_attribute( $attribute_id );
 			}

-			remove_filter( 'woocommerce_admin_features', $enable_visual_attribute_feature );
+			delete_option( 'woocommerce_feature_wc_visual_attribute_enabled' );
 			switch_theme( $original_theme );
 		}//end try
 	}

+	/**
+	 * Test visual attribute feature setting visibility.
+	 *
+	 * @testdox Should show the `wc-visual` feature setting only for block themes.
+	 */
+	public function test_wc_visual_attribute_feature_setting_visibility() {
+		$original_theme = wp_get_theme()->get_stylesheet();
+
+		try {
+			switch_theme( 'twentytwentyfour' );
+
+			$features = FeaturesUtil::get_features( true );
+			$this->assertArrayHasKey( 'wc-visual-attribute', $features, 'The visual attribute feature should exist.' );
+			$this->assertFalse( $features['wc-visual-attribute']['disable_ui'], 'The visual attribute feature setting should be visible for block themes.' );
+
+			switch_theme( 'storefront' );
+
+			$features = FeaturesUtil::get_features( true );
+			$this->assertArrayHasKey( 'wc-visual-attribute', $features, 'The visual attribute feature should exist.' );
+			$this->assertTrue( $features['wc-visual-attribute']['disable_ui'], 'The visual attribute feature setting should be hidden for classic themes.' );
+		} finally {
+			switch_theme( $original_theme );
+		}
+	}
+
 	public function get_attribute_names_and_slugs() {
 		return array(
 			array( 'Dash Me', 'dash-me' ),