Como añadir al carrito vía AJAX en WooCommerce con JS en WordPress

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

  1. Encolar un script JS en el frontend y pasarle datos necesarios (ajax_url, nonce).
  2. Capturar el evento (click o submit) en el frontend, prevenir el comportamiento por defecto y enviar los datos al servidor vía fetch/XHR.
  3. Procesar la petición en PHP: verificar nonce, validar producto/variante y llamar a WC()->cart->add_to_cart().
  4. Devolver un JSON con estado y fragmentos actualizados del carrito.
  5. 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 🙂



Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *