我试图把这个谜题的所有部分放在一起。在过去的 3 天里,我一直在阅读有关此主题的所有问题和答案。所以我遵循的总体蓝图如下:
- 在单个产品页面上,首先检查产品类型是“简单”还是“可变”。
- 如果产品是“变量”,那么我正在使用
woocommerce_variable_add_to_cart();
函数来输出正确的 html。 - 然后尝试使用默认的 html(即“下拉菜单”)和 woocommerce 挂钩生成新的和自定义的 html(即“单选按钮”)。
- 然后尝试使用 javascript 为新的和自定义的 html(即“单选按钮”)提供功能。
- 然后使用 css 隐藏默认下拉菜单。
- 然后尝试向 wordpress 发送 ajax 请求。
- 然后尝试在后端处理该 ajax 请求并将产品添加到购物车。
这是我每个部分的代码:
- 在单品页面查看商品类型是否为“可变”:
global $post;
$product = wc_get_product($post->ID);
$product_type = $product->get_type();
- 如果产品类型是“变量”,则输出正确的 html:
if($product_type == 'variable'):
woocommerce_variable_add_to_cart();
endif;
- 使用 php 和 woocommerce 钩子生成新的和自定义的 html(单选按钮):
add_filter('woocommerce_dropdown_variation_attribute_options_html', 'my_theme_variation_radio_buttons', 20, 2);
function my_theme_variation_radio_buttons($html, $args)
{
$args = wp_parse_args(apply_filters('woocommerce_dropdown_variation_attribute_options_args', $args), array(
'options' => false,
'attribute' => false,
'product' => false,
'selected' => false,
'name' => '',
'id' => '',
'class' => '',
'show_option_none' => __('Choose an option', 'woocommerce'),
));
if (false === $args['selected'] && $args['attribute'] && $args['product'] instanceof WC_Product) {
$selected_key = 'attribute_' . sanitize_title($args['attribute']);
$args['selected'] = isset($_REQUEST[$selected_key]) ? wc_clean(wp_unslash($_REQUEST[$selected_key])) : $args['product']->get_variation_default_attribute($args['attribute']);
}
$options = $args['options'];
$product = $args['product'];
$attribute = $args['attribute'];
$name = $args['name'] ? $args['name'] : 'attribute_' . sanitize_title($attribute);
$id = $args['id'] ? $args['id'] : sanitize_title($attribute);
$class = $args['class'];
$show_option_none = (bool)$args['show_option_none'];
$show_option_none_text = $args['show_option_none'] ? $args['show_option_none'] : __('Choose an option', 'woocommerce');
if (empty($options) && !empty($product) && !empty($attribute)) {
$attributes = $product->get_variation_attributes();
$options = $attributes[$attribute];
}
$radios = '<div class="variation-radios">';
if (!empty($options)) {
if ($product && taxonomy_exists($attribute)) {
$terms = wc_get_product_terms($product->get_id(), $attribute, array(
'fields' => 'all',
));
foreach ($terms as $term) {
if (in_array($term->slug, $options, true)) {
$id = $name . '-' . $term->slug;
$radios .= '<input type="radio" data-checked="no" id="' . esc_attr($id) . '" name="' . esc_attr($name) . '" value="' . esc_attr($term->slug) . '" ' . checked(sanitize_title($args['selected']), $term->slug, false) . '><label for="' . esc_attr($id) . '">' . esc_html(apply_filters('woocommerce_variation_option_name', $term->name)) . '</label>';
}
}
} else {
foreach ($options as $option) {
$id = $name . '-' . $option;
$checked = sanitize_title($args['selected']) === $args['selected'] ? checked($args['selected'], sanitize_title($option), false) : checked($args['selected'], $option, false);
$radios .= '<input type="radio" id="' . esc_attr($id) . '" name="' . esc_attr($name) . '" value="' . esc_attr($option) . '" id="' . sanitize_title($option) . '" ' . $checked . '><label for="' . esc_attr($id) . '">' . esc_html(apply_filters('woocommerce_variation_option_name', $option)) . '</label>';
}
}
}
$radios .= '</div>';
return $html . $radios;
}
add_filter('woocommerce_variation_is_active', 'my_theme_variation_check', 10, 2);
function my_theme_variation_check($active, $variation)
{
if (!$variation->is_in_stock() && !$variation->backorders_allowed()) {
return false;
}
return $active;
}
- 使用 javascript 为“单选按钮”提供功能:
jQuery(document).ready($ => {
$(document).on('change', '.variation-radio input', function () {
$('.variation-radio input:checked').each(function (index, element) {
var radioElement = $(element);
var radioName = radioElement.attr('name');
var radioValue = radioElement.attr('value');
$('select[name="' + radioName + '"]').val(radioValue).trigger('change');
});
});
$(document).on('woocommerce_update_variation_values', function () {
$('.variation-radio input').each(function (index, element) {
var radioElement = $(element);
var radioName = radioElement.attr('name');
var radioValue = radioElement.attr('value');
radioElement.removeAttr('disabled');
if ($('select[name="' + radioName + '"] option[value="' + radioValue + '"]').is(':disabled')) {
radioElement.prop('disabled', true);
}
});
});
$("a.reset_variations").click(function () {
$('input:radio[name="attribute_size"]').prop('checked', false); $(this).css('display', 'none');
});
})
- 使用 css 隐藏默认下拉菜单:
table.variations select{
display: none;
}
- 向 wordpress 发送 ajax 请求:
jQuery(document).ready($ => {
$("button.single_add_to_cart_button").on('click', function (e) {
e.preventDefault();
var myBtn = $(this),
$form = myBtn.closest('form.variations_form'),
product_qty = $form.find('input[name=quantity]').val() || 1,
product_id = $form.find('input[name=product_id]').val(),
variation_id = $form.find('input[name=variation_id]').val() || 0,
variation = {},
keys = [],
values = [];
// Looping through the attributes names and save them as the keys array
$('table tr td.label label').each(function (index, element) {
let radioElement = $(element);
keys[index] = radioElement.text();
});
// Looping through the attributes values and save them as the values array
$('.variation-radios input:checked').each(function (index, element) {
let radioElement = $(element);
values[index] = radioElement.val();
});
// Looping through the variation object and save keys and values in that object
$.each(keys, function (index, element) {
variation[element] = values[index]
})
console.log(variation);
var data = {
action: 'woocommerce_add_variation_to_cart',
product_id: product_id,
quantity: product_qty,
variation_id: variation_id,
var: variation
};
$(document.body).trigger('adding_to_cart', [myBtn, data]);
$.ajax({
type: 'post',
url: wc_add_to_cart_params.ajax_url,
data: data,
beforeSend: function (response) {
myBtn.removeClass('added').addClass('loading');
},
complete: function (response) {
myBtn.addClass('added').removeClass('loading');
},
success: function (response) {
console.log(response);
if (response.error && response.product_url) {
window.location = response.product_url;
return;
} else {
$(document.body).trigger('added_to_cart', [response.fragments, response.cart_hash, myBtn]);
}
},
});
return false;
});
})
- 在后端处理 ajax 请求并将产品添加到购物车:
add_action('wp_ajax_nopriv_woocommerce_add_variation_to_cart', 'my_theme_testing_add_to_cart_variable');
add_action('wp_ajax_woocommerce_add_variation_to_cart', 'my_theme_testing_add_to_cart_variable');
function my_theme_testing_add_to_cart_variable()
{
if (isset($_POST['product_id']) && $_POST['product_id'] > 0) {
$product_id = apply_filters('woocommerce_add_to_cart_product_id', absint($_POST['product_id']));
$quantity = empty($_POST['quantity']) ? 1 : wc_stock_amount($_POST['quantity']);
$variation_id = isset($_POST['variation_id']) ? absint($_POST['variation_id']) : '';
$attributes = explode(',', $_POST['var']);
$variation = array();
foreach ($attributes as $values) {
$values = explode(':', $values);
$variation['attributes_' . $values[0]] = $values[1];
}
$passed_validation = apply_filters('woocommerce_add_to_cart_validation', true, $product_id, $quantity);
if ($passed_validation && WC()->cart->add_to_cart($product_id, $quantity, $variation_id, $variation)) {
do_action('woocommerce_ajax_added_to_cart', $product_id);
if (get_option('woocommerce_cart_redirect_after_add') == 'yes') {
wc_add_to_cart_message($product_id);
}
WC_AJAX::get_refreshed_fragments();
} else {
$data = array(
'error' => true,
'product_url' => apply_filters('woocommerce_cart_redirect_after_error', get_permalink($product_id), $product_id)
);
wp_send_json($data);
}
die();
}
}
问题
在第 7 步之前一切正常,没有错误,但是当我运行整个过程时,单个产品页面会刷新,并且变量产品不会添加到购物车中。wordpress 错误说“{您的属性字段}是必填字段”!
我认为当我尝试将变体对象发送到后端时,错误可能在 ajax 调用中的某个地方。
虽然,我在后端得到的数据绝对没问题,但它并没有将它添加到购物车中。
我试图调试的东西
我尝试将 ajax 调用中的数据作为数组发送,但也没有用。我还尝试使用两者来分解变化数据=
,:
但没有一个有效!
蹄!到目前为止,这已经是漫长的一周了:\ 充满了调试、头痛和挫折。现在,当我尝试运行整个 shebang 时,我无法让它工作,而且我一直在阅读所有 Qs 和 As on SO 但找不到错误!我想我已经想了几天了,而且还有很多部分。
所以我认为我需要一些额外的眼睛来希望能检测到这个错误。
谢谢你,我很感激任何见解!
此外,向我从他们身上学到很多东西的这些人大声疾呼:
- LoicTheAztec为这个伟大的答案以及这个和这个以及更多。
- cfx这个很好的答案
- 安东尼格里斯特的这个答案
- helgatheviking为这个答案
- 和别的
编辑
代码工作正常,错误不在代码中,而是在我提供的数据中。我会把代码留在这里,以防将来有人需要它。