Carrito con JavaScript
El theme puede leer y cambiar el carrito sin recargar la página, con los mismos endpoints que el carrito AJAX de Shopify.
Todas las rutas son relativas a la tienda (mismo origen que el theme). Las que cambian el carrito son POST, aceptan JSON o formulario y solo responden a pedidos del mismo origen. La respuesta es JSON.
Leer el carrito
GET /cart.js devuelve el carrito con la forma del objeto cart: item_count, items, total_price (en unidades menores), requires_shipping, currency. En cada línea, image es la URL de la imagen.
const cart = await fetch('/cart.js').then((r) => r.json());
document.querySelector('[data-cart-count]').textContent = cart.item_count;
Las páginas de la tienda se sirven desde caché y llegan con el carrito vacío: el contador del encabezado se completa así, con /cart.js. Solo la página /cart trae el carrito real en Liquid.
Agregar
POST /cart/add.js con { id, quantity } o con varias líneas { items: [{ id, quantity }] }. id es el id de la variante. Responde la línea agregada (o { items: [...] }).
const res = await fetch('/cart/add.js', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ id: variantId, quantity: 1 }),
});
if (!res.ok) {
const error = await res.json();
alert(error.description); // "Elegí una variante.", "Ese producto ya no está disponible."…
}
Sin JavaScript, el {% form 'product' %} hace lo mismo con un formulario común y lleva al carrito.
Cambiar una línea
POST /cart/change.js con { id, quantity } (id de la variante, o line con la posición en el carrito empezando en 1). quantity: 0 saca la línea. Responde el carrito completo.
await fetch('/cart/change.js', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ line: 1, quantity: 3 }),
});
Varias líneas a la vez
POST /cart/update.js con { updates: { "<id de variante>": cantidad } }. En un formulario, updates[<id>]=2. Sin .js, el formulario vuelve al carrito (o va al checkout si el botón se llama checkout).
Vaciar
POST /cart/clear.js deja el carrito vacío y lo devuelve.
Refrescar secciones
Las respuestas de add.js, change.js y update.js pueden traer el HTML de secciones ya renderizado con el carrito nuevo, para reemplazarlas sin otro pedido: mandá sections con los ids (de una sección estática como header, o de templates/cart.json).
const res = await fetch('/cart/add.js', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ id: variantId, quantity: 1, sections: ['header', 'cart-drawer'] }),
});
const data = await res.json();
for (const [id, html] of Object.entries(data.sections)) {
if (html) document.getElementById(`section-${id}`).outerHTML = html;
}
Una sección que no existe llega como null. Pedí solo las que tenés que refrescar: hay un tope de secciones por pedido.
Errores
Los errores tienen la forma de Shopify: { "status": 422, "message": "Cart Error", "description": "…" }, con description lista para mostrar.
| Estado | Cuándo |
|---|---|
400 |
El pedido está mal armado. |
403 |
El pedido no vino de la tienda (otro origen). |
404 |
El producto ya no está disponible. |
422 |
Falta la variante o no hay stock para esa cantidad. |
429 |
Demasiados intentos seguidos: esperá antes de reintentar. |
Checkout
El checkout (/checkout) es de la plataforma y no lo edita el theme: el botón del carrito tiene que llevar ahí, con un link o con update y un botón name="checkout".