WooCommerce get_available_variations获取Any规则全变体问题
问题说明
WooCommerce开发中调用get_available_variations()函数时,会遇到设置了ANY(匹配所有属性值)变体的可变商品返回结果不全的问题:
- 测试可变商品为socks(袜子),仅配置1个属性size(尺寸),关联X、M、XL三个属性值
- 该商品仅创建1个设置为
ANY规则的变体,未给三个尺寸单独创建独立变体
函数返回结果结构如下:
array(1) { [0]=> array(25) { ["attributes"]=> array(1) { ["attribute_pa_size"]=> string(0) "" } ... } }
该返回逻辑本身符合WooCommerce后台规则:ANY选项对应的存储值为空字符串,商品前台详情页也能正常展示3个可选尺寸;其他为每个属性值单独创建变体的可变商品,调用该函数都能正常返回完整变体列表。
原有商品导出代码如下,需要适配上述场景生成完整的3个有效变体条目:
$products = wc_get_products(array( 'status' => 'publish', 'limit' => -1, )); if ($products) { echo '<products>'; foreach ($products as $product) { echo '<product>'; echo '<id>'. $product->get_id() .'</id>'; echo '<title>'. esc_html(strip_tags($product->get_title())) .'</title>'; echo '<description>'. esc_html(str_replace(' ', ' ', $product->get_short_description())) .'</description>'; echo '<price>'. $product->get_sale_price() .'</price>'; echo '<old_price>'. $product->get_regular_price() .'</old_price>'; echo '<sku>'. esc_html($product->get_sku()) .'</sku>'; if ($product->get_type() == 'variable') { $product_variations = $product->get_available_variations(); echo '<options>'; foreach ($product_variations as $variation) { echo "<option> {"; foreach ($variation['attributes'] as $key=>$value) { $taxonomy = str_replace('attribute_', '', $key); $term = get_term_by('slug', $value, $taxonomy); echo " 'label' : '". wc_attribute_label($taxonomy) ."', 'value' : '". $term->name ."', "; } echo " 'sku' : '". $variation['sku'] ."', 'weight' : '". (!empty($variation['weight']) ? $variation['weight'] : 0) ."', 'quantity' : ". ($variation['is_purchasable'] === true ? 10 : 0) .", 'image' : '". $variation['image']['url'] ."', 'price' : ". $variation['display_regular_price'] .", 'discounted_price' : ". $variation['display_price'] ." } </option> "; } echo '</options>'; } echo '</product>'; } echo '</products>'; }
解决方案
核心处理逻辑:识别变体中属性值为空(即设置为ANY匹配所有值)的条目,遍历对应属性的所有可选值,通过笛卡尔积手动展开生成对应数量的变体条目即可。
替换原有可变商品的变体处理部分代码:
if ($product->get_type() == 'variable') { $raw_variations = $product->get_available_variations(); $expanded_variations = []; foreach ($raw_variations as $variation) { // 区分当前变体内设置为ANY的属性、固定值属性 $any_attributes = []; $fixed_attributes = []; foreach ($variation['attributes'] as $attr_key => $attr_value) { if ($attr_value === '') { $taxonomy = str_replace('attribute_', '', $attr_key); // 获取该属性下关联到当前商品的所有可选值 $any_attributes[$attr_key] = wc_get_product_terms($product->get_id(), $taxonomy, array('fields' => 'slugs')); } else { $fixed_attributes[$attr_key] = $attr_value; } } // 无ANY规则的普通变体直接加入结果集 if (empty($any_attributes)) { $expanded_variations[] = $variation; continue; } // 计算属性组合笛卡尔积 $combinations = [[]]; foreach ($any_attributes as $attr_key => $slugs) { $new_combinations = []; foreach ($combinations as $combo) { foreach ($slugs as $slug) { $new_combo = $combo; $new_combo[$attr_key] = $slug; $new_combinations[] = $new_combo; } } $combinations = $new_combinations; } // 为每个属性组合生成对应变体条目 foreach ($combinations as $combo) { $new_variation = $variation; $new_variation['attributes'] = array_merge($fixed_attributes, $combo); $expanded_variations[] = $new_variation; } } echo '<options>'; // 遍历展开后的变体列表,原有输出逻辑无需修改 foreach ($expanded_variations as $variation) { echo "<option> {"; foreach ($variation['attributes'] as $key=>$value) { $taxonomy = str_replace('attribute_', '', $key); $term = get_term_by('slug', $value, $taxonomy); echo " 'label' : '". wc_attribute_label($taxonomy) ."', 'value' : '". $term->name ."', "; } echo " 'sku' : '". $variation['sku'] ."', 'weight' : '". (!empty($variation['weight']) ? $variation['weight'] : 0) ."', 'quantity' : ". ($variation['is_purchasable'] === true ? 10 : 0) .", 'image' : '". $variation['image']['url'] ."', 'price' : ". $variation['display_regular_price'] .", 'discounted_price' : ". $variation['display_price'] ." } </option> "; } echo '</options>'; }
- 该逻辑兼容多属性同时设置为
ANY的场景,自动生成所有合法的属性组合 - 展开生成的变体继承原
ANY变体的价格、库存、图片、SKU等配置,和前台用户选择任意属性值时拿到的商品信息完全一致 - 普通独立创建的变体不会被改动,完全兼容原有正常场景
若商品同时存在多个设置为
ANY的变体(比如覆盖不同属性组合范围的变体),需要额外增加优先级判断逻辑,优先匹配属性固定值更多的变体,避免重复生成条目。单ANY变体的场景下上述代码可直接使用。
内容的提问来源于stack exchange,提问作者Deyan Kostadinov
相关产品推荐
相关产品推荐

