> ## Documentation Index
> Fetch the complete documentation index at: https://docs.aftersell.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Mostrar datos de metafields en las líneas del carrito

> Un caso de uso del Cart SDK que usa registerCartEnricher para traer metafields desde la Shopify Storefront API a cada línea del carrito y luego renderizarlos.

El carrito sabe lo que la Ajax API de Shopify le dice: títulos, precios, cantidades, propiedades. No conoce tus metafields. Un **cart enricher** obtiene campos adicionales de producto o variante desde la Storefront API y los adjunta a cada línea coincidente, para que puedas mostrar una estimación de entrega, una advertencia de "se envía por separado", una lista de ingredientes o cualquier otra cosa que almacenes en el producto.

Usos típicos: ventanas de entrega por producto, insignias de alérgenos o ingredientes, un indicador personalizado de "pocas existencias", multiplicadores de puntos de fidelidad, precios exclusivos para suscriptores.

<div id="register-the-enricher">
  ## Registra el enricher
</div>

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
window.aftersell.cart.hooks.registerCartEnricher({
  id: 'delivery',
  onType: 'Product',
  fragment: `
    deliveryWindow: metafield(namespace: "custom", key: "delivery_window") { value }
    shipsSeparately: metafield(namespace: "custom", key: "ships_separately") { value }
  `,
});
```

Tres campos:

| Campo      | Descripción                                                                                                                                    |
| ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`       | Espacio de nombres para el resultado; aterriza en `line.metadata[id]`. Debe ser único; un segundo registro con el mismo `id` se ignora.        |
| `onType`   | `'Product'` o `'ProductVariant'`. También es la clave de unión, es decir, ID de producto vs. ID de variante.                                   |
| `fragment` | Una selección de campos GraphQL (sin llaves exteriores) que se inserta en la consulta a la Storefront API. Las llaves deben estar balanceadas. |

Cada vez que el carrito se carga o cambia, Aftersell obtiene tu fragment para cada producto o variante del carrito. La solicitud es **no bloqueante**: el carrito se renderiza de inmediato y vuelve a emitir `cart_updated` cuando llegan los datos. Un fragment lento o con fallos nunca retrasa ni rompe el carrito.

<div id="read-the-data">
  ## Lee los datos
</div>

Como el enriquecimiento es asíncrono, `line.metadata.delivery` es `undefined` hasta que la primera solicitud se resuelve. Protege siempre la lectura.

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
window.aftersell.cart.events.on('cart_updated', (state) => {
  state.items.forEach((line) => {
    const deliveryWindow = line.metadata.delivery?.deliveryWindow?.value;
    if (!deliveryWindow) return; // not fetched yet

    console.log(line.title, 'arrives in', deliveryWindow);
  });
});
```

<div id="render-it-in-the-cart">
  ## Renderízalo en el carrito
</div>

El enriquecimiento coloca los datos en la línea; un [bloque de código personalizado](/es/aftersell/cart/custom-code-blocks) en modo React los dibuja. Agrega el bloque como un **sub-bloque de Cart items** para que se renderice una vez por línea y reciba esa línea como `props.line`:

```jsx theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
function CustomCode(props) {
  const data = props.line?.metadata?.delivery;
  const window_ = data?.deliveryWindow?.value;

  if (!window_) return null;

  return (
    <div className="cart-external-custom-code_html" style={{ fontSize: '12px', opacity: 0.7 }}>
      Arrives in {window_}
    </div>
  );
}
```

<Warning>
  Los valores enriquecidos vuelven de la Storefront API **tal cual y sin sanitizar**. Renderízalos como texto, como se muestra arriba, y nunca con `dangerouslySetInnerHTML` ni escribiendo HTML sin procesar.
</Warning>

<div id="variant-level-data">
  ## Datos a nivel de variante
</div>

Establece `onType: 'ProductVariant'` cuando el metafield vive en la variante en lugar del producto:

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
window.aftersell.cart.hooks.registerCartEnricher({
  id: 'pricing',
  onType: 'ProductVariant',
  fragment: `
    anchorPrice: metafield(namespace: "custom", key: "anchor_price") { value }
    subscriberPrice: metafield(namespace: "custom", key: "subscriber_price") { value }
  `,
});
```

<div id="more-than-metafields">
  ## Más que metafields
</div>

El fragment se inserta en una consulta a la Storefront API, así que funciona cualquier cosa que la API exponga en un `Product` o `ProductVariant`, no solo metafields:

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
window.aftersell.cart.hooks.registerCartEnricher({
  id: 'productInfo',
  onType: 'Product',
  fragment: `
    tags
    vendor
    productType
    availableForSale
  `,
});
```

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
// Then: warn about anything from a drop-ship vendor.
window.aftersell.cart.events.on('cart_updated', (state) => {
  const hasDropship = state.items.some((line) => {
    const tags = line.metadata.productInfo?.tags;
    return tags?.includes('dropship');
  });
});
```

<div id="things-to-get-right">
  ## Cosas que debes hacer bien
</div>

* **Protege cada lectura.** `metadata` es `{}` por defecto y tu espacio de nombres es `undefined` hasta que la solicitud se resuelve. El carrito se renderiza antes de que lleguen los datos, siempre.
* **Cada `id` es su propio espacio de nombres.** Varios enrichers coexisten sin colisionar, incluidos los registrados por otras apps.
* **Los metafields deben ser visibles para la Storefront API.** Un metafield que no está expuesto a la Storefront API devuelve `null`. Revisa la definición en el admin de Shopify si no recibes nada.
* **Mantén el fragment pequeño.** Se ejecuta para cada producto del carrito, en cada cambio del carrito. Pide los campos que usas, no todo.
* **Regístralo en el momento de configuración.** Es un hook, así que pertenece al inicio de tu script de inicialización.
* **Las llaves deben estar balanceadas.** Sin llaves exteriores alrededor del fragment, pero cualquier selección anidada necesita su propio par correspondiente. Un fragment desbalanceado se rechaza.

<div id="where-to-go-next">
  ## Adónde ir después
</div>

* **[`registerCartEnricher`](/es/aftersell/cart/sdk-hooks#registercartenricher)**: la referencia completa del hook.
* **[Bloques de código personalizado](/es/aftersell/cart/custom-code-blocks)**: cómo renderizar los datos.
* **[Objeto cart](/es/aftersell/cart/sdk-cart-object)**: dónde se ubica `metadata` en una línea.
