You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在WooCommerce产品变体中设置特定属性值?

WooCommerce 产品变体属性设置问题

问题描述

我正在开发一款WooCommerce插件,用于从JSON文件导入产品并创建产品变体。目前可变产品的全局属性能正常设置,但单个变体无法绑定特定的属性值——调用$variation->set_attributes($variation_attributes)完全没效果,所有变体都继承了父产品的全部属性选项。请问为单个产品变体定义特定属性值的正确写法是什么?

现有代码

插件核心PHP代码

/**
 * Plugin Name: WooCommerce JSON Product Importer
 * Description: Imports WooCommerce products with variations from a JSON file.
 * Version: 1.0.0
 * Author: Joe
 */

if (!defined('ABSPATH')) {
    exit;
}
add_action('admin_menu', 'wcppi_register_menu');

function wcppi_register_menu() {
    add_menu_page(
        'Product JSON Importer', 
        'Product Importer', 
        'manage_options', 
        'wcppi-importer', 
        'wcppi_importer_page', 
        'dashicons-upload', 
        20
    );
}

function wcppi_importer_page() {
    ?>
    <div class="wrap">
        <h1>WooCommerce Product Importer</h1>
        <form method="post" enctype="multipart/form-data">
            <input type="file" name="product_json" required><br><br>
            <input type="submit" name="import_submit" value="Import Products">
        </form>
    </div>
    <?php

    if (isset($_POST['import_submit'])) {
        wcppi_handle_import();
    }
}

function wcppi_handle_import() {

    if (isset($_FILES['product_json'])) {
        $json_file = $_FILES['product_json']['tmp_name'];

        $json_data = file_get_contents($json_file);
        $products = json_decode($json_data, true);

        if (!$products) {
            echo '<p>Error: Invalid JSON format.</p>';
            return;
        }

        $array = [
        'pa_color'     => array('Blue', 'Red', 'Green'),
        'pa_size' => array('S', 'M','L'),
        ];

        foreach($array as $attribute_slug => $terms){
            if (!taxonomy_exists($attribute_slug)) {
                $attribute_id[$attribute_slug] = wc_create_attribute(array(
                    'name'         => ucfirst(str_replace('pa_', '', $attribute_slug)),
                    'slug'         => $attribute_slug, // Attribute slug
                    'type'         => 'select',        // Type (dropdown)
                    'order_by'     => 'menu_order',    // Order by menu order
                    'has_archives' => false,
                ));

                // Register the taxonomy for the attribute
                register_taxonomy($attribute_slug, 'product', array(
                    'label' => ucfirst(str_replace('pa_', '', $attribute_slug)),
                    'public' => true,
                    'hierarchical' => false,
                    'show_ui' => false,
                    'query_var' => true,
                    'rewrite' => false,
                ));
            } 
        }

        foreach ($array as $attribute_slug => $terms) {
            foreach ($terms as $term) {
                if (!term_exists($term, $attribute_slug)) {
                    wp_insert_term($term, $attribute_slug);
                }
            }
        }

        foreach ($products as $product_data) {
            wcppi_import_product($product_data);
        }

        echo '<p>Products imported successfully!</p>';
    }
}

function wcppi_import_product($data) {
   
    $product = new WC_Product_Variable();
    $product->set_name($data['name']);
    $product->set_description($data['description']);
    $product->set_sku($data['sku']);
    $product->set_status('publish');
    $product->save();
    
    $product_id = $product->get_id();

    $attributes = array(); // Initializing
    $position   = $attr_id = 0; // Initializing
    
    foreach ($data['attributes'] as $taxonomy => $terms ) {
        $attr_id++;
      
        $attribute = new WC_Product_Attribute(); 
        $attribute->set_id($attr_id);
        $attribute->set_name("pa_" . lcfirst($taxonomy));
        $attribute->set_position($position);
        $attribute->set_visible(1);
        $attribute->set_variation(1);
        $attributes["pa_" . lcfirst($taxonomy)] = $attribute;
        $position++;
    }
    $product->set_attributes($attributes);
    $product_id = $product->save(); // Save product that returns the product ID
    
    foreach ($data['attributes'] as $taxonomy => $terms ) {
        
        wp_set_object_terms( $product_id, $terms, "pa_" . lcfirst($taxonomy), true );
    }

    foreach ($data['variations'] as $variation_data) {
        wcppi_import_variation($product_id, $variation_data);
    }
}

function wcppi_import_variation($product_id, $data) {
    $variation = new WC_Product_Variation();
    $variation->set_parent_id($product_id);
    $variation->set_regular_price($data['price']);
    $variation->set_sku($data['sku']);
 
    $variation_attributes = [];
    foreach ($data['attributes'] as $attribute_name => $attribute_value) {
        $taxonomy = 'pa_' . lcfirst($attribute_name);
        $variation_attributes[$taxonomy] = $attribute_value;
        
    }

    $variation->set_attributes($variation_attributes); 
    $product_id = $variation->save(); 

    foreach ($data['attributes'] as $taxonomy => $terms ) {
       
        wp_set_object_terms( $product_id, $terms, "pa_" . lcfirst($taxonomy), true );
    }
}

导入用的JSON文件

[
  {
    "name": "T-shirt",
    "sku": "TSHIRT001",
    "description": "A stylish t-shirt",
    "attributes": {
      "Color": ["Red", "Blue", "Green"],
      "Size": ["S", "M", "L"]
    },
    "variations": [
      {
        "sku": "TSHIRT001-RED-S",
        "price": "19.99",
        "attributes": {
          "Color": "Red",
          "Size": "S"
        }
      },
      {
        "sku": "TSHIRT001-RED-M",
        "price": "19.99",
        "attributes": {
          "Color": "Red",
          "Size": "M"
        }
      },
      {
        "sku": "TSHIRT001-BLUE-S",
        "price": "19.99",
        "attributes": {
          "Color": "Blue",
          "Size": "S"
        }
      }
    ]
  },
  {
    "name": "Hoodie",
    "sku": "HOODIE001",
    "description": "A warm hoodie",
    "attributes": {
      "Color": ["Black", "White"],
      "Size": ["M", "L", "XL"]
    },
    "variations": [
      {
        "sku": "HOODIE001-BLACK-M",
        "price": "29.99",
        "attributes": {
          "Color": "Black",
          "Size": "M"
        }
      },
      {
        "sku": "HOODIE001-BLACK-L",
        "price": "29.99",
        "attributes": {
          "Color": "Black",
          "Size": "L"
        }
      },
      {
        "sku": "HOODIE001-WHITE-XL",
        "price": "29.99",
        "attributes": {
          "Color": "White",
          "Size": "XL"
        }
      }
    ]
  }
]

问题原因及修正方案

核心问题点

  1. 变体属性值用了名称而非Slug:WooCommerce变体的属性值需要存储对应术语的slug(小写、空格转横杠),而不是显示名称。
  2. 多余的wp_set_object_terms调用:在wcppi_import_variation函数中,错误地给变体设置了所有属性术语,覆盖了之前用set_attributes设置的特定值。
  3. 父产品属性未关联术语:原代码中创建WC_Product_Attribute时没有设置术语列表,导致父产品属性不完整。

修正后的关键函数代码

修正wcppi_import_product函数

function wcppi_import_product($data) {
    $product = new WC_Product_Variable();
    $product->set_name($data['name']);
    $product->set_description($data['description']);
    $product->set_sku($data['sku']);
    $product->set_status('publish');
    
    $attributes = array();
    $position = 0;
    
    foreach ($data['attributes'] as $taxonomy_name => $term_names ) {
        $taxonomy = 'pa_' . lcfirst($taxonomy_name);
        
        // 获取术语的slug列表
        $term_slugs = array();
        foreach ($term_names as $term_name) {
            $term = get_term_by('name', $term_name, $taxonomy);
            if ($term) {
                $term_slugs[] = $term->slug;
            }
        }
        
        $attribute = new WC_Product_Attribute();
        // 不需要手动设置ID,保存时会自动生成
        $attribute->set_name($taxonomy);
        $attribute->set_position($position);
        $attribute->set_visible(1);
        $attribute->set_variation(1);
        $attribute->set_options($term_slugs); // 关联术语slug
        $attributes[] = $attribute;
        
        $position++;
    }
    
    $product->set_attributes($attributes);
    $product_id = $product->save();

    foreach ($data['attributes'] as $taxonomy_name => $term_names ) {
        $taxonomy = 'pa_' . lcfirst($taxonomy_name);
        wp_set_object_terms( $product_id, $term_names, $taxonomy, true );
    }

    foreach ($data['variations'] as $variation_data) {
        wcppi_import_variation($product_id, $variation_data);
    }
}

修正wcppi_import_variation函数

function wcppi_import_variation($product_id, $data) {
    $variation = new WC_Product_Variation();
    $variation->set_parent_id($product_id);
    $variation->set_regular_price($data['price']);
    $variation->set_sku($data['sku']);
 
    $variation_attributes = [];
    foreach ($data['attributes'] as $attribute_name => $attribute_value) {
        $taxonomy = 'pa_' . lcfirst($attribute_name);
        // 获取术语的slug
        $term = get_term_by('name', $attribute_value, $taxonomy);
        if ($term) {
            $variation_attributes[$taxonomy] = $term->slug;
        } else {
            // 如果术语不存在,用名称降级处理(不推荐,最好提前创建)
            $variation_attributes[$taxonomy] = sanitize_title($attribute_value);
        }
    }

    $variation->set_attributes($variation_attributes); 
    $variation->save(); 

    // 移除多余的wp_set_object_terms调用,避免覆盖属性值
}

额外优化点

  • 原wcppi_handle_import中硬编码的属性列表可以移除,直接从JSON数据中动态创建属性和术语,避免重复或遗漏。
  • 添加错误处理,比如术语不存在时的提示,确保导入稳定性。

内容的提问来源于stack exchange,提问作者zony

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 14:22:02