> ## 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.

# Hook

> Cambia il comportamento dell'Aftersell Cart: trasforma le righe, arricchiscile con dati Storefront, modella le opzioni di abbonamento e controlla l'add-to-cart.

Mentre gli [eventi](/it/aftersell/cart/sdk-events) ti permettono di *reagire* al carrello e le [azioni](/it/aftersell/cart/sdk-actions) di *modificarlo*, gli **hook** cambiano il comportamento del carrello stesso: come vengono renderizzate le righe, quali dati trasportano e cosa succede all'add-to-cart.

Gli hook vivono sotto `window.aftersell.cart.hooks`.

<Note>
  Un hook cambia ciò che l'acquirente **vede**; un'azione cambia ciò che è **nel suo carrello**. Nascondere una riga di omaggio con una transform la lascia nel carrello e nel totale. Rimuoverla con [`removeItem`](/it/aftersell/cart/sdk-actions#removeitemkey) la toglie davvero.
</Note>

<Note>
  Gli hook sono chiamate di set-up, quindi è sicuro registrarli in cima al tuo script, senza bisogno di aspettare `ready()`. Registrali nello script di **Initialization** del tuo carrello (vedi [Script personalizzati](/it/aftersell/cart/custom-scripts)).
</Note>

<div id="how-registration-works">
  ## Come funziona la registrazione
</div>

Ogni hook è un metodo `register*`. Lo chiami con la tua funzione; restituisce una **funzione di deregistrazione** che puoi chiamare per rimuovere la tua.

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
const off = window.aftersell.cart.hooks.registerSkipAddToCartRule((form) =>
  form.hasAttribute('data-skip-aftersell')
);

// later: off();
```

La registrazione è **additiva**, quindi la tua funzione viene eseguita insieme a tutte le altre. Questo è importante perché il tuo script raramente è l'unico sulla pagina: un'app di abbonamenti, un'app di bundle e il tema stesso possono tutti registrarsi sullo stesso hook. Nessuno di loro può sostituire il tuo, e nulla di ciò che registri può essere silenziosamente scartato da ciò che si carica dopo di te.

| Hook                                                                                      | Cosa fa                                                                                                                                   | Con più registrazioni                                             |
| ----------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- |
| [`registerLineTransform`](#registerlinetransform)                                         | Nascondi o rietichetta singole righe.                                                                                                     | Tutte vengono eseguite, in ordine di registrazione.               |
| [`registerLineComparator`](#registerlinecomparator)                                       | Riordina le righe renderizzate.                                                                                                           | Si compongono come tie-breaker.                                   |
| [`registerCartEnricher`](#registercartenricher)                                           | Allega dati Storefront extra a ogni riga.                                                                                                 | Tutti vengono eseguiti; ogni `id` è un namespace a sé.            |
| [`registerSubscriptionOptionsTransform`](#registersubscriptionoptionstransform)           | Nascondi o rinomina i selling plan di una riga.                                                                                           | Tutte vengono eseguite; le patch si fondono per piano, per campo. |
| [`registerDefaultSubscriptionOptionSelector`](#registerdefaultsubscriptionoptionselector) | Scegli quale piano è preselezionato.                                                                                                      | Vince la prima risposta non `null`.                               |
| [`registerSkipAddToCartRule`](#registerskipaddtocartrule)                                 | Consenti a form specifici di bypassare il carrello. Vedi [Intercettazione dell'add-to-cart](/it/aftersell/cart/add-to-cart-interception). | Qualsiasi regola che restituisce `true` salta.                    |

Un hook che genera un errore, o che non è una funzione, viene saltato; gli altri vengono comunque eseguiti e il carrello prosegue. Un'integrazione rotta non può abbattere l'add-to-cart, il selettore di abbonamento o l'ordinamento.

Il rovescio della medaglia è che un tuo hook rotto fallisce **silenziosamente**: nulla raggiunge la console del browser. Vedi [Debugging](/it/aftersell/cart/sdk-overview#debugging) per dove emergono questi errori.

***

<div id="registerlinetransform">
  ## registerLineTransform
</div>

`registerLineTransform(fn)` viene eseguito per ogni riga del carrello prima che venga renderizzata. Usalo per nascondere una riga o cambiare come si legge, senza toccare ciò che è effettivamente nel carrello dell'acquirente.

La funzione riceve una riga in sola lettura più dei setter. Restituisce una funzione di deregistrazione.

| Setter                            | Effetto                                                                                                                                      |
| --------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `setHidden(bool)`                 | Nasconde la riga dal drawer. Resta nel carrello e nel totale.                                                                                |
| `setTitle(string)`                | Cambia il titolo visualizzato.                                                                                                               |
| `setVariantTitle(string \| null)` | Cambia l'etichetta di variante visualizzata.                                                                                                 |
| `setInternalProperties(obj)`      | Fonde proprietà solo di rendering. Mai persistite su Shopify. Usato per [raggruppare righe bundle](/it/aftersell/cart/sdk-use-case-bundles). |

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
// Hide free gift lines from the drawer. The cart total is unaffected.
const off = window.aftersell.cart.hooks.registerLineTransform((line) => {
  if (line.finalLinePrice === 0) {
    line.setHidden(true);
  }
  if (line.sellingPlan) {
    line.setVariantTitle(`Delivered ${line.sellingPlan.name.toLowerCase()}`);
  }
});

// later: off();
```

<Warning>
  Una transform cambia solo ciò che viene renderizzato. Non può cambiare prezzo, quantità o identità della riga. Per quello usa le [azioni](/it/aftersell/cart/sdk-actions).
</Warning>

**Usalo per:** nascondere righe gift-with-purchase o iniettate da app, rietichettare righe di abbonamento, contrassegnare articoli scontati, nascondere componenti di bundle che l'acquirente non dovrebbe gestire individualmente.

`setInternalProperties` è il setter dietro il raggruppamento dei bundle: stampare le proprietà canoniche del bundle su ogni riga è il modo in cui fai renderizzare come un unico articolo le righe di carrello separate di un'app di terze parti. Vedi [Raggruppare righe bundle di un'altra app](/it/aftersell/cart/sdk-use-case-bundles).

<div id="registerlinecomparator">
  ## registerLineComparator
</div>

Un comparator nella stessa forma che `Array.prototype.sort` si aspetta. Viene eseguito dopo hide e rename, quindi vede le righe trasformate.

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
// Subscriptions first, then everything else.
window.aftersell.cart.hooks.registerLineComparator((lineA, lineB) => {
  return (lineB.sellingPlan ? 1 : 0) - (lineA.sellingPlan ? 1 : 0);
});
```

I comparator **si compongono come tie-breaker**: il primo che restituisce un valore diverso da zero decide quella coppia, e gli altri vengono consultati solo in caso di parità. Restituisci `0` per le coppie su cui non hai un'opinione. È così che passi la decisione al comparator successivo invece di imporgli un ordine.

**Usalo per:** portare in cima abbonamenti o articoli di alto valore, spingere in fondo omaggi e add-on, mantenere un prodotto sponsorizzato al primo posto.

<div id="registercartenricher">
  ## registerCartEnricher
</div>

`registerCartEnricher(registration)` recupera dati extra di prodotto o variante dalla Storefront API di Shopify e li allega a ogni riga del carrello corrispondente in `line.metadata[id]`. Usalo per esporre metafield, tag o qualsiasi altra cosa la Storefront API renda disponibile, senza che sia necessaria alcuna modifica al codice da parte di Aftersell.

| Campo      | Tipo                             | Descrizione                                                                                                                                 |
| ---------- | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`       | `string`                         | Namespace per il risultato; finisce in `line.metadata[id]`. Deve essere unico; una seconda registrazione con lo stesso `id` viene ignorata. |
| `onType`   | `'Product'` o `'ProductVariant'` | Quale nodo prende di mira il fragment. È anche la chiave di join (ID prodotto vs. ID variante).                                             |
| `fragment` | `string`                         | Una selezione di campi GraphQL (senza parentesi graffe esterne) inserita nella query Storefront. Le graffe devono essere bilanciate.        |

Restituisce una **funzione di deregistrazione**.

Ogni volta che il carrello si carica o cambia, Aftersell recupera il tuo fragment per ogni prodotto o variante nel carrello e allega il risultato. Il fetch è non bloccante: il carrello viene renderizzato immediatamente e riemette `cart_updated` quando i dati arrivano. Un fragment lento o che fallisce non ritarda né rompe mai il carrello.

```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 }
  `,
});

// Read it once the data arrives.
window.aftersell.cart.events.on('cart_updated', (state) => {
  state.items.forEach((line) => {
    const anchor = line.metadata.pricing?.anchorPrice;
    if (anchor) console.log(line.title, 'anchor price', anchor.value);
  });
});
```

Poiché l'arricchimento è asincrono, proteggi sempre la lettura, dato che `line.metadata.pricing` è `undefined` finché il primo fetch non si risolve, e `metadata` stesso è `{}` per impostazione predefinita.

**Usalo per:** portare un metafield su ogni riga (una stima di consegna, una lista di ingredienti, un flag "spedito separatamente", un moltiplicatore fedeltà) e renderizzarlo tramite un [blocco Custom code](/it/aftersell/cart/custom-code-blocks). Vedi [mostrare dati di metafield sulle righe del carrello](/it/aftersell/cart/sdk-use-case-metafields).

<Note>
  Più enricher coesistono senza problemi, dato che ogni `id` è un namespace a sé, quindi i loro dati non collidono mai.
</Note>

<Warning>
  I valori arricchiti vengono restituiti così come sono dalla Storefront API e **non** sono sanificati. Renderizzali come testo, non come HTML grezzo.
</Warning>

<div id="registersubscriptionoptionstransform">
  ## registerSubscriptionOptionsTransform
</div>

Nascondi o rinomina i selling plan offerti su una riga. La tua funzione riceve opzioni in sola lettura più dei setter, e non restituisce nulla.

| Setter            | Effetto                                |
| ----------------- | -------------------------------------- |
| `setHidden(bool)` | Nasconde il piano dal selettore.       |
| `setName(string)` | Cambia il nome del piano visualizzato. |

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
window.aftersell.cart.hooks.registerSubscriptionOptionsTransform((options, context) => {
  // context: { productId, variantId }
  options.forEach((option) => {
    if (option.discountPercent === 0) option.setHidden(true);
    option.setName(option.name.replace('Every ', ''));
  });
});
```

**Setter, non una lista restituita, così che più script possano coesistere.** Se questo hook restituisse un array, una transform interessata a un solo piano scriverebbe naturalmente `options.filter(...)` ed eliminerebbe silenziosamente i piani di tutte le altre app strada facendo. Con i setter puoi descrivere solo le tue modifiche: le patch si fondono per piano e per campo, e l'ultimo scrittore vince un conflitto reale sullo stesso campo dello stesso piano. Una transform che genera un errore non contribuisce nulla, e le altre si applicano comunque.

Ogni transform vede le opzioni *originali*, non una vista parzialmente patchata, quindi l'ordine di registrazione non cambia ciò che stai leggendo.

<Note>
  L'ordine dei piani resta quello restituito da Shopify, quindi una transform non può riordinare. Per controllare quale piano viene offerto per primo (e a quale si abbona il pulsante di upgrade da acquisto singolo), usa [`registerDefaultSubscriptionOptionSelector`](#registerdefaultsubscriptionoptionselector), che promuove la sua scelta in prima posizione.
</Note>

Inoltre non puoi *aggiungere* un piano o cambiare un prezzo: `discountPercent` non ha un setter, perché un piano che Shopify non onorerebbe al checkout sarebbe solo una promessa infranta nel selettore.

<div id="registerdefaultsubscriptionoptionselector">
  ## registerDefaultSubscriptionOptionSelector
</div>

Scegli quale piano è preselezionato su una riga. Restituisci l'`id` di un piano, oppure `null` per passare la mano.

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
window.aftersell.cart.hooks.registerDefaultSubscriptionOptionSelector((options) => {
  const best = options
    .slice()
    .sort((optionA, optionB) => optionB.discountPercent - optionA.discountPercent)[0];
  return best ? best.id : null;
});
```

Il **primo selector a restituire l'id di un piano disponibile vince**, quindi restituisci `null` per le righe che non ti interessano invece di tirare a indovinare. Questo passa la decisione al selector successivo invece di sovrascriverla. Un id che non corrisponde ad alcun piano sulla riga viene trattato come `null` e cede anch'esso la mano, quindi un id obsoleto non può svuotare il selettore.

La tua funzione riceve `(options, context)`, lo stesso `context` che riceve la transform delle opzioni.

<div id="registerskipaddtocartrule">
  ## registerSkipAddToCartRule
</div>

Restituisci `true` per lasciare che un form prodotto specifico aggiunga al carrello normalmente, bypassando completamente Aftersell. È utile per un form che necessita del proprio redirect o della propria gestione.

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
window.aftersell.cart.hooks.registerSkipAddToCartRule((form) =>
  form.hasAttribute('data-skip-aftersell')
);
```

**Qualsiasi `true` salta**, quindi mantieni la tua regola ristretta, facendola corrispondere ai form specifici che possiedi, e restituisci `false` per tutto il resto. Le regole vengono valutate in ordine di registrazione e si fermano al primo `true`, quindi non mettere effetti collaterali in una di esse: se la tua viene eseguita o meno dipende da cosa si è registrato prima.

<Tip>
  Se controlli il markup del form, non ti serve affatto un hook: aggiungi la classe **`aftersell-cart-skip-atc`** al `<form>` e Aftersell lo lascia in pace. Usa questo hook quando non puoi modificare il markup, o quando la decisione dipende da qualcosa che solo il tuo codice conosce.
</Tip>

**Usalo per:** un form di pre-ordine o preventivo che necessita del proprio redirect, il flusso personalizzato di un'app di abbonamenti, un pulsante "buy it now" che dovrebbe andare dritto al checkout. Per disattivare invece l'intercettazione per l'intera pagina, usa [`skip_add_to_cart_interceptor`](/it/aftersell/cart/sdk-configure#skip_add_to_cart_interceptor), ma preferisci questo hook, che è limitato ai form che indichi.

<div id="where-to-go-next">
  ## Dove andare adesso
</div>

* **[Oggetto cart](/it/aftersell/cart/sdk-cart-object)**: la struttura della riga che una transform riceve.
* **[Eventi](/it/aftersell/cart/sdk-events)**: tutto ciò a cui puoi sottoscriverti.
* **[Azioni](/it/aftersell/cart/sdk-actions)**: leggere e modificare il carrello.
* **[Casi d'uso](/it/aftersell/cart/sdk-use-cases)**: soluzioni complete alle richieste più comuni.
