Trigger personalizzati

I trigger predefiniti coprono le modifiche più rilevanti per la maggior parte dei negozi. Un trigger personalizzato copre il resto: basta scegliere un evento di Shopify, scrivere poche righe di JavaScript per stabilire se è rilevante e cosa inviare, e il risultato diventa un trigger utilizzabile in Shopify Flow.

Tre problemi che risolve e che un trigger integrato non è in grado di risolvere:

  • Attiva questa funzione solo alle tue condizioni. "Solo quando un ordine superiore a 500 EUR riceve il tag vip" è una sola riga di codice, invece di un flusso di lavoro che viene eseguito su ogni ordine e poi applica un filtro.
  • Esegui la verifica su una transizione, non su uno stato. Il tuo codice rileva il valore prima e dopo la modifica, quindi è possibile che "lo stato sia passato da bozza ad attivo" o che "le scorte siano scese al di sotto di 5". Una condizione basata sul valore corrente non può esprimere questo concetto.
  • Invia esattamente i campi che ti servono. Riorganizza l'evento in base ai valori effettivamente utilizzati dal tuo flusso di lavoro, invece di leggerli uno per uno.

Un trigger personalizzato non ha nemmeno bisogno di un evento Shopify: può anche essere eseguito in base a una pianificazione e decidere autonomamente cosa è cambiato.

Come funziona

  1. Scegli come farlo funzionare: un evento Shopify o una pianificazione.
  2. Per un evento, seleziona l'evento a cui è associato (qualsiasi evento Shopify che l'app riceve già) oppure parti da un modello, che seleziona l'evento e inserisce il codice.
  3. Acquisisci un payload reale. Apporta quella modifica nel tuo negozio e l'app acquisirà esattamente il corpo dell'evento.
  4. Scrivi una trasformazione: restituisci un oggetto da attivare; restituisci unnulle da ignorare.
  5. Provalo con l'evento acquisito e verifica esattamente cosa riceverebbe il tuo flusso di lavoro.
  6. Accendilo.
L'editor di trigger personalizzati con nome, identificativo, la possibilità di scegliere tra un evento Shopify e una pianificazione, l'evento e un modello
Un nuovo trigger personalizzato: scegli cosa lo attiva, seleziona l'evento e, se lo desideri, parti da un modello.

Scrittura della trasformazione

Il trigger è un modulo JavaScript che esporta una funzione denominata transform. Accetta quattro argomenti:

  • payload - il corpo grezzo dell'evento Shopify, esattamente così come viene ricevuto.
  • topic - quale evento è stato attivato, ad esempio PRODUCTS_UPDATE.
  • shop - il tuo dominio myshopify.
  • ctx - ctx.log(...) visualizza i dati nel pannello di log accanto all'editor, ctx.shopify(...) esegue una query GraphQL di amministrazione e ctx.fetch(...) richiama un URL su Internet.

Quello che restituisci determina cosa succederà:

  • Restituisce un oggetto e il trigger si attiva, trasportando quell’oggetto.
  • Restituisci null e l'evento viene saltato. È così che funziona il filtraggio: non c'è bisogno di imparare un linguaggio di filtraggio a parte.
  • Se si lascia il campo vuoto, l'evento viene attivato ogni volta che si verifica un evento di quel tipo.
flow-triggers/high-value-vip-order.jsjavascript
/**
 * Only fire for high-value orders carrying the vip tag.
 */
export async function transform(payload, topic, shop, ctx) {
  const total = parseFloat(payload.total_price || "0");
  const tags = (payload.tags || "").split(",").map(t => t.trim());

  if (total < 500) return null;
  if (!tags.includes("vip")) return null;

  ctx.log("firing for", payload.name, total);

  return {
    orderId: payload.admin_graphql_api_id,
    orderNumber: payload.name,
    total,
    currency: payload.currency,
    customerEmail: payload.email,
  };
}

Il valore prima della modifica

Shopify

Nelle sezioni "Aggiornamento prodotto", "Aggiornamento ordine" e "Aggiornamento cliente", payload._changes elenca tutti i campi monitorati modificati da tale aggiornamento, indicando per ciascuno di essi oldValue e newValue:

  • Prodotti: title, handle, description, status, vendor, productType, tags
  • Ordini: financialStatus, fulfillmentStatus, tags, note, lineItems e customAttributes.<name>
  • Clienti: tags, note, state (ENABLED, DISABLED, INVITED, DECLINED)

Si tratta di un elenco vuoto quando l'aggiornamento non ha interessato quei campi - ad esempio, una modifica all'inventario - oppure quando l'app visualizza il record per la prima volta. L'evento di esempio che si acquisisce nell'editor mostra il campo, in modo da poterne vedere la struttura effettiva prima di inserire dati al suo interno.

flow-triggers/product-went-live.jsjavascript
/**
 * Fire only when a product BECOMES active - not on every later edit of an
 * active product, which is what a condition on the current status would do.
 */
export async function transform(payload, topic, shop, ctx) {
  const change = (payload._changes || []).find((c) => c.field === "status");
  if (!change) return null;
  if (change.oldValue !== "draft" || change.newValue !== "active") return null;

  return {
    productId: payload.admin_graphql_api_id,
    title: payload.title,
    oldStatus: change.oldValue,
    newStatus: change.newValue,
  };
}

Gli eventi più specifici hanno i propri valori, sia vecchi che nuovi, quindi non è necessario utilizzare _changes in quel caso: una variazione di prezzo presenta oldPrice, newPrice e percentChange; una variazione di inventario presenta _oldAvailable, _newAvailable e _delta; una variazione di metafield presenta previousValue accanto a metafield.value.

Parti da un modello

Nella sezione "Fires on" dell'editor, l'opzione "Start from a template" seleziona l'evento e inserisce il codice funzionante. Modifica le costanti nella parte superiore, esegui un test, quindi salva. Ogni modello legge un valore prima e dopo la modifica:

  • Un campo relativo a un prodotto, a un ordine o a un cliente è passato da un valore a un altro: lo stato è passato da “bozza” a “attivo”, un ordine è stato pagato, un account è stato attivato.
  • Il prezzo è sceso di oltre N per cento: si tratta di una vera e propria riduzione, non di una semplice modifica del prezzo.
  • Le scorte sono scese al di sotto di una soglia: si attiva una volta sola, nel momento in cui le scorte superano la soglia, non ad ogni vendita quando sono già basse.
  • Il valore di un metafield del prodotto ha superato una soglia: una valutazione è scesa al di sotto di 3, un margine è salito al di sopra di 40.
  • Ordine pagato da un cliente di alto valore: rileva la spesa complessiva del cliente nel tuo negozio e si attiva solo se supera l'importo da te impostato.
La scheda “Trasforma” dell’editor con il codice di un modello denominato payload._changes
Un modello inserisce automaticamente il codice funzionante. Modifica le costanti nella parte superiore, provalo e poi salva.

Recupero di dati aggiuntivi con ctx.shopify

I corpi dei webhook contengono solo i campi inviati da Shopify. Se hai bisogno di altre informazioni - ad esempio il numero di ordini di un cliente, le giacenze di una variante o un metafield - esegui una query all'API di amministrazione direttamente dal tuo trasformatore:

Enrich the event before decidingjavascript
export async function transform(payload, topic, shop, ctx) {
  const data = await ctx.shopify(`
    query($id: ID!) {
      customer(id: $id) { numberOfOrders tags }
    }
  `, { id: payload.customer.admin_graphql_api_id });

  // Only fire for repeat customers
  if (data.customer.numberOfOrders < 5) return null;

  return {
    orderId: payload.admin_graphql_api_id,
    orderCount: data.customer.numberOfOrders,
  };
}

Restituisce l'data della query e genera un'eccezione se la query presenta errori, in modo che nel test venga segnalato un errore anziché terminare silenziosamente senza produrre alcun risultato.

Tre limiti da tenere a mente:

  • Fino a 10 chiamate per esecuzione. L'arricchimento ne richiede poche; se sono di più, di solito si tratta di un ciclo. Se possibile, recupera ciò che ti serve con una sola query.
  • L'app** legge, non scrive.** Utilizza le autorizzazioni che hai concesso e richiede sempre e solo l'accesso in lettura. Una richiesta relativa ai dati degli ordini non va a buon fine se nella pagina "Autorizzazioni" non è concessa l'autorizzazione "Accesso ai dati degli ordini". Per apportare modifiche al tuo negozio, fallo nelle azioni del flusso che seguono il trigger.
  • Le credenziali del tuo negozio non vengono mai trasmesse al tuo codice. La query viene eseguita dall'app per tuo conto, quindi all'interno della sandbox non è presente alcun token di accesso che possa essere divulgato.

ctx.fetch(url, options) Funziona come l'fetch del browser per qualsiasi contenuto presente su Internet: i dati sulle scorte di un fornitore, un tasso di cambio, la tua API. Gli indirizzi di rete interni e privati vengono rifiutati. Se il tuo codice di trigger è salvato su GitHub, non inserire una chiave API al suo interno.

Trigger che vengono eseguiti secondo una pianificazione

Shopify Flow reagisce quando succede qualcosa. Non può reagire quando non succede nulla e non può rilevare nulla al di fuori del tuo negozio. Per questo, seleziona “In base a una pianificazione” nella sezione “Cosa fa scattare questa azione”. Dietro a questo tipo di trigger non c’è alcun evento Shopify: il tuo codice viene eseguito a intervalli regolari, da ogni 30 secondi fino a una volta al giorno, e decide autonomamente cosa si intende per “modifica”.

Si tratta della stessa funzione transform, con un payload diverso e un valore di ritorno diverso:

  • payload.state - qualunque sia stato il valore restituito dal tuo codice come state nell'esecuzione precedente. null nella prima esecuzione.
  • payload.now e payload.lastRunAt - timestamp.
  • **Restituisce un oggetto { state, events }`**`: il nuovo stato da memorizzare (fino a 32 KB) e un elenco di eventi da attivare (fino a 100 per esecuzione). Ogni evento attiva **il** **`Custom Trigger`** una sola volta; l'`resourceId` di un evento, se impostato, diventa l'ID del record in Flow. Restituisce un oggetto null`` quando non c'è nulla da segnalare.

**Fai in modo che al primo ciclo **il codice si limiti a memorizzare i dati, senza mai attivare alcuna azione. Al primo ciclo, il codice non ha alcun termine di paragone, quindi tutto gli apparirà nuovo. Memorizza ciò che rilevi e non restituire alcun evento; in questo modo, l’attivazione del trigger non intaserà mai i tuoi flussi di lavoro. Tutti i modelli funzionano in questo modo.

L'editor personalizzato dei trigger in modalità "In base a un programma", con l'intervallo e il numero di esecuzioni in 30 giorni
In base a una pianificazione: scegli l'intervallo - l'editor mostra il numero totale di esecuzioni - e parti da un modello di pianificazione.
flow-triggers/supplier-stock-changed.jsjavascript
// Fires when a value at a JSON URL changes, with the value before and after.
const URL = "https://api.example.com/stock/1042"

export async function transform(payload, topic, shop, ctx) {
  const res = await ctx.fetch(URL, { headers: { accept: "application/json" } })
  if (!res.ok) throw new Error("The URL answered with HTTP " + res.status)
  const value = String((await res.json()).stock)

  // The first run only remembers the value.
  const previous = payload.state ? payload.state.value : undefined
  if (previous === undefined || previous === value) return { state: { value } }

  return {
    state: { value },
    events: [{ oldValue: previous, newValue: value }],
  }
}

Modelli per gli eventi pianificati, nella sezione “Avvia da un modello” della scheda “Pianificazione”:

  • Prodotto, ordine o cliente non aggiornato da N giorni: recensioni obsolete nel catalogo, ordini in sospeso, riconquista dei clienti. Ogni record si attiva una volta per ogni periodo di inattività e gli elementi già scaduti al momento dell’attivazione non vengono attivati tutti in una volta.
  • È stato modificato un valore esterno a Shopify: un feed delle scorte di un fornitore, un tasso di cambio, un listino prezzi, con la differenza e la percentuale relative ai numeri.
  • Nuovo elemento in un feed RSS o Atom: notizie dal fornitore, un feed con l'elenco dei prodotti, una pagina di stato.
  • Nessun ordine per N ore: un "battito cardiaco" per il tuo negozio. Si attiva una volta quando gli ordini si interrompono e una volta quando riprendono.

Test esegue il codice una sola volta senza attivare alcuna azione e senza salvare lo stato, in modo da poterlo eseguire tutte le volte che vuoi.

Come utilizzarlo in Shopify Flow

Ogni trigger personalizzato viene visualizzato in Flow con lo stesso nome: Trigger personalizzato. Aggiungilo a un flusso di lavoro, quindi inserisci una condizione del tipo “L’ID del trigger è uguale all’ID del tuo trigger”.

Quel nome è visibile nella pagina del trigger e non cambia mai, anche se si rinomina il trigger: in questo modo il flusso di lavoro continua a funzionare.

Ogni chiave restituita dalla tua trasformazione diventa un campo del trigger, e l'intero oggetto è disponibile anche in formato JSON, nel caso in cui tu preferisca analizzarlo autonomamente.

Conserva il codice su GitHub

È possibile collegare un repository GitHub in modo che il codice del trigger sia sottoposto al controllo di versione. Le modifiche diventano così revisibili in una pull request, è possibile vedere chi ha apportato quali modifiche ed è possibile ripristinare una trasformazione che ha smesso di funzionare.

Collegalo nella pagina "Sviluppatore", nella sezione "Connessioni". Puoi scegliere quali repository l'app può visualizzare e revocare tale accesso da GitHub in qualsiasi momento.

Una volta selezionato un repository, ogni trigger esistente viene immediatamente salvato al suo interno e la sincronizzazione rimane bidirezionale:

Cosa fai Cosa succede
Crea, modifica o duplica un trigger nell'app Il file è stato salvato nel tuo repository
Eliminare un trigger nell'app Il file è stato rimosso dal tuo repository
Invia una modifica al ramo collegato Il codice del trigger viene aggiornato nell'app

Ogni trigger è un file il cui nome corrisponde al proprio handle e che contiene esattamente il modulo visualizzato nell'editor, senza alcun codice aggiuntivo. Ciò significa che puoi aprirlo nel tuo editor, eseguirlo e controllarne la correttezza come qualsiasi altro file JavaScript.

Tornare a una versione precedente

Non è necessario conoscere Git per annullare una modifica. Una volta collegato un repository, l'editor mostra un menu a tendina "Versione" che elenca tutte le versioni precedenti di quel file con la rispettiva data e autore. Scegline una e verrà caricata nell'editor come modifica non salvata, così potrai prima leggerla; sarà il salvataggio a ripristinarla.

Esegui i test mentre modifichi i file localmente

Se stai modificando il file nel tuo editor, puoi eseguirlo sull'evento di esempio acquisito senza doverlo prima salvare nell'app. Utilizza una chiave API con livello di esecuzione dalla pagina Sviluppatori:

Test the file you are editingbash
curl -X POST https://shopify.workflow-trigger-extensions.app/api/v1/triggers/custom/high-value-vip-order/test \
  -H "Authorization: Bearer ftk_your_key_here" \
  -H "Content-Type: application/json" \
  -d "$(jq -Rn --rawfile c flow-triggers/high-value-vip-order.js '{code:$c}')"

Si ottiene lo stesso risultato visualizzato dal pulsante "Test" dell'app: se verrebbe attivato, l'oggetto di output, le righe ctx.log e il tempo di esecuzione.

Questo endpoint non attiva alcuna azione né esegue alcun salvataggio, e non consuma alcuna quota del piano; pertanto, può essere eseguito in tutta sicurezza ad ogni salvataggio da un file watcher. (Il pulsante "Esegui test" all'interno dell'app attiva il flusso di lavoro Flow, consentendoti di osservarne l'esecuzione dall'inizio alla fine; anche questa operazione è gratuita.)

È anche possibile scaricare il payload di esempio separatamente utilizzando una chiave di lettura, salvarlo in locale ed eseguire il file completamente offline:

Get the captured sample payloadbash
curl https://shopify.workflow-trigger-extensions.app/api/v1/triggers/custom/high-value-vip-order/test \
  -H "Authorization: Bearer ftk_your_key_here"
L'utilizzo di un trigger personalizzato consuma il traffico incluso nel mio piano?

Sì, e conta ogni evento che analizza, non solo quelli su cui si attiva. Se il tuo trigger rileva gli aggiornamenti dei prodotti e il tuo negozio registra 60.000 aggiornamenti al mese, si tratta di 60.000 eventi anche se il tuo codice si attiva solo su 100 di essi.

Riceviamo, deduplicamo e mettiamo in coda ciascuno di questi eventi, quindi eseguiamo il tuo codice in un ambiente sandbox isolato - il tutto prima che il tuo codice decida se attivarsi. Il conteggio riflette tale attività.

In altre parole: il costo è lo stesso che si avrebbe con un trigger integrato per lo stesso evento. Non viene addebitato alcun costo aggiuntivo per il filtraggio e i test sono sempre gratuiti. Un trigger pianificato viene conteggiato una volta per ogni esecuzione.

Il test è gratuito?

Sì. Sia il pulsante "Esegui test" nell'app che l'endpoint API /test sono esenti, anche se "Esegui test" avvia effettivamente il flusso di lavoro Flow in modo da poterlo osservare mentre viene eseguito. Solo le esecuzioni in tempo reale consumano la tua quota, quindi puoi ripetere una trasformazione tutte le volte che vuoi.

Perché payload._changes è vuoto?

O l'aggiornamento riguardava campi non monitorati - ad esempio, una modifica all'inventario o a una variante di un prodotto - oppure l'app non dispone ancora di una linea di base per quel record. La linea di base viene memorizzata la prima volta che l'app rileva un record, quindi il primissimo aggiornamento di un record che non ha mai visto prima non contiene alcun valore precedente. Tutti gli aggiornamenti successivi ne contengono uno.

Il mio codice può modificare i dati presenti nel mio archivio?

No. ctx.shopify viene eseguito con i permessi di lettura che hai concesso e l'app non richiede mai l'accesso in scrittura. Si tratta di una scelta deliberata: un trigger che modifica il record che sta monitorando si riavvia automaticamente, il che costituisce il ciclo per cui Shopify disattiva i flussi di lavoro. Modifica i dati nelle azioni del flusso che seguono il trigger.

Posso cambiare la maniglia in un secondo momento?

No, ed è una scelta deliberata. Il tuo flusso di lavoro Flow applica un filtro sull'identificatore, quindi modificarlo interromperebbe silenziosamente l'esecuzione di quel flusso di lavoro. Puoi rinominare il trigger a tuo piacimento: l'identificatore rimane invariato.

L'handle corrisponde anche al nome del file nel tuo repository GitHub, quindi non cambia mai.

Cosa succede se il mio codice contiene un bug?

L'evento viene saltato e l'errore viene registrato nel trigger, in modo da poter capire cosa è andato storto. Una trasformazione non riuscita non blocca mai nient'altro: gli altri trigger, sia personalizzati che integrati, continuano a funzionare senza subire alcun effetto.

Dove viene eseguito il mio codice?

In un ambiente sandbox isolato, separato dal resto dell'app, con un limite di tempo breve e senza accesso alle credenziali del tuo negozio. Vede esclusivamente il payload dell'evento che hai acquisito, oltre a ciò che recuperi tramite ctx.shopify o ctx.fetch.

Cosa succede se modifico il file contemporaneamente su GitHub e nell'app?

Vince l'ultimo salvataggio. Il salvataggio nell'app esegue il commit sul file, mentre il push sul ramo collegato sovrascrive il codice presente nell'app. Se lavori principalmente nel tuo repository, considera l'editor dell'app come di sola lettura per evitare sorprese.

Un file presente nel mio repository può generare un nuovo trigger?

No. Un trigger deve anche sapere a quale evento Shopify è associato, mentre il file contiene solo codice: indovinare l'evento comporterebbe collegarlo all'elemento sbagliato. Crea prima il trigger nell'app, poi modifica liberamente il suo file.

Può attivarsi in occasione di eventi che l'app non riceve già?

No. Un trigger personalizzato rileva gli eventi a cui l'app è già iscritta per il tuo negozio, a seconda delle autorizzazioni che hai concesso. Se concedi l'autorizzazione per una risorsa, i relativi eventi diventano disponibili anche per i trigger personalizzati. Per tutto il resto, esegui l'operazione secondo una pianificazione.

Prossimi passi