woocommerce产品详情页,在购物车表单选择产品属性,如:尺码、颜色等,默认是下拉选择。产品主图展示区功能单一,比如要实现根据不同产品颜色切换主图和略缩图导航走廊,就无法直接配置实现。当然这不怪它,毕竟woo 作为一款高度灵活的开源插件,其核心设计理念是提供基础功能框架,同时允许通过扩展(插件、代码)进行定制。既保持核心功能的简洁性,也是对开发者生态系统的尊重。
既然如此,只好自行自定义代码实现了,以提升用户使用体验,功能包括:尺码由下拉选择改为按钮组单选;颜色也改为图片预览选择,并和商品组图联动,比如用户选择 “蓝色运动鞋” 时,左侧商品图和略缩图走廊实时切换为对应颜色和版型。
1:定制选项HTML结构
函数1:wc_dropdown_variation_attribute_options,该功能输出产品购物车表单的属性选项的html结构。该函数里面预设2个过滤器。
过滤器1:woocommerce_dropdown_variation_attribute_options_args,修改下拉菜单设置的数组。
过滤器2:woocommerce_dropdown_variation_attribute_options_html,修改变体选择器的 HTML 结构。
我想把属性尺码改为按钮组单选,把颜色选项改为图片预览选择。

则在过滤器1中,增加下拉菜单设置的数组,用于判断当前正在渲染的属性。
if ($args['attribute'] === 'pa_size') {
$args['type'] = 'size';
} elseif ($args['attribute'] === 'pa_color') {
$args['type'] = 'color';
}
return $args;
在过滤器2中,在输出变体选择器的 HTML 结构时,新增自定义的变体选择器的 HTML 结构。
如:当前正常渲染尺码选项,在输出尺码下拉菜单的 HTML 结构时,利用过滤器1中$args数组中新增的属性判断当前是否在渲染尺码选项:
if (isset($args['type']) === 'size') {
...输出自定义选项结构
}
如果是,则输出过滤器2为此自定义的尺码按钮组单选。
注意,原先的下拉菜单HTML结构也要保留,因为前端的动态价格更新、库存状态显示、AJAX 交互等功能,写在add-to-cart-variation.js文件里。如果不保留原始 HTML,则要自己重写大量 JavaScript 逻辑来保持这些功能正常工作,也违背最小修改原则的最佳实践。因此我们应该利用现有功能。
所以,过滤器2中,返回HTML结构时,新建一层div把原来html结构包裹,并也新增隐藏类,由css设置隐藏效果。如下:
// 将原始下拉菜单和自定义单选按钮组合在一起
return '<div class="custom-variation-selector">' .
'<div class="visually-hidden">' .
$html .
'</div>' . // 隐藏原始下拉菜单
$radio_html .
'</div>';
2:将自定义单选按钮组集成到原生变体选择功能
原生add-to-cart-variation.js功能使用下拉选择框<select>来处理产品变体选择,当用户选择不同的变体选项时,通过 JavaScript 监听选择框的change事件,根据选择的值向服务器请求匹配的变体数据,更新页面上的价格、图片、库存状态等信息。
但是现在我由<select>自行定制成了单选按钮组<input>形式
<div class="radio-variation-wrapper" data-attribute_name="attribute_pa_size">
<div class="form-check">
<input type="radio" id="pa_size_42" name="grid-selector-input" value="42" class="form-check-input">
<label class="form-check-label" for="pa_size_42">42</label>
</div>
<div class="form-check">
<input type="radio" id="pa_size_43" name="grid-selector-input" value="43" class="form-check-input">
<label class="form-check-label" for="pa_size_43">43</label>
</div>
</div>
所以,还得自行写事件,模拟用户选择行为。监听自定义单选按钮的变化事件,获取当前选择的属性值,更新对应的隐藏选择框,再手动触发change事件,实现利用现有逻辑:
(function ($, wp) {
$(function () {
$(".radio-variation-wrapper input[type=\"radio\"]").on("change", function() {
// 获取当前被点击的单选按钮
var $radio = $(this);
// 从父容器获取属性名称(例如:attribute_pa_color)
var attributeName = $radio.closest('.radio-variation-wrapper').data('attribute_name');
// 找到对应的隐藏下拉选择器
var $select = $('select[name="' + attributeName + '"]');
// 备份原始函数
var originalImageUpdate = $.fn.wc_variations_image_update;
// 更新下拉选择器的值并触发change事件
$select.val($radio.val()).trigger('change');
});
});