Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

499
Views
Woocommerce cómo ajaxificar el botón Agregar al carrito para productos variables usando botones de radio html personalizados en lugar del menú desplegable, sin complemento

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:

  1. En la página de un solo producto, primero verifique si el tipo de producto es "simple" o "variable".
  2. Si el producto es "variable", entonces estoy usando woocommerce_variable_add_to_cart(); función para generar el html adecuado.
  3. Luego, intente generar html nuevo y personalizado (es decir, "botones de radio") utilizando el html predeterminado (es decir, "menú desplegable") y los ganchos de woocommerce.
  4. Luego, tratando de dar funcionalidad al html nuevo y personalizado (es decir, "botones de radio") usando javascript.
  5. Luego oculta el menú desplegable predeterminado usando css.
  6. Luego, intento enviar una solicitud ajax a wordpress.
  7. Luego, intente procesar esa solicitud ajax en el backend y agregue el producto al carrito.

Aquí está mi código para cada sección:

  1. Comprobando si el tipo de producto es "variable" en la página de un solo producto:
 global $post; $product = wc_get_product($post->ID); $product_type = $product->get_type();
  1. Si el tipo de producto es "variable", genere el html adecuado:
 if($product_type == 'variable'): woocommerce_variable_add_to_cart(); endif;
  1. Generando html nuevo y personalizado (botones de radio) usando ganchos de php y woocommerce:
 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; }
  1. Dando funcionalidad a los "botones de radio" usando 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'); }); })
  1. Ocultar el menú desplegable predeterminado usando css:
 table.variations select{ display: none; }
  1. Enviando una solicitud ajax a wordpress:
 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; }); })
  1. Procesando la solicitud de ajax en el backend y agregando el producto al carrito:
 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.

over 4 years ago · Santiago Trujillo
1 answers
Answer question

0

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:

  • Primero, los datos con los que está trabajando
  • Segundo, el código que escribiste.
over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!