Gatilhos personalizados

Gatilhos personalizados

Copiar página

Crie gatilhos personalizados no Shopify Flow a partir de qualquer evento, com valores antes/depois e transformação em JavaScript.

Os gatilhos integrados abrangem as alterações que mais interessam à maioria das lojas. Um gatilho personalizado abrange o restante: basta escolher um evento Shopify, escrever algumas linhas de JavaScript para determinar se é relevante e o que deve ser enviado, e este torna-se um gatilho que poderá utilizar em Shopify Flow.

Três problemas que este resolve e que um gatilho integrado não consegue resolver:

  • Execute apenas se a sua condição for satisfeita. «Apenas quando um pedido superior a 500 EUR receber a etiqueta vip» é uma única linha de código, em vez de um fluxo de trabalho que seja executado em todos os pedidos e, posteriormente, as filtre.
  • Aplique uma condição a uma transição, não a um estado. O seu código deteta o valor antes e depois da alteração, pelo que é possível que «o estado tenha passado de rascunho para ativo» ou que «o stock tenha descido abaixo de 5». Uma condição baseada no valor atual não permite expressar isso.
  • Envie exatamente os campos que pretende. Reestruture o evento de acordo com os valores que o seu fluxo de trabalho utiliza efetivamente, em vez de os ler novamente um a um.

Um gatilho personalizado nem sequer necessita de um evento Shopify: também pode ser executado de acordo com uma programação e determinar por si próprio o que mudou.

Como funciona

  1. Escolha o que o faz funcionar: um evento Shopify ou um horário.
  2. Para um evento, selecione o evento ao qual este está associado - qualquer evento Shopify que a aplicação já receba - ou comece a partir de um modelo, que seleciona o evento e preenche o código.
  3. Capture um payload real. Efetue essa alteração na sua loja e a aplicação irá capturar o corpo exato do evento.
  4. Escreva uma transformação - devolva um objeto para disparar, devolva umnullo para ignorar.
  5. Teste-o com o evento capturado e veja exatamente o que o seu fluxo de trabalho receberia.
  6. Ligue-o.
O editor de gatilhos personalizados com nome, identificador, a opção entre um evento Shopify e uma programação, o evento e um modelo
Um novo gatilho personalizado: escolha o que o faz ser executado, selecione o evento e, se desejar, comece a partir de um modelo.

Escrever a transformação

O seu «gatilho» é um módulo JavaScript que exporta uma função denominada transform. Esta função recebe quatro argumentos:

  • payload - o corpo do evento Shopify na sua forma bruta, tal como é recebido.
  • topic - qual o evento que foi desencadeado, por exemplo, PRODUCTS_UPDATE.
  • shop - o seu domínio myshopify.
  • ctx - ctx.log(...) apresenta resultados no painel de registo ao lado do editor, ctx.shopify(...) executa uma consulta GraphQL de administração e ctx.fetch(...) acede a um endereço URL na Internet pública.

O que devolver determinar o que acontecerá:

  • Devolva um objeto e o gatilho é acionado, transportando esse objeto.
  • Se devolver «null», o evento é ignorado. É assim que funciona a filtragem - não é necessário aprender nenhuma linguagem de filtragem específica.
  • Deixe o ficheiro em branco e será acionado em cada evento desse 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,
  };
}

O valor antes da alteração

Shopify

Nas atualizações de produto, de pedido e de cliente, payload._changes apresenta todos os campos monitorizados que foram alterados por esta atualização, cada um com oldValue e newValue:

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

Trata-se de uma lista vazia quando a atualização não incidiu sobre esses campos - uma alteração no estoque, por exemplo - ou quando a aplicação está a visualizar o registo pela primeira vez. O evento de exemplo que captura no editor mostra o campo, para que possa ver a sua estrutura real antes de efetuar qualquer alteração no mesmo.

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

Comece a partir de um modelo

Na secção «Fires on» do editor, a opção «Começar a partir de um modelo» seleciona o evento e preenche o código funcional. Edite as constantes na parte superior, teste e, em seguida, guarde. Cada modelo lê um valor antes e depois da alteração:

  • Um campo de um produto, de um pedido ou de um cliente mudou de um valor para outro - o estado passou de «rascunho» para «ativo», um pedido passou para «paga», uma conta foi ativada.
  • O preço baixou mais de N por cento - uma verdadeira redução de preço, não uma simples alteração de preço.
  • O stock desceu abaixo de um limiar - aciona-se uma única vez, no momento em que o stock ultrapassa o limiar, e não em cada venda enquanto o stock já se encontra baixo.
  • O valor de um metacampo do produto ultrapassou um limiar - uma classificação ficou abaixo de 3, uma margem ultrapassou os 40.
  • Pedido pago por um cliente de elevado valor - analisa o valor total gasto pelo cliente na sua loja ao longo do tempo e só é acionado se o valor for superior ao que definir.
O cartão «Transform» do editor com o código de um modelo que lê «payload._changes»
Um modelo preenche o código com código funcional. Edite as constantes na parte superior, teste-o e, em seguida, guarde-o.

Obter dados adicionais com ctx.shopify

Os corpos dos Webhooks contêm apenas os campos enviados pelo Shopify. Quando necessitar de outra informação - o número de pedidos de um cliente, o estoque de uma variante, um metacampo - , consulte a API de Administração diretamente a partir da sua transformação:

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

Devolve o objeto data da consulta e lança uma exceção caso a consulta contenha erros, para que o erro seja visível no seu teste, em vez de a consulta simplesmente não produzir qualquer resultado sem aviso prévio.

Três limites que convém conhecer:

  • Até 10 chamadas por execução. O enriquecimento requer algumas; mais do que isso, normalmente implica um ciclo. Recupere o que precisar numa única consulta, sempre que possível.
  • A aplicação lê, não escreve. Utiliza as permissões que concedeu, e a aplicação apenas solicita acesso de leitura. Uma consulta aos dados de pedidos falhará, a menos que o «Acesso aos dados de pedidos» esteja concedido na página «Permissões». Para alterar algo na sua loja, faça-o nas ações do Shopify Flow que se seguem ao gatilho.
  • As credenciais da sua loja nunca chegam ao seu código. A consulta é executada pela aplicação em seu nome, pelo que não existe qualquer token de acesso dentro da sandbox que possa ser divulgado.

ctx.fetch(url, options) funciona como a funcionalidade fetch do navegador para qualquer conteúdo na Internet pública: o feed de stock de um fornecedor, uma taxa de câmbio, a sua própria API. Os endereços de redes internas e privadas são rejeitados. Se o seu código de ativação estiver guardado no GitHub, não inclua uma chave de API no mesmo.

Gatilhos que são executados de acordo com um horário definido

Shopify Flow reage quando algo acontece. Não pode reagir quando nada acontece e não consegue ver nada fora da sua loja. Para tal, selecione «De acordo com um horário» na secção «O que faz com que isto seja executado». Não existe nenhum evento Shopify por trás deste tipo de gatilho: o seu código é executado a intervalos, desde a cada 30 segundos até uma vez por dia, e decide por si próprio o que constitui uma alteração.

Trata-se da mesma função transform, com um payload diferente e um valor de retorno diferente:

  • payload.state - o valor que o seu código devolveu como state na execução anterior. null na primeira execução.
  • payload.now e payload.lastRunAt - registos de data e hora.
  • { state, events }: o novo estado a memorizar (até 32 KB) e uma lista de eventos a disparar (até 100 por execução). Cada evento dispara o Gatilho personalizado uma vez; o resourceId de um evento, caso o tenha definido, passa a ser o ID do registo no Shopify Flow. null quando não houver nada a comunicar.

Certifique-se de que, na primeira execução, o código apenas registe, nunca acione. Na primeira execução, o seu código não tem nada com que comparar, pelo que tudo parecerá novo. Guarde o que observar e não devolva quaisquer eventos; ao ativar o gatilho, nunca sobrecarregue os seus fluxos de trabalho. Todos os modelos funcionam desta forma.

O editor de gatilhos personalizados no modo «De acordo com um horário», com o intervalo e o número de execuções em 30 dias
De acordo com um calendário: escolha o intervalo - o editor indica o número total de execuções - e comece a partir de um modelo de programação.
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 }],
  }
}

Modelos para gatilhos programados, na secção «Iniciar a partir de um modelo» do cartão «Agendamento»:

  • Produto, pedido ou cliente não atualizado há N dias - revisões de catálogo desatualizadas, pedidos em espera, reconquista de clientes. Cada registo é acionado uma vez por período de inatividade, e os registos que já se encontravam em atraso no momento em que ativar esta funcionalidade não são acionados todos de uma só vez.
  • Foi alterado um valor fora dShopify: um feed de stock de um fornecedor, uma taxa de câmbio, uma lista de preços, com a diferença e a percentagem para os valores numéricos.
  • Novo elemento num feed RSS ou Atom - notícias do fornecedor, um feed de listagem, uma página de estado.
  • Sem pedidos durante N horas - um «batimento cardíaco» para a sua loja. É executado uma vez quando os pedidos cessam e outra vez quando estes voltam a surgir.

O Test executa o seu código uma vez, sem acionar nada e sem guardar o estado, pelo que pode executá-lo quantas vezes quiser.

Utilização no site Shopify Flow

Cada gatilho personalizado surge no Shopify Flow com o mesmo nome: Gatilho Personalizado. Adicione-o a um fluxo de trabalho e, em seguida, adicione uma condição com o texto «O identificador do gatilho é igual ao identificador do seu gatilho».

Esse identificador é apresentado na página do gatilho e nunca se altera, mesmo que renomeie o gatilho - pelo que o seu fluxo de trabalho continua a funcionar.

Cada chave devolvida pela sua transformação torna-se um campo no gatilho, e o objeto completo também está disponível em formato JSON, caso prefira analisá-lo por conta própria.

Guarde o código no GitHub

Pode ligar um repositório do GitHub para que o seu código de gatilho fique sob controlo de versões. As alterações ficam disponíveis para revisão numa solicitação de integração, pode ver quem alterou o quê e pode reverter uma transformação que tenha deixado de funcionar.

Ligue-o na página «Desenvolvedor», na secção «Ligações». Pode escolher quais os repositórios a que a aplicação tem acesso e pode revogar esse acesso no GitHub a qualquer momento.

Assim que um repositório for selecionado, todos os gatilhos existentes são imediatamente gravados nesse repositório, e a sincronização mantém-se em ambos os sentidos:

O que faz O que acontece
Criar, editar ou duplicar um gatilho na aplicação O ficheiro foi submetido ao seu repositório
Eliminar um gatilho na aplicação O ficheiro foi removido do seu repositório
Envie uma alteração para o ramo ligado O código do gatilho é atualizado na aplicação

Cada gatilho é um ficheiro cujo nome corresponde ao seu identificador, contendo exatamente o módulo que vê no editor - sem qualquer código adicional à sua volta. Isso significa que pode abri-lo no seu próprio editor, executá-lo e submetê-lo a uma verificação de conformidade, tal como faria com qualquer outro ficheiro JavaScript.

Voltar a uma versão anterior

Não é necessário conhecer o Git para reverter uma alteração. Assim que um repositório estiver ligado, o editor apresenta um menu suspenso «Versão» que lista todas as versões anteriores desse ficheiro, com a respetiva data e autor. Escolha uma delas e esta será carregada no editor como uma alteração não guardada, para que possa lê-la primeiro - é ao guardar que a alteração é revertida.

Teste enquanto edita localmente

Se estiver a editar o ficheiro no seu próprio editor, pode executá-lo com base no evento de amostra capturado sem ter de o guardar primeiro na aplicação. Utilize uma chave de API com o nível de execução disponível na página do Desenvolvedor:

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}')"

Receberá o mesmo resultado que o botão «Testar» da aplicação apresenta: se a função seria executada, o objeto de saída, as suas linhas ctx.log e o tempo de execução.

Este ponto final não** executa nem guarda nada** e não consome qualquer quota do plano - pelo que é seguro executá-lo sempre que for efetuado um salvamento a partir de um observador de ficheiros. (O botão «Executar teste» dentro da aplicação executa o seu fluxo de trabalho no Shopify Flow, para que possa acompanhar a sua execução de início a fim; isso também é gratuito.)

Também pode obter o payload de exemplo separadamente com uma chave de leitura, guardá-lo localmente e executar o ficheiro totalmente 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"
Um gatilho personalizado consome a franquia do meu plano?

Sim, e conta todos os eventos que analisa - não apenas aqueles em que é acionado. Se o seu gatilho estiver a monitorizar a atualização de produtos e a sua loja tiver 60 000 atualizações de produtos por mês, isso equivale a 60 000 eventos, mesmo que o seu código seja acionado em apenas 100 deles.

Recebemos, deduplicamos e colocamos em fila cada um desses eventos e, em seguida, executamos o seu código num ambiente isolado - tudo isto antes de o seu código decidir se deve ser executado. A contagem reflete esse trabalho.

Por outras palavras: o custo é o mesmo que o de um gatilho integrado para o mesmo evento. Não lhe é cobrado qualquer custo adicional pela filtragem e os testes são sempre gratuitos. Um gatilho agendado conta uma vez por execução.

O teste é gratuito?

Sim. Tanto o botão «Executar teste» na aplicação como o ponto final da API /test estão isentos, apesar de o botão «Executar teste» ativar efetivamente o seu fluxo de trabalho do Shopify Flow para que possa observá-lo a ser executado. Apenas as execuções em tempo real consomem a sua cota, pelo que pode iterar sobre uma transformação quantas vezes desejar.

Por que razão o «payload._changes» está vazio?

Ou a atualização não dizia respeito aos campos monitorizados - uma alteração no estoque ou numa variante do produto, por exemplo - ou a aplicação ainda não dispõe de uma linha de base para esse registo. A linha de base é armazenada na primeira vez que a aplicação deteta um registo; por isso, a primeira atualização de um registo que nunca tenha sido detetado não inclui qualquer valor anterior. Todas as atualizações subsequentes incluem esse valor.

O meu código pode alterar os dados na minha loja?

N.º ctx.shopify funciona com as permissões de leitura que concedeu, e a aplicação nunca solicita acesso de escrita. Trata-se de uma escolha deliberada: um gatilho que edita o registo que está a monitorizar reinicia-se a si próprio, o que constitui o ciclo vicioso pelo qual o Shopify desativa os fluxos de trabalho. Altere os dados nas ações do Shopify Flow que se seguem ao gatilho.

Posso trocar a pega mais tarde?

Não, e isso é intencional. O seu fluxo de trabalho no Shopify Flow filtra com base no identificador; por isso, alterá-lo interromperia silenciosamente a execução desse fluxo de trabalho. Pode renomear o gatilho à vontade - o identificador permanece inalterado.

O nome de utilizador corresponde também ao nome do ficheiro no seu repositório do GitHub, pelo que também nunca se altera.

O que acontece se o meu código tiver um erro?

O evento é ignorado e o erro é registado no gatilho, para que possa verificar o que correu mal. Uma transformação com falha nunca bloqueia nada mais - os seus outros gatilhos, personalizados ou integrados, continuam a funcionar sem serem afetados.

Onde é que o meu código é executado?

Num ambiente de teste isolado, separado do resto da aplicação, com um limite de tempo curto e sem acesso às credenciais da sua loja. Este ambiente apenas tem acesso à carga útil do evento que capturou, bem como a tudo o que obtiver através de ctx.shopify ou ctx.fetch.

E se eu editar o ficheiro no GitHub e na aplicação ao mesmo tempo?

Aquilo que guardar por último é que prevalece. Ao guardar na aplicação, o código é submetido ao ficheiro, e ao enviar para o ramo ligado, o código guardado na aplicação é substituído. Se trabalhar principalmente no seu repositório, considere o editor da aplicação como de leitura apenas, para evitar surpresas.

Um ficheiro no meu repositório pode criar um novo gatilho?

Não. Um gatilho também precisa de saber a que evento Shopify está atento, e o ficheiro contém apenas código - tentar adivinhar o evento levaria a associá-lo à coisa errada. Crie primeiro o gatilho na aplicação e, em seguida, edite o respetivo ficheiro à vontade.

Pode ser acionado por eventos que a aplicação ainda não receba?

Não. Um gatilho personalizado monitoriza os eventos aos quais a aplicação já está subscrita para a sua loja, o que depende das permissões que concedeu. Ao conceder permissão a um recurso, os seus eventos ficam também disponíveis para os gatilhos personalizados. Para tudo o resto, execute-o de acordo com uma programação.

Próximos passos