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 🙂 |
