Contents
Introducción
Este tutorial explica paso a paso cómo añadir productos al carrito de WooCommerce mediante AJAX usando JavaScript. Cubriremos el proceso completo: cómo encolar el script, enviar la petición AJAX desde el frontend, procesarla en el servidor (PHP), devolver y actualizar los fragmentos del carrito (mini cart) y manejar productos simples, variables y cantidades. Incluye ejemplos listos para pegar en tu tema o plugin.
Requisitos previos
- WordPress con WooCommerce activo.
- Acceso para editar el archivo functions.php de tu tema o mejor, un plugin personalizado.
- Conocimientos básicos de PHP y JavaScript.
Visión general del flujo
- Encolar un script JS en el frontend y pasarle datos necesarios (ajax_url, nonce).
- Capturar el evento (click o submit) en el frontend, prevenir el comportamiento por defecto y enviar los datos al servidor vía fetch/XHR.
- Procesar la petición en PHP: verificar nonce, validar producto/variante y llamar a WC()->cart->add_to_cart().
- Devolver un JSON con estado y fragmentos actualizados del carrito.
- Actualizar la interfaz en el cliente (contador del carrito, mini cart, mensajes) y mostrar errores si los hay.
1) Encolar el script y pasar datos desde PHP
En functions.php (o plugin) encola el script y localiza variables que necesita el JS (ajax_url y nonce). Usa un handle único y carga solo en frontend cuando WooCommerce está activo.
admin_url( admin-ajax.php ), nonce => wp_create_nonce( mi_add_to_cart_nonce ), ) ) wp_enqueue_script( mi-add-to-cart-ajax ) } ?>
2) HTML mínimo del botón
El botón que dispare la acción debe incluir al menos el product_id y opcionalmente quantity y variation_id. Ejemplo para productos simples:
Para producto variable el formulario suele contener los atributos de variación y un input para variation_id si ya la tienes seleccionada o debes enviar los atributos para que PHP identifique la variación.
3) Código JavaScript: captura del evento y petición AJAX
Este ejemplo usa fetch también se puede adaptar a jQuery.ajax si lo prefieres. El script obtiene los datos del botón/form, construye FormData y envía la petición a admin-ajax.php.
// mi-add-to-cart-ajax.js (function(){ use strict // Delegación: útil si hay botones añadidos dinámicamente document.addEventListener(click, function(e){ var btn = e.target.closest(.mi-add-to-cart-btn) if(!btn) return e.preventDefault() var product_id = btn.getAttribute(data-product_id) var quantity = btn.getAttribute(data-quantity) 1 var variation_id = btn.getAttribute(data-variation_id) // Si usas atributos de variación (por ejemplo data-attributes) puedes leerlos // var attributes = { attribute_pa_color: red } if ( ! product_id ) { console.error(Falta product_id en el botón) return } var form = new FormData() form.append(action, mi_ajax_add_to_cart) form.append(security, MiAddToCart.nonce) form.append(product_id, product_id) form.append(quantity, quantity) if ( variation_id ) { form.append(variation_id, variation_id) } // Si necesitas pasar atributos de variación: // form.append(variation[attribute_pa_color], red) fetch(MiAddToCart.ajax_url, { method: POST, credentials: same-origin, body: form }) .then(function(response){ return response.json() }) .then(function(data){ if ( ! data ) { console.error(Respuesta inválida del servidor) return } if ( data.error ) { // Mostrar mensaje de error al usuario alert(data.error) // reemplaza con tu propia UI return } if ( data.fragments ) { // Actualizar fragmentos del carrito (mini cart) Object.keys(data.fragments).forEach(function(selector){ var html = data.fragments[selector] // selector puede ser por ejemplo .widget_shopping_cart_content o .site-header-cart var els = document.querySelectorAll(selector) els.forEach(function(el){ el.innerHTML = html }) }) } if ( data.cart_hash ) { // Puedes actualizar contador manualmente si no usas fragmentos var cartCount = document.querySelector(.mi-cart-count) if ( cartCount data.cart_count !== undefined ) { cartCount.textContent = data.cart_count } } // Mensaje de éxito breve if ( data.message ) { // Insertar o mostrar feedback console.log(data.message) } }) .catch(function(err){ console.error(Error en la petición AJAX:, err) }) }) })()
4) Handler PHP: añadir al carrito y devolver fragmentos
Añade las acciones AJAX para usuarios autenticados y no autenticados. La función valida el nonce, limpia inputs, intenta añadir al carrito y devuelve JSON con fragmentos actualizados usando WC_AJAX::get_refreshed_fragments().
true, message => Petición no autorizada. ), 403 ) } // Recoger y sanear datos product_id = isset( _POST[product_id] ) ? absint( _POST[product_id] ) : 0 quantity = isset( _POST[quantity] ) ? wc_stock_amount( wp_unslash( _POST[quantity] ) ) : 1 variation_id = isset( _POST[variation_id] ) ? absint( _POST[variation_id] ) : 0 variation = array() // Si hemos enviado atributos como variation[attribute_pa_color]=red if ( isset( _POST[variation] ) is_array( _POST[variation] ) ) { foreach ( _POST[variation] as attr => val ) { variation[ sanitize_text_field( attr ) ] = sanitize_text_field( wp_unslash( val ) ) } } if ( ! product_id ) { wp_send_json( array( error => true, message => ID de producto inválido. ) ) } // Intentar añadir al carrito added = false // Para productos variables, variation_id y variation pueden ser necesarios if ( variation_id ) { added = WC()->cart->add_to_cart( product_id, quantity, variation_id, variation ) } else { added = WC()->cart->add_to_cart( product_id, quantity ) } if ( ! added ) { wp_send_json( array( error => true, message => No se pudo añadir el producto al carrito. ) ) } // Obtener fragmentos refrescados (HTML del mini cart, contador, etc) if ( function_exists( WC_AJAX ) ) { // WC_AJAX::get_refreshed_fragments() devuelve un array con fragments y cart_hash fragments = WC_AJAX::get_refreshed_fragments() } else { // Fallback: generar manualmente el mini cart ob_start() woocommerce_mini_cart() mini_cart = ob_get_clean() fragments = array( fragments => array( .widget_shopping_cart_content => mini_cart ), cart_hash => WC()->cart->get_cart_hash() ) } // Añadir mensaje y contador opcional fragments[message] = sprintf( __( %s añadido al carrito., text-domain ), get_the_title( product_id ) ) fragments[cart_count] = WC()->cart->get_cart_contents_count() wp_send_json( fragments ) } ?>
5) Variaciones y atributos: consideraciones
Para productos variables no basta enviar product_id y variation_id en todos los casos. Si no tienes variation_id debes enviar todos los atributos de la variación (por ejemplo variation[attribute_pa_color] = rojo, variation[attribute_pa_talla] = m). El método WC()->cart->add_to_cart() necesita product_id, quantity, variation_id y array variation si trabajas con variaciones.
Ejemplo de envío de atributos desde un formulario
Si el formulario contiene selects con name=attribute_pa_color y name=attribute_pa_talla, en JS debes transformarlos para enviarlos como variation[attribute_pa_color] y variation[attribute_pa_talla].
// Construir atributos de variación dinámicamente var variation = {} var formEl = btn.closest(form) if ( formEl ) { var attrs = formEl.querySelectorAll(select[name^=attribute_], input[name^=attribute_]) attrs.forEach(function(input){ var name = input.name // e.g. attribute_pa_color variation[variation[ name ]] = input.value }) } // Luego en FormData haces: // for ( var key in variation ) { form.append(key, variation[key]) }
6) Actualizar la interfaz: fragmentos y UX
WooCommerce ofrece fragmentos refrescados que contienen mini cart y otros elementos. El ejemplo anterior actualiza selectores recibidos en data.fragments. Asegúrate de que los selectores que devuelves coinciden con los del tema (por ejemplo .site-header .cart-contents o .widget_shopping_cart_content).
Para una mejor experiencia de usuario:
- Mostrar un spinner/loader mientras la petición está en curso.
- Desactivar temporalmente el botón para evitar múltiples envíos.
- Mostrar mensajes claros de éxito o error (no usar alert en producción usa notificaciones visuales).
- Gestionar casos de falta de stock y errores retornados por WC.
7) Seguridad y buenas prácticas
- Usa nonce y verifica con wp_verify_nonce.
- Valida y sanea todos los inputs (absint, sanitize_text_field, wc_stock_amount, etc.).
- No confíes en datos enviados desde el frontend valida existencia del producto y permisos si aplica.
- Evita exponer datos sensibles en la respuesta JSON.
- Si añades lógica extra (precios personalizados, cuotas), ten en cuenta cómo afecta al cálculo del carrito y a sesiones.
8) Problemas comunes y cómo solucionarlos
- Respuesta JSON inválida: habilita WP_DEBUG_LOG y revisa si hay warnings o notices que imprimen texto antes de la respuesta. Usa wp_send_json para evitar problemas.
- Fragmentos que no se actualizan: verifica que los selectores devueltos coinciden con tu tema. Algunos temas usan otras clases/HTML.
- No añade la variación correcta: asegúrate de enviar los atributos con los nombres exactos (attribute_pa_). Puedes depurar imprimiendo los datos recibidos en PHP.
- Error de nonce: asegúrate de que wp_localize_script se ejecuta al encolar el script y que el nonce coincide.
9) Ejemplo final: todo junto (resumen práctico)
1) Encolar script y pasar ajax_url nonce (ver bloque PHP anterior). 2) Botón con data-product_id y data-quantity. 3) JS que envía FormData a action=mi_ajax_add_to_cart. 4) Handler PHP que llama a WC()->cart->add_to_cart y devuelve WC_AJAX::get_refreshed_fragments().
Conclusión
Implementar un Añadir al carrito vía AJAX en WooCommerce con JS proporciona una experiencia de usuario más fluida y moderna. Siguiendo estos pasos y teniendo en cuenta la validación de datos, la gestión de variaciones y la actualización de fragmentos, lograrás integrar una solución robusta compatible con la mayoría de temas y configuraciones de WooCommerce.
|
Acepto donaciones de BAT's mediante el navegador Brave 🙂 |