Skip to main content
Mientras que los eventos te permiten reaccionar al carrito y las acciones te permiten cambiarlo, los hooks cambian cómo se comporta el carrito en sí: cómo se renderizan las líneas, qué datos llevan y qué sucede al agregar al carrito. Los hooks viven bajo window.aftersell.cart.hooks.
Un hook cambia lo que el comprador ve; una acción cambia lo que hay en su carrito. Ocultar una línea de regalo gratis con una transformación la deja en el carrito y en el total. Eliminarla con removeItem la saca de verdad.
Los hooks son llamadas de configuración, así que es seguro registrarlos al principio de tu script, sin necesidad de esperar a ready(). Regístralos en el script de Initialization de tu carrito (consulta Scripts personalizados).

Cómo funciona el registro

Cada hook es un método register*. Lo llamas con tu función; devuelve una función de anulación de registro que puedes llamar para eliminar la tuya.
El registro es aditivo, así que tu función se ejecuta junto a todas las demás. Eso importa porque tu script rara vez es el único en la página: una app de suscripciones, una app de bundles y el propio tema pueden registrarse todos en el mismo hook. Ninguno puede reemplazar el tuyo, y nada de lo que registres puede ser descartado silenciosamente por lo que se cargue después de ti. Un hook que lanza una excepción, o que no es una función, se omite; el resto sigue ejecutándose y el carrito continúa. Una integración rota no puede tumbar el agregar al carrito, el selector de suscripciones ni el ordenamiento. La contraparte es que un hook roto tuyo falla silenciosamente: nada llega a la consola del navegador. Consulta Depuración para ver dónde sí afloran esos fallos.

registerLineTransform

registerLineTransform(fn) se ejecuta para cada línea del carrito antes de que se renderice. Úsalo para ocultar una línea o cambiar cómo se lee, sin tocar lo que realmente está en el carrito del comprador. La función recibe una línea de solo lectura más setters. Devuelve una función de anulación de registro.
Una transformación solo cambia lo que se renderiza. No puede cambiar el precio, la cantidad ni la identidad de la línea. Usa las acciones para eso.
Úsalo para: ocultar líneas de regalo con compra o inyectadas por apps, reetiquetar líneas de suscripción, marcar artículos con descuento, ocultar componentes de bundle que el comprador no debería gestionar individualmente. setInternalProperties es el setter detrás de la agrupación de bundles: estampar las propiedades canónicas del bundle en cada línea es cómo haces que las líneas de carrito separadas de una app de terceros se rendericen como un solo artículo. Consulta Agrupar líneas de bundle de otra app.

registerLineComparator

Un comparador con la misma forma que espera Array.prototype.sort. Se ejecuta después de ocultar y renombrar, así que ve las líneas transformadas.
Los comparadores se componen como criterios de desempate: el primero en devolver un valor distinto de cero decide ese par, y los demás se consultan solo en empates. Devuelve 0 para los pares sobre los que no tienes opinión. Eso es lo que le pasa la decisión al siguiente comparador en lugar de imponerle un orden. Úsalo para: hacer flotar suscripciones o artículos de alto valor hacia arriba, hundir regalos gratis y complementos hacia abajo, mantener un producto patrocinado en primer lugar.

registerCartEnricher

registerCartEnricher(registration) obtiene datos extra de producto o variante de la Storefront API de Shopify y los adjunta a cada línea del carrito coincidente en line.metadata[id]. Úsalo para mostrar metafields, etiquetas o cualquier otra cosa que la Storefront API exponga, sin requerir cambios de código por parte de Aftersell. Devuelve una función de anulación de registro. Cada vez que el carrito se carga o cambia, Aftersell obtiene tu fragment para cada producto o variante del carrito y adjunta el resultado. La obtención es no bloqueante: el carrito se renderiza inmediatamente y vuelve a emitir cart_updated una vez que los datos llegan. Un fragment lento o que falla nunca retrasa ni rompe el carrito.
Como el enriquecimiento es asíncrono, protege siempre la lectura, ya que line.metadata.pricing es undefined hasta que la primera obtención se resuelve, y metadata en sí tiene como valor predeterminado {}. Úsalo para: traer un metafield a cada línea (una estimación de entrega, una lista de ingredientes, un flag de “se envía por separado”, un multiplicador de lealtad) y renderizarlo mediante un bloque Custom code. Consulta mostrar datos de metafields en las líneas del carrito.
Múltiples enriquecedores coexisten sin problemas, ya que cada id es su propio namespace, así que sus datos nunca colisionan.
Los valores enriquecidos se devuelven tal cual desde la Storefront API y no están sanitizados. Renderízalos como texto, no como HTML sin procesar.

registerSubscriptionOptionsTransform

Oculta o renombra los planes de venta ofrecidos en una línea. Tu función recibe opciones de solo lectura más setters, y no devuelve nada.
Setters, no una lista devuelta, para que varios scripts puedan coexistir. Si este hook devolviera un array, una transformación que solo se preocupara por un plan escribiría naturalmente options.filter(...) y borraría silenciosamente los planes de todas las demás apps al salir. Con setters solo puedes describir tus propias ediciones: los parches se fusionan por plan y por campo, y el último escritor gana un conflicto genuino en el mismo campo del mismo plan. Una transformación que lanza una excepción no aporta nada, y las demás aún se aplican. Cada transformación ve las opciones originales, no una vista parcheada a medias, así que el orden de registro no cambia lo que estás leyendo.
El orden de los planes se mantiene como Shopify lo devolvió, así que una transformación no puede reordenar. Para controlar qué plan se ofrece primero (y a cuál se suscribe el botón de upgrade de compra única), usa registerDefaultSubscriptionOptionSelector, que promueve su elección al frente.
Tampoco puedes agregar un plan ni cambiar un precio: discountPercent no tiene setter, porque un plan que Shopify no honrará en el checkout solo sería una promesa rota en el selector.

registerDefaultSubscriptionOptionSelector

Elige qué plan está preseleccionado en una línea. Devuelve un id de plan, o null para pasar.
El primer selector que devuelve el id de un plan disponible gana, así que devuelve null para las líneas que no te importan en lugar de adivinar. Eso le pasa la decisión al siguiente selector en lugar de anularlo. Un id que no coincide con ningún plan de la línea se trata igual que null y también cede, así que un id obsoleto no puede dejar el selector en blanco. Tu función recibe (options, context), el mismo context que recibe la transformación de opciones.

registerSkipAddToCartRule

Devuelve true para permitir que un formulario de producto específico agregue al carrito normalmente, omitiendo Aftersell por completo. Esto es útil para un formulario que necesita su propia redirección o manejo.
Cualquier true omite, así que mantén tu regla estrecha, coincidiendo con los formularios específicos que posees, y devuelve false para todo lo demás. Las reglas se evalúan en orden de registro y se detienen en el primer true, así que no pongas efectos secundarios en una: si la tuya se ejecuta o no depende de lo que se registró antes.
Si controlas el marcado del formulario, no necesitas un hook en absoluto: agrega la clase aftersell-cart-skip-atc al <form> y Aftersell lo dejará en paz. Usa este hook cuando no puedas editar el marcado, o cuando la decisión dependa de algo que solo tu código sabe.
Úsalo para: un formulario de preventa o de cotización que necesita su propia redirección, el flujo personalizado de una app de suscripciones, un botón de “comprar ahora” que debe ir directo al checkout. Para desactivar la intercepción en toda la página en su lugar, usa skip_add_to_cart_interceptor, pero prefiere este hook, que está limitado a los formularios que nombras.

Adónde ir después

  • Objeto cart: la forma de la línea que recibe una transformación.
  • Eventos: todo aquello a lo que puedes suscribirte.
  • Acciones: leer y cambiar el carrito.
  • Casos de uso: soluciones completas a solicitudes comunes.