Gatilhos personalizados

Gatilhos personalizados

Copiar página

Crie gatilhos personalizados no Shopify Flow com JavaScript, comparando valores antes/depois para disparar só quando a condição for atendida.

Os gatilhos integrados abrangem as alterações que mais interessam às lojas. Um gatilho personalizado abrange o restante: basta selecionar um evento Shopify, escrever algumas linhas de JavaScript para determinar se ele é relevante e quais dados devem ser enviados, e ele se torna um gatilho que poderá ser utilizado em Shopify Flow.

Três problemas que ele resolve e que um gatilho embutido não consegue resolver:

  • Execute apenas conforme sua condição. “Somente quando um pedido acima de 500 EUR receber a tag vip” é uma única linha de código, em vez de um fluxo de trabalho que seja executado em todos os pedidos e, em seguida, faça a filtragem.
  • Aplique uma condição a uma transição, não a um estado. Seu código percebe o valor antes e depois da alteração; portanto, é possível que “o status tenha passado de rascunho para ativo” ou que “o estoque tenha ficado abaixo de 5”. Uma condição baseada no valor atual não consegue expressar isso.
  • Envie exatamente os campos que desejar. Reestruture o evento de acordo com os valores que seu fluxo de trabalho realmente utiliza, em vez de recuperá-los um por um.

Um gatilho personalizado nem sequer precisa de um evento do tipo Shopify: ele também pode ser executado de acordo com uma programação e determinar por conta própria o que mudou.

Como funciona

  1. Escolha como o programa será executado: um evento Shopify ou uma programação.
  2. Para um evento, selecione o evento ao qual ele está atento - qualquer evento do tipo Shopify que o aplicativo já receba - ou comece a partir de um modelo, que seleciona o evento e preenche o código.
  3. Capture um payload real. Faça essa alteração em suas lojas e o aplicativo capturará o corpo exato do evento.
  4. Escreva uma transformação - retorne um objeto para acionar a ação; retorne umnullo para ignorá-la.
  5. Teste-o com o evento capturado e veja exatamente o que 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 aciona, selecione o evento e, se desejar, comece a partir de um modelo.

Escrevendo a transformação

Seu gatilho é um módulo JavaScript que exporta uma função chamada transform. Ela recebe quatro argumentos:

  • payload - o corpo do evento Shopify em formato bruto, exatamente como é recebido.
  • topic - qual evento foi disparado, por exemplo, PRODUCTS_UPDATE.
  • shop - seu domínio do MyShopify.
  • ctx - ctx.log(...) exibe informações no painel de log ao lado do editor, ctx.shopify(...) executa uma consulta GraphQL de administração e ctx.fetch(...) acessa uma URL na internet pública.

O que o(a) senhor(a) retornar determinará o que acontecerá:

  • Retorne um objeto e o gatilho será acionado, transportando esse objeto.
  • Retorne null e o evento será ignorado. É assim que a filtragem funciona - não há uma linguagem de filtragem separada para aprender.
  • Deixe o arquivo em branco e ele será acionado a 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, pedido e cliente, payload._changes lista todos os campos rastreados que foram alterados por essa 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>
  • , , (, , , )

Trata-se de uma lista vazia quando a atualização não envolveu esses campos - uma alteração no estoque, por exemplo - ou quando o aplicativo está acessando o registro pela primeira vez. O evento de exemplo que o senhor captura no editor mostra o campo, para que o senhor possa ver sua estrutura real antes de realizar a gravação nele.

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

Metacampos

Comece a partir de um modelo

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

  • Um campo de produto, pedido ou cliente mudou de um valor para outro - o status passou de “rascunho” para “ativo”, um pedido passou para “pago”, uma conta foi ativada.
  • O preço caiu mais de N por cento - uma redução real, e não apenas uma alteração de preço qualquer.
  • O estoque caiu abaixo de um limite - acione uma vez, no momento em que o estoque cruzar a linha, e não a cada venda enquanto ele já estiver baixo.
  • O valor de um metacampo do produto ultrapassou um limite - uma avaliação ficou abaixo de 3, uma margem ultrapassou 40.
  • Pedido pago por um cliente de alto valor - analisa o total de gastos acumulados do cliente em sua loja e aciona o evento somente quando o valor for superior ao que você definir.
A guia “Transformar” do editor com o código de um modelo que lê “payload._changes”
Um modelo preenche o código com funções operacionais. Edite as constantes na parte superior, teste-o e, em seguida, salve.

Obter dados adicionais com ctx.shopify

Os corpos dos Webhooks contêm apenas os campos enviados pelo Shopify. Quando precisar de outras informações - como o número de pedidos de um cliente, o estoque de uma variante ou um metacampo - , consulte a API de Administração diretamente a partir de 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,
  };
}

Ela retorna o data da consulta e gera uma exceção caso haja erros na consulta, de modo que um erro seja exibido em seu teste, em vez de simplesmente não retornar nada sem aviso prévio.

Três limites que vale a pena conhecer:

  • Até 10 chamadas por execução. O enriquecimento requer algumas; mais do que isso geralmente implica um loop. Recupere o que for necessário em uma única consulta, sempre que possível.
  • Ela lê, não grava. Ela utiliza as permissões que o senhor concedeu, e o aplicativo solicita apenas 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 em 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 pelo aplicativo em seu nome; portanto, não há nenhum token de acesso dentro da sandbox que possa vazar.

ctx.fetch(url, options) funciona como a função fetch do navegador para qualquer conteúdo na internet pública: um feed de estoque de um fornecedor, uma taxa de câmbio, sua própria API. Endereços de redes internas e privadas são rejeitados. Se o seu código de gatilho estiver salvo no GitHub, não inclua uma chave de API nele.

Gatilhos executados de acordo com uma programação

Shopify Flow reage quando algo acontece. Ele não pode reagir quando nada acontece e não consegue perceber nada fora da sua loja. Para isso, selecione “De acordo com uma programação” na seção “O que faz com que isso seja executado”. Não há nenhum evento Shopify por trás desse gatilho: seu código é executado em intervalos, a cada 30 segundos até uma vez por dia, e decide por si mesmo o que conta como 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 seu código retornou como state na execução anterior. null na primeira execução.
  • payload.now e payload.lastRunAt - registros de data e hora.
  • **Retorne { state, events }`**`: o novo estado a ser lembrado (até 32 KB) e uma lista de eventos a serem acionados (até 100 por execução). Cada evento aciona **o Gatilho personalizado** uma vez; o resourceIdde um evento, caso você o tenha definido, torna-se o ID do registro no Shopify Flow. Retornenull`` quando não houver nada a ser relatado.

Faça com que a primeira execução apenas registre, mas nunca acione. Na primeira execução, seu código não tem nada com que comparar, portanto tudo parecerá novo. Armazene o que for observado e não retorne nenhum evento; assim, ativar o gatilho nunca sobrecarregará seus fluxos de trabalho. Todos os modelos fazem isso.

O editor de gatilhos personalizados no modo “Por programação”, com o intervalo e o número de execuções em 30 dias
De acordo com uma programação: escolha o intervalo - o editor mostra quantas execuções isso totaliza - e comece a partir de um modelo programado.
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 seção “Iniciar a partir de um modelo” do cartão “Programação”:

  • Produto, pedido ou cliente não atualizado há N dias - revisões de catálogo desatualizadas, pedidos paralisados, reconquista de clientes. Cada registro é acionado uma vez por período de inatividade, e os itens que já estavam em atraso no momento em que a função for ativada não serão acionados todos de uma só vez.
  • Um valor fora de Shopify foi alterado - um feed de estoque de fornecedor, uma taxa de câmbio, uma lista de preços, com a diferença e a porcentagem para os números.
  • Novo item em um feed RSS ou Atom - notícias de fornecedores, um feed de listagem, uma página de status.
  • Sem pedidos por N horas - um indicador de atividade para a sua loja. É acionado uma vez quando os pedidos param e outra vez quando eles retornam.

O Test executa seu código uma vez, sem acionar nada e sem armazenar o estado, para que você possa executá-lo quantas vezes desejar.

Como utilizá-lo no site Shopify Flow

Todo gatilho personalizado chega ao 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 é exibido na página do gatilho e nunca se altera, mesmo que o senhor renomeie o gatilho - assim, seu fluxo de trabalho continua funcionando.

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

Mantenha o código no GitHub

É possível conectar um repositório do GitHub para que o código do seu gatilho fique sob controle de versão. As alterações passam a estar disponíveis para revisão em uma solicitação de pull; você pode verificar quem alterou o quê e reverter uma transformação que tenha deixado de funcionar.

Conecte-o na página “Desenvolvedor”, na seção “Conexões”. Você escolhe quais repositórios o aplicativo pode acessar e pode revogar esse acesso no GitHub a qualquer momento.

Assim que um repositório for selecionado, todos os gatilhos existentes são gravados nele imediatamente, e a sincronização é mantida em ambas as direções:

O que o(a) senhor(a) faz O que acontece
Crie, edite ou duplique um gatilho no aplicativo O arquivo foi enviado para o seu repositório
Excluir um gatilho no aplicativo O arquivo foi removido do seu repositório
Envie uma alteração para o branch conectado O código do gatilho é atualizado no aplicativo

Cada gatilho é um arquivo cujo nome corresponde ao seu identificador, contendo exatamente o módulo que o senhor vê no editor - sem nada adicionado ao redor. Isso significa que o senhor pode abri-lo em seu próprio editor, executá-lo e verificar sua validade como qualquer outro arquivo JavaScript.

Voltar a uma versão anterior

Não é necessário conhecer o Git para desfazer uma alteração. Assim que um repositório estiver conectado, o editor exibe um menu suspenso “Versão” que lista todas as versões anteriores daquele arquivo, com a respectiva data e autor. Escolha uma delas e ela será carregada no editor como uma alteração não salva; assim, o senhor poderá lê-la primeiro - é ao salvar que a alteração é revertida.

Faça testes enquanto edita localmente

Caso esteja editando o arquivo em seu próprio editor, é possível executá-lo com o evento de amostra capturado sem precisar salvá-lo primeiro no aplicativo. 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}')"

O senhor receberá o mesmo resultado que o botão “Testar” do aplicativo exibe: se a função seria acionada, o objeto de saída, suas linhas de ctx.log e o tempo de execução.

Nada é acionado nem salvo por este endpoint, e ele não utiliza nenhuma cota do plano - portanto, é seguro executá-lo a cada salvamento a partir de um monitor de arquivos. (O botão “Executar teste” dentro do aplicativo aciona o seu fluxo de trabalho do Shopify Flow, para que você possa acompanhá-lo de ponta a ponta; isso também é gratuito.)

Você também pode baixar o payload de exemplo separadamente com uma chave de leitura, salvá-lo localmente e executar o arquivo 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 cota do meu plano?

Sim, e ele conta todos os eventos que monitora - não apenas aqueles que acionam o seu código. Se o seu gatilho estiver configurado para monitorar atualizações de produtos e a sua loja tiver 60.000 atualizações de produtos por mês, isso significa 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; em seguida, executamos seu código em um ambiente isolado - tudo isso antes que seu código decida se será acionado. A contagem reflete esse trabalho.

Dito de outra forma: o custo é o mesmo que o do gatilho integrado para o mesmo evento. Não há cobrança adicional pela filtragem, e os testes são sempre gratuitos. Um gatilho programado é contabilizado uma vez por execução.

O teste é gratuito?

Sim. Tanto o botão “Executar teste” no aplicativo quanto o endpoint da API /test estão isentos, embora o botão “Executar teste” realmente acione seu fluxo de trabalho do Shopify Flow para que você possa observá-lo em execução. Apenas as execuções em tempo real consomem sua cota; portanto, você pode iterar sobre uma transformação quantas vezes desejar.

Por que `payload._changes` está vazio?

Ou a atualização ocorreu fora dos campos monitorados - uma alteração no estoque ou na variante do produto, por exemplo - ou o aplicativo ainda não possui uma linha de base para esse registro. A linha de base é armazenada na primeira vez em que o aplicativo detecta um registro; portanto, a primeira atualização de um registro que ele nunca tenha visto não contém nenhum valor anterior. Todas as atualizações subsequentes, por sua vez, contêm.

Meu código pode alterar os dados nas minhas lojas?

N.º ctx.shopify é executado com as permissões de leitura que o senhor concedeu, e o aplicativo nunca solicita acesso de gravação. Isso é intencional: um gatilho que edita o registro que está monitorando é reiniciado automaticamente, o que constitui o loop 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 alça mais tarde?

Não, e isso é proposital. Seu fluxo de trabalho no Shopify Flow é filtrado pelo identificador; portanto, alterá-lo interromperia silenciosamente a execução desse fluxo de trabalho. O senhor pode renomear o gatilho livremente - o identificador permanece inalterado.

O nome de usuário também corresponde ao nome do arquivo no seu repositório do GitHub; portanto, ele também nunca muda.

O que acontece se meu código tiver um bug?

O evento é ignorado e o erro é registrado no gatilho, para que o senhor possa verificar o que deu errado. Uma transformação com falha nunca bloqueia nada mais - seus outros gatilhos, sejam eles personalizados ou integrados, continuam funcionando normalmente.

Onde meu código é executado?

Em um ambiente isolado, separado do restante do aplicativo, com um prazo curto e sem acesso às credenciais da sua loja. Ele só tem acesso à carga útil do evento que o senhor capturou, além do que o senhor obtiver por meio de ctx.shopify ou ctx.fetch.

E se eu editar o arquivo no GitHub e no aplicativo ao mesmo tempo?

Aquilo que for salvo por último prevalece. Ao salvar no aplicativo, as alterações são confirmadas no arquivo, e ao enviar para o ramo conectado, o código armazenado no aplicativo é sobrescrito. Se o senhor trabalha principalmente no seu repositório, considere o editor do aplicativo como de leitura apenas para evitar surpresas.

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

Não. Um gatilho também precisa saber a qual evento Shopify ele está atento, e o arquivo contém apenas código - tentar adivinhar o evento faria com que ele fosse vinculado ao elemento errado. Crie primeiro o gatilho no aplicativo e, em seguida, edite seu arquivo livremente.

Será que ele pode ser acionado por eventos que o aplicativo ainda não recebe?

Não. Um gatilho personalizado monitora os eventos aos quais o aplicativo já está inscrito para a sua loja, o que depende das permissões que você concedeu. Ao conceder permissão para um recurso, seus eventos também ficam disponíveis para gatilhos personalizados. Para qualquer outra coisa, execute-o de acordo com uma programação.

Próximos passos