Estoy tratando de juntar todas las piezas de este rompecabezas. He estado leyendo todas las preguntas y respuestas sobre este tema durante los últimos 3 días. Entonces, el plan general que estoy siguiendo es el siguiente:
woocommerce_variable_add_to_cart(); función para generar el html adecuado.Aquí está mi código para cada sección:
global $post; $product = wc_get_product($post->ID); $product_type = $product->get_type(); if($product_type == 'variable'): woocommerce_variable_add_to_cart(); endif; 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; } 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'); }); }) table.variations select{ display: none; } 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; }); }) 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(); } }PROBLEMA
Todo funciona hasta el paso 7 sin errores, pero cuando ejecuto todo, la página del producto individual se actualiza y el producto variable no se agrega al carrito. ¡Y el error de wordpress dice "{su campo de atributo} es un campo obligatorio"!
Creo que el error podría estar en algún lugar de la llamada ajax cuando intento enviar un objeto de variación al backend.
Aunque obtengo los datos absolutamente bien en el backend, pero no los agrega al carrito.
Cosas que he intentado depurar
Intenté enviar los datos en la llamada ajax como una matriz, pero tampoco funcionó. También traté de explotar los datos de variación usando tanto = como : ¡pero ninguno funcionó!
¡Pezuña! Ha sido una semana larga hasta ahora :\ llena de depuración, dolores de cabeza y frustraciones. Ahora, cuando trato de ejecutar todo el asunto, no puedo hacer que funcione y he estado leyendo todas las preguntas y respuestas en SO, ¡pero no puedo encontrar el error! Creo que lo he estado pensando demasiado durante un par de días y también hay muchas piezas.
Así que creo que necesito algunos pares de ojos adicionales para detectar el error.
¡Gracias, agradezco cualquier información!
Además, un gran agradecimiento a estos compañeros de quienes he aprendido mucho:
- LoicTheAztec por esta gran respuesta y esto y esto y muchos más.
- cfx por esta gran respuesta
- Anthony Grist por esta respuesta
- helgatheviking por esta respuesta
- Y OTROS
EDITAR
El código funciona bien, el error no estaba en el código, estaba en los datos que me proporcionaron. Dejaré el código aquí por si alguien lo necesita en el futuro.
Respuesta corta
El código funciona bien, lo dejaré aquí por si alguien lo necesita en el futuro. El error no estaba en el código, estaba en los datos que me proporcionaron.
Explicación detallada
El código funciona bien. Mi cliente manipuló los datos que me proporcionaron por alguna razón para que cada producto variable no fuera un producto variable real, pero al mismo tiempo las etiquetas se escribieron como productos variables (sí, sé que es confuso y no es un estándar práctica), es por eso que cada vez que intentaba agregarlos al carrito, me daba el error diciendo que {su-atributo} es un campo obligatorio.
Así que eliminamos los datos de cada producto y los volvimos a agregar como un producto variable real y verdadero, luego el código funcionó sin que cambiáramos nada en él.
Quitar
Así que recuerda, cada vez que desarrolles tu aplicación, ¡siempre hay dos caras en esta moneda! Un lado es su código y el otro lado son los datos en los que está trabajando.
Entonces, siempre, siempre, siempre, asegúrese de que los datos con los que está trabajando estén en la forma/formato que se supone que deben estar. Además, si no puede encontrar ningún error en su código, recuerde verificar/depurar el otro lado, que son los datos.
Si no verifica los datos primero o en cualquier etapa de depuración, ¡será difícil rastrear el problema en el futuro!
Este error generó un gran retraso en el proyecto (alrededor de 2 semanas hasta que localizamos el error en los datos). Así que asegúrese de comprobar siempre las dos caras de la moneda: