Commit 10afcd3dfbc for woocommerce
commit 10afcd3dfbc08dcf63a301474b2b36e491561ee7
Author: Jason Kytros <jason.kytros@automattic.com>
Date: Tue Mar 10 12:11:24 2026 +0200
Fix attribute matching for non-ASCII characters in product CSV importer (#62963)
* Fix attribute matching for non-ASCII characters in product CSV importer
* Add changefile(s) from automation for the following project(s): woocommerce
* Lint fixes
* Updated unit test
* Remove redundant unit test requirement
---------
Co-authored-by: woocommercebot <woocommercebot@users.noreply.github.com>
diff --git a/plugins/woocommerce/changelog/62963-fix-issue-62709 b/plugins/woocommerce/changelog/62963-fix-issue-62709
new file mode 100644
index 00000000000..7e651624410
--- /dev/null
+++ b/plugins/woocommerce/changelog/62963-fix-issue-62709
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Fix attribute matching for non-ASCII characters in product CSV importer
\ No newline at end of file
diff --git a/plugins/woocommerce/includes/import/abstract-wc-product-importer.php b/plugins/woocommerce/includes/import/abstract-wc-product-importer.php
index aa1d3cefac5..4846616e7cb 100644
--- a/plugins/woocommerce/includes/import/abstract-wc-product-importer.php
+++ b/plugins/woocommerce/includes/import/abstract-wc-product-importer.php
@@ -497,7 +497,7 @@ abstract class WC_Product_Importer implements WC_Importer_Interface {
}
if ( $attribute_id ) {
- $attribute_name = wc_attribute_taxonomy_name_by_id( $attribute_id );
+ $attribute_name = sanitize_title( wc_attribute_taxonomy_name_by_id( $attribute_id ) );
} else {
$attribute_name = sanitize_title( $attribute['name'] );
}
@@ -511,7 +511,8 @@ abstract class WC_Product_Importer implements WC_Importer_Interface {
if ( $parent_attributes[ $attribute_name ]->is_taxonomy() ) {
// If dealing with a taxonomy, we need to get the slug from the name posted to the API.
- $term = get_term_by( 'name', $attribute_value, $attribute_name );
+ $taxonomy_name = $parent_attributes[ $attribute_name ]->get_name();
+ $term = get_term_by( 'name', $attribute_value, $taxonomy_name );
if ( $term && ! is_wp_error( $term ) ) {
$attribute_value = $term->slug;
@@ -547,7 +548,7 @@ abstract class WC_Product_Importer implements WC_Importer_Interface {
}
if ( $attribute_id ) {
- $attribute_name = wc_attribute_taxonomy_name_by_id( $attribute_id );
+ $attribute_name = sanitize_title( wc_attribute_taxonomy_name_by_id( $attribute_id ) );
} else {
$attribute_name = sanitize_title( $attribute['name'] );
}
diff --git a/plugins/woocommerce/tests/php/includes/importer/class-wc-product-csv-importer-test.php b/plugins/woocommerce/tests/php/includes/importer/class-wc-product-csv-importer-test.php
index a79af4aa330..bde2455c832 100644
--- a/plugins/woocommerce/tests/php/includes/importer/class-wc-product-csv-importer-test.php
+++ b/plugins/woocommerce/tests/php/includes/importer/class-wc-product-csv-importer-test.php
@@ -120,4 +120,108 @@ class WC_Product_CSV_Importer_Test extends \WC_Unit_Test_Case {
$this->assertInstanceOf( WP_Error::class, $error );
$this->assertEquals( 'A product with this SKU already exists.', $error->get_error_message() );
}
+
+ /**
+ * @testdox Test that attributes with non-ASCII characters are correctly set to "Used for Variations" during import.
+ */
+ public function test_variable_product_attributes_with_non_ascii_characters_set_to_used_for_variations() {
+ // Set admin user to allow term creation.
+ wp_set_current_user( self::factory()->user->create( array( 'role' => 'administrator' ) ) );
+
+ // Create a CSV importer instance to access protected methods.
+ $csv_file = __DIR__ . '/sample.csv';
+ $importer = new WC_Product_CSV_Importer( $csv_file );
+
+ // Create a variable product with non-ASCII attributes (Chinese characters).
+ $product = new WC_Product_Variable();
+ $product->set_name( 'Test Product with Chinese Attributes' );
+ $product->set_sku( 'test-non-ascii-attr' );
+ $product->save();
+
+ // Create global attributes with Chinese names.
+ $color_attr_id = wc_create_attribute(
+ array(
+ 'name' => '颜色',
+ 'type' => 'select',
+ 'order_by' => 'menu_order',
+ 'has_archives' => false,
+ )
+ );
+ $size_attr_id = wc_create_attribute(
+ array(
+ 'name' => '尺寸',
+ 'type' => 'select',
+ 'order_by' => 'menu_order',
+ 'has_archives' => false,
+ )
+ );
+
+ // Register taxonomies.
+ $color_taxonomy = wc_attribute_taxonomy_name_by_id( $color_attr_id );
+ $size_taxonomy = wc_attribute_taxonomy_name_by_id( $size_attr_id );
+ register_taxonomy( $color_taxonomy, 'product' );
+ register_taxonomy( $size_taxonomy, 'product' );
+
+ // Create terms for the attributes.
+ wp_insert_term( '红色', $color_taxonomy );
+ wp_insert_term( '绿色', $color_taxonomy );
+ wp_insert_term( '大码', $size_taxonomy );
+ wp_insert_term( '小码', $size_taxonomy );
+
+ // Set attributes on the product (initially NOT set to "Used for Variations").
+ $color_attribute = new WC_Product_Attribute();
+ $color_attribute->set_id( $color_attr_id );
+ $color_attribute->set_name( $color_taxonomy );
+ $color_attribute->set_options( array( '红色', '绿色' ) );
+ $color_attribute->set_visible( true );
+ $color_attribute->set_variation( false ); // Initially false.
+
+ $size_attribute = new WC_Product_Attribute();
+ $size_attribute->set_id( $size_attr_id );
+ $size_attribute->set_name( $size_taxonomy );
+ $size_attribute->set_options( array( '大码', '小码' ) );
+ $size_attribute->set_visible( true );
+ $size_attribute->set_variation( false ); // Initially false.
+
+ $product->set_attributes( array( $color_attribute, $size_attribute ) );
+ $product->save();
+
+ // Verify attributes are initially NOT set to "Used for Variations".
+ $attributes_before = $product->get_attributes();
+ $this->assertFalse( $attributes_before[ sanitize_title( $color_taxonomy ) ]->get_variation(), 'Color attribute should initially NOT be set to "Used for Variations"' );
+ $this->assertFalse( $attributes_before[ sanitize_title( $size_taxonomy ) ]->get_variation(), 'Size attribute should initially NOT be set to "Used for Variations"' );
+
+ // Simulate variation import data (as would come from CSV).
+ $variation_attributes = array(
+ array(
+ 'name' => '颜色',
+ 'taxonomy' => true,
+ ),
+ array(
+ 'name' => '尺寸',
+ 'taxonomy' => true,
+ ),
+ );
+
+ // Use reflection to call the protected method.
+ $reflection = new ReflectionClass( $importer );
+ $method = $reflection->getMethod( 'get_variation_parent_attributes' );
+ $method->setAccessible( true );
+
+ // Call the method (this should set "Used for Variations" to true).
+ $method->invoke( $importer, $variation_attributes, $product );
+
+ // Reload product to get updated attributes.
+ $product = wc_get_product( $product->get_id() );
+ $attributes_after = $product->get_attributes();
+
+ // Verify attributes are now set to "Used for Variations".
+ $this->assertTrue( $attributes_after[ sanitize_title( $color_taxonomy ) ]->get_variation(), 'Color attribute should be set to "Used for Variations" after processing variations' );
+ $this->assertTrue( $attributes_after[ sanitize_title( $size_taxonomy ) ]->get_variation(), 'Size attribute should be set to "Used for Variations" after processing variations' );
+
+ // Clean up.
+ WC_Helper_Product::delete_product( $product->get_id() );
+ wc_delete_attribute( $color_attr_id );
+ wc_delete_attribute( $size_attr_id );
+ }
}