如何修复WooCommerce商品变体复制插件的保存失效问题?
问题原因分析
- 目标商品类型不兼容:你的目标商品是「简单商品」类型,WooCommerce不允许简单商品关联变体,即使创建了变体也会被系统自动清理,所以会出现变体ID递增但实际不显示的情况。
- 缺少父商品属性配置:变体依赖父商品的全局属性定义,你只复制了变体的属性值,但目标商品没有同步源商品的属性(包括属性名称、可选值、是否用于变体等核心设置),导致变体属性无法被系统识别。
- 变体创建流程不完整:直接实例化
WC_Product_Variation缺少必要的初始化逻辑,部分关键元数据或状态字段未设置,触发了WooCommerce的自动校验清理机制。
解决办法
- 先将目标商品从「简单商品」转为「可变商品」类型;
- 同步源商品的所有属性配置到目标商品;
- 使用WooCommerce官方推荐的
wc_create_product_variation()函数创建变体,确保流程合规; - 补充变体的必填字段(如库存状态、SKU),避免因字段缺失导致保存失败。
修复后的完整插件代码
<?php /* Plugin Name: WC Copy Variations Plugin URI: https://www.example.com Description: Copy a Woocommerce Product's Variations From One Product to Another Version: 1.1 Author: Wayne Schulz Author URI: https://www.example.com License: GPL2 License URI: https://www.gnu.org/licenses/gpl-2.0.html Text Domain: wc-copy-variations Domain Path: /languages */ // plugin settings menu add_action('admin_menu', 'wcvc_create_menu'); function wcvc_create_menu() { add_menu_page('WC Copy Variations Settings', 'Copy Variations', 'administrator', __FILE__, 'wcvc_settings_page' , plugins_url('/images/icon.png', __FILE__) ); add_action( 'admin_init', 'register_wcvc_settings' ); } function register_wcvc_settings() { register_setting( 'wcvc-settings-group', 'source_product_id' ); register_setting( 'wcvc-settings-group', 'target_product_id' ); register_setting( 'wcvc-settings-group', 'wcvc_status' ); } function wcvc_settings_page() { $wcvc_status = get_option('wcvc_status'); if(str_contains($wcvc_status, 'yes')) { perform_wcv_copy(); } ?> <div class="wrap"> <h1>WC Copy Variations</h1> <form method="post" action="options.php"> <?php settings_fields( 'wcvc-settings-group' ); ?> <?php do_settings_sections( 'wcvc-settings-group' ); ?> <table class="form-table"> <tr valign="top"> <th scope="row">Source Product ID</th> <td><input type="text" name="source_product_id" value="<?php echo esc_attr( get_option('source_product_id') ); ?>" /></td> </tr> <tr valign="top"> <th scope="row">Target Product ID</th> <td><input type="text" name="target_product_id" value="<?php echo esc_attr( get_option('target_product_id') ); ?>" /></td> </tr> <tr valign="top"> <th scope="row">Type 'yes' to copy</th> <td><input type="text" name="wcvc_status" value="<?php echo esc_attr( get_option('wcvc_status') ); ?>" /></td> </tr> </table> <?php submit_button(); ?> </form> </div> <table><tr><td style="vertical-align: top;"><?php show_wcv_source(); ?></td><td style="vertical-align: top;"><?php show_wcv_target(); ?></td></tr></table> <?php } function perform_wcv_copy() { $source_product_id = get_option('source_product_id'); $target_product_id = get_option('target_product_id'); $source_product = wc_get_product($source_product_id); $target_product = wc_get_product($target_product_id); if (!$source_product || !$source_product->is_type('variable')) { update_option( 'wcvc_status', 'error: source is not variable product' ); return; } // 1. 将目标商品转为可变类型 if ($target_product->is_type('simple')) { $target_product->set_type('variable'); $target_product->save(); // 重新获取更新后的商品对象 $target_product = wc_get_product($target_product_id); } // 2. 同步源商品的属性配置到目标商品 $source_attributes = $source_product->get_attributes(); foreach ($source_attributes as $attr_key => $attribute) { // 复制属性设置(包括名称、选项、是否用于变体等) $target_product->update_attribute($attr_key, $attribute->get_options()); $attribute->set_id(0); // 重置ID,避免关联到源商品的属性 $target_product->set_attribute($attr_key, $attribute); } $target_product->save(); // 3. 复制变体 $variations = $source_product->get_children(); foreach ($variations as $variation_id) { $variation = wc_get_product($variation_id); // 整理变体属性格式(匹配父商品的属性键) $variation_attributes = []; foreach ($variation->get_attributes() as $attr_name => $attr_value) { $attr_taxonomy = wc_attribute_taxonomy_name($attr_name); $variation_attributes[$attr_taxonomy] = $attr_value; } // 使用官方函数创建变体 $new_variation_id = wc_create_product_variation($target_product_id, [ 'attributes' => $variation_attributes, 'regular_price' => $variation->get_regular_price(), 'sale_price' => $variation->get_sale_price(), 'weight' => $variation->get_weight(), 'length' => $variation->get_length(), 'height' => $variation->get_height(), 'width' => $variation->get_width(), 'stock_status' => $variation->get_stock_status() ?: 'instock', 'sku' => $variation->get_sku() ?: $target_product->get_sku() . '-' . uniqid(), ]); } update_option( 'wcvc_status', 'done: variations copied successfully' ); } function show_wcv_source() { $source_product_id = get_option('source_product_id'); echo '<p><strong>Source Product ID: '.$source_product_id.'</strong><br />'; echo 'Product Categories: '.wc_get_product_category_list($source_product_id).'</p>'; $source_product = wc_get_product($source_product_id); if ($source_product->is_type('variable')) { $s_variations = $source_product->get_children(); foreach ($s_variations as $s_variation_id) { $s_variation = wc_get_product($s_variation_id); echo '<div class="wrap"><p>'; echo 'Attributes: '; var_dump($s_variation->get_attributes()); echo '<br />'; echo 'Regular Price: '.$s_variation->get_regular_price().'<br />'; echo 'Sale Price: '.$s_variation->get_sale_price().'<br />'; echo 'Weight: '.$s_variation->get_weight().'<br />'; echo 'Length: '.$s_variation->get_length().'<br />'; echo 'Height: '.$s_variation->get_height().'<br />'; echo 'Width: '.$s_variation->get_width().'<br />'; echo '</p></div>'; } } } function show_wcv_target() { $target_product_id = get_option('target_product_id'); echo '<p><strong>Target Product ID: '.$target_product_id.'</strong><br />'; echo 'Product Categories: '.wc_get_product_category_list($target_product_id).'</p>'; $target_product = wc_get_product($target_product_id); if ($target_product->is_type('variable')) { $t_variations = $target_product->get_children(); foreach ($t_variations as $t_variation_id) { $t_variation = wc_get_product($t_variation_id); echo '<div class="wrap"><p>'; echo 'Attributes: '; var_dump($t_variation->get_attributes()); echo '<br />'; echo 'Regular Price: '.$t_variation->get_regular_price().'<br />'; echo 'Sale Price: '.$t_variation->get_sale_price().'<br />'; echo 'Weight: '.$t_variation->get_weight().'<br />'; echo 'Length: '.$t_variation->get_length().'<br />'; echo 'Height: '.$t_variation->get_height().'<br />'; echo 'Width: '.$t_variation->get_width().'<br />'; echo '</p></div>'; } } } ?>
内容的提问来源于stack exchange,提问作者Wayne Schulz
相关产品推荐
相关产品推荐

