Kits Nativos da Plataforma
O Kit Nativo da Plataforma é a implementação de kit usada quando um produto principal representa um conjunto de itens que precisam ser comprados juntos. Nesse modelo, a compra não depende apenas do SKU do produto principal: a página precisa resolver também o SKU de cada item interno do kit antes de enviar a compra ao carrinho.
Este guia explica a lógica de kit nativo da plataforma sem depender de acesso à estrutura padrão do template. Os exemplos de código abaixo usam a semântica esperada pelo fluxo de kit: bundle, product-block-bundle, data-bundle-section, data-product-box, data-quickview-type, data-main-bundle-product-id e data-bundle-add.
📘 Demonstração do componente
Resumo técnico
Seção intitulada “Resumo técnico”Se você precisar resumir a implementação do kit nativo em poucas regras, são estas:
- O produto principal precisa ser tratado como kit nativo da plataforma.
- A página precisa conhecer os produtos internos do kit.
- Cada item interno precisa resolver um
skuválido antes da compra final. - A compra envia o SKU principal do kit e a lista
bundle_skus[]. - Se qualquer item exigir personalização, a compra em bloco deve ser bloqueada.
Visão geral da implementação
Seção intitulada “Visão geral da implementação”Uma implementação correta de kit nativo precisa resolver quatro partes:
- Liquid: identifica que o produto é um kit, carrega os produtos internos e renderiza um bloco para cada item.
- Seleção de variantes: garante que cada item interno exponha um
name="sku"com o SKU escolhido. - JavaScript de compra: lê o SKU principal, coleta os SKUs internos e monta
bundle_skus[]. - Carrinho: recebe
POST /carrinho/adicionarcomsku,quantityebundle_skus[].
O quickview pode ser usado para carregar o formulário dos itens internos sob demanda, mas não é obrigatório. O requisito obrigatório é que, no momento do clique em data-bundle-add, todos os blocos data-product-box tenham um name="sku" válido.
O que é um kit nativo da plataforma
Seção intitulada “O que é um kit nativo da plataforma”Um kit nativo da plataforma é um produto principal que representa um conjunto de itens comprados em uma única operação. Tecnicamente, esse produto é identificado na plataforma como product_type == 'bundle'. Ele não é comprado como um item simples: a compra só é válida quando o frontend consegue montar o conjunto completo da operação.
Na prática, o kit nativo depende de três elementos:
- Um produto principal do kit;
- Uma lista de produtos internos;
- Uma forma de resolver o SKU selecionado de cada item interno.
Quando usar a lógica de kit nativo
Seção intitulada “Quando usar a lógica de kit nativo”A lógica de kit nativo deve ser usada quando:
- A PDP representa um kit como produto principal;
- Os itens internos fazem parte da composição obrigatória da compra;
- A escolha de variante dos itens internos é necessária;
- O carrinho precisa receber uma compra consolidada do kit.
Se a necessidade for apenas sugerir produtos opcionais, o fluxo correto não é kit nativo, e sim um recurso como compre junto.
Pré-requisitos
Seção intitulada “Pré-requisitos”Antes de implementar o kit nativo, valide se estes elementos existem no seu contexto:
| Requisito | Motivo |
|---|---|
| identificação de que o produto atual é um kit nativo | ativa o fluxo correto da PDP |
| lista dos produtos internos do kit | define quais itens compõem a compra |
| SKU principal do kit | necessário para o payload final |
| dados suficientes para selecionar a variante de cada item interno | sem isso não é possível gerar bundle_skus[] |
| regra clara para itens com personalização | define quando a compra deve ser bloqueada |
Regras funcionais do kit nativo
Seção intitulada “Regras funcionais do kit nativo”A implementação do kit nativo precisa respeitar estas regras:
- O produto principal deve entrar em um fluxo específico de kit nativo.
- A página deve exibir os produtos internos do kit nativo.
- Cada item interno precisa permitir resolver uma variante válida.
- A compra do kit só pode acontecer depois que todos os SKUs internos forem resolvidos.
- O carrinho deve receber o SKU principal do kit e a lista
bundle_skus[]. - Se qualquer item do kit exigir personalização, a compra em bloco deve ser bloqueada.
- O kit nativo não deve ser tratado como uma simples extensão da compra padrão de um produto comum.
Dados mínimos necessários
Seção intitulada “Dados mínimos necessários”Para implementar o kit nativo corretamente, a lógica de frontend precisa ter acesso, no mínimo, aos seguintes dados:
| Dado | Uso |
|---|---|
| indicador de que o produto é kit nativo | ativa o fluxo de kit |
| lista dos produtos internos | define os itens que precisam participar da compra |
| SKU principal do kit | preenche o campo sku do payload |
| SKU selecionado de cada item interno | preenche bundle_skus[] |
| tags ou metadados de personalização | permitem bloquear a compra em bloco quando necessário |
Fluxo de compra do kit nativo
Seção intitulada “Fluxo de compra do kit nativo”O fluxo funcional do kit nativo pode ser resumido assim:
- identificar que o produto atual é um kit nativo;
- trocar a compra comum pela compra de kit nativo;
- carregar ou renderizar os produtos internos;
- permitir a seleção de variante de cada item interno;
- resolver o
skude cada item; - montar o payload do carrinho;
- enviar a compra;
- abrir o carrinho em caso de sucesso.
Contrato de compra do kit nativo
Seção intitulada “Contrato de compra do kit nativo”Na lógica de kit nativo, o payload enviado ao carrinho contém:
sku: SKU do produto principal do kit;quantity: quantidade do kit;bundle_skus[]: lista dos SKUs selecionados dos produtos internos.
Exemplo do payload:
sku=KIT-PRINCIPALquantity=1bundle_skus[]=SKU-ITEM-1bundle_skus[]=SKU-ITEM-2bundle_skus[]=SKU-ITEM-3Esse envio é feito para:
POST /carrinho/adicionarcom Content-Type: application/x-www-form-urlencoded.
Comportamento esperado da resposta
Seção intitulada “Comportamento esperado da resposta”A lógica de compra do kit nativo deve prever estes cenários:
- Se a resposta vier com
202, o frontend precisa respeitar oRetry-Aftere tentar novamente; - Se a resposta vier com erro, o botão do kit deve entrar em estado de falha ou indisponibilidade temporária;
- Se a resposta for bem-sucedida, o carrinho deve ser aberto ou atualizado.
Regra de personalização
Seção intitulada “Regra de personalização”Se qualquer item interno do kit exigir personalização, a compra em bloco deve ser desabilitada.
Essa regra existe porque, nesse caso, a compra do item depende de uma etapa extra de preenchimento ou validação que não pode ser resolvida apenas com a consolidação de SKUs.
Na prática, isso significa:
- O kit continua sendo exibido;
- Os itens internos continuam visíveis;
- O botão final do kit fica indisponível;
- O usuário precisa adicionar os itens individualmente.
Diferença entre kit nativo e compre junto
Seção intitulada “Diferença entre kit nativo e compre junto”Esses dois fluxos agrupam produtos, mas não são a mesma funcionalidade.
| Recurso | Como funciona | Endpoint principal |
|---|---|---|
kit nativo da plataforma (bundle) | produto principal com compra consolidada por SKU principal + bundle_skus[] | POST /carrinho/adicionar |
| compre junto | seleção manual de produtos relacionados, normalmente enviada como lista de items[] | POST /carrinho/adicionar/kit |
Se a dúvida for sobre um kit cadastrado como produto principal, o fluxo correto é o de kit nativo.
O que o kit nativo não faz
Seção intitulada “O que o kit nativo não faz”O kit nativo não deve ser tratado como solução genérica para qualquer agrupamento de produtos.
Na implementação de kit nativo, ele não faz estas coisas automaticamente:
- Não substitui o fluxo de compre junto;
- Não resolve personalização dos itens internos;
- Não dispensa a seleção de variante dos produtos internos;
- Não reutiliza a compra simples de um produto comum sem adaptação;
- Não usa o endpoint de
items[]do compre junto.
Estrutura mínima recomendada no frontend
Seção intitulada “Estrutura mínima recomendada no frontend”Mesmo fora de uma estrutura padrão, uma implementação de kit nativo precisa manter esta separação lógica:
- Um container principal do kit;
- Um campo com o SKU principal;
- Uma lista de blocos dos itens internos;
- Um mecanismo para resolver a variante de cada item interno;
- Um botão final que consolida os SKUs internos e dispara a compra.
Checklist mínimo de marcação
Seção intitulada “Checklist mínimo de marcação”Se você estiver construindo o kit manualmente, o frontend precisa conseguir localizar:
- Um container principal do kit;
- Um input oculto com o SKU principal;
- Um bloco por item interno;
- Um input
name="sku"resolvido dentro de cada item interno; - Um botão final para adicionar o kit;
- Uma forma de bloquear ou sinalizar kits com personalização.
Contrato mínimo entre template e JavaScript
Seção intitulada “Contrato mínimo entre template e JavaScript”Mesmo em uma implementação customizada, o kit nativo precisa preservar um contrato mínimo entre a marcação HTML e a lógica de compra.
Sem esse contrato, o JavaScript não consegue identificar o kit nem montar bundle_skus[] de forma confiável.
| Elemento | Papel na compra |
|---|---|
| container principal do kit | delimita o contexto do kit |
| input com SKU principal | fornece o sku do produto de kit nativo |
| bloco de item interno | delimita cada produto que compõe o kit |
input name="sku" dentro de cada item | fornece o SKU efetivamente escolhido daquele item |
| botão final do kit | dispara a rotina de adição ao carrinho |
Se qualquer um desses pontos estiver ausente, a compra do kit nativo fica incompleta ou inconsistente.
Conteúdo necessário no container principal do kit
Seção intitulada “Conteúdo necessário no container principal do kit”A sua implementação provavelmente terá um template, partial ou componente principal responsável por renderizar o kit nativo. Independentemente do nome desse arquivo, ele precisa concentrar o estado principal da compra.
Esse container principal deve conter, no mínimo:
- A identificação de que aquele bloco representa um kit nativo;
- O SKU principal do kit em um input acessível ao JavaScript;
- A lista dos itens internos que compõem o kit;
- A renderização ou carregamento dos blocos de item interno;
- A validação de bloqueio por personalização;
- O botão final de compra do kit.
Em termos funcionais, esse bloco principal é responsável por responder estas perguntas:
- Este produto deve usar fluxo de kit nativo?
- Qual é o SKU principal do kit?
- Quais são os produtos internos que participam da compra?
- A compra do kit está liberada ou bloqueada?
- Onde está o botão que dispara a adição ao carrinho?
Se esse bloco não expuser essas informações, a lógica de compra do kit fica sem contexto suficiente para funcionar.
Exemplo do container principal em Liquid
Seção intitulada “Exemplo do container principal em Liquid”Neste exemplo, {% load_products %} carrega em products os produtos internos do kit a partir dos IDs de product.bundle_children. A variável has_customization é calculada antes da renderização dos itens para decidir se o kit pode ser comprado em bloco.
{% if product.bundle_children.size > 0 %} <div class="bundle" data-bundle-section> <input type="hidden" value="{{ product.variants[0].sku }}" data-main-bundle-product-id>
{% assign bundle_product_ids = '' %} {% for item in product.bundle_children %} {% if forloop.first %} {% assign bundle_product_ids = item.product_id %} {% else %} {% assign bundle_product_ids = bundle_product_ids | append: ',' | append: item.product_id %} {% endif %} {% endfor %} {% assign bundle_product_ids = bundle_product_ids | split: ',' | uniq | join: ',' %} {% load_products ids: bundle_product_ids %} {% assign has_customization = false %}
{% for bundle_product in products %} {% assign customs_tag = bundle_product.tags | where: 'type', 'personalizacao' | first %} {% if customs_tag and customs_tag != blank %} {% assign has_customization = true %} {% break %} {% endif %} {% endfor %}
{% for item in product.bundle_children %} {% assign item_id = item.product_id %} {% assign item_quantity = item.quantity %} {% assign bundle_product = products | where: "id", item_id | first %} {% if item_quantity > 0 %} {% for i in (1..item_quantity) %} {% render 'partials/content/product/bundle/product_block_bundle', product: bundle_product, show_short_description: false, has_customization: has_customization %} {% endfor %} {% endif %} {% endfor %}
{% if has_customization %} <p class="custom-message">Este kit contém produtos com personalização. Adicione-os individualmente ao carrinho.</p> <button type="button" class="button-default -unavailable" data-bundle-add> Indisponível </button> {% else %} <button type="button" class="button-default" data-bundle-add> Adicionar kit no carrinho </button> {% endif %} </div>{% endif %}Nesse bloco, os pontos mais importantes do contrato são:
data-bundle-sectionno container principal;data-main-bundle-product-idcom o SKU principal do kit;- Renderização repetida dos itens internos;
data-bundle-addno botão final;- Bloqueio explícito quando existe personalização.
Conteúdo necessário em cada bloco de item do kit
Seção intitulada “Conteúdo necessário em cada bloco de item do kit”A sua implementação também precisa de um bloco para cada item interno do kit nativo. Novamente, o nome do arquivo pode variar, mas a responsabilidade funcional é a mesma.
Cada bloco de item interno deve conter, no mínimo:
- Identificação do produto interno;
- Nome e mídia do item;
- Área para seleção de variante ou atributos;
- Lógica para resolver a variante escolhida;
- Um input
name="sku"com o SKU final daquele item, ou uma estrutura que permita ao JavaScript preencher esse valor.
Na prática, cada bloco de item precisa deixar o produto interno pronto para responder:
- Qual item do kit está sendo exibido?
- Qual variante o usuário escolheu?
- Qual SKU corresponde a essa escolha?
- Esse SKU está disponível para leitura no momento da compra?
Se a resposta para a última pergunta for não, o kit não terá como montar bundle_skus[] corretamente.
Exemplo do bloco de item interno em Liquid
Seção intitulada “Exemplo do bloco de item interno em Liquid”Neste exemplo, has_customization é recebido do container principal do kit. A variável imgs_without_lazy representa quantas imagens devem carregar sem lazy loading; quando ela não existir no contexto da loja, o snippet define 0 como padrão.
{% assign image_urls = product.images | map: 'url' | uniq %}
{% assign img_limit = 1 %}{% assign imgs_without_lazy = imgs_without_lazy | default: 0 %}
{% assign short_description = product.description %}{% if product.description contains '<hr/>' %} {% assign short_description = product.description | split: '<hr/>' | first %}{% endif %}
<div class="product-block-bundle" {% unless has_customization %} data-product-box="{{ product.id }}" data-quickview-type="bundle" {% endunless %}> <div class="heading"> {% if has_customization %} <a href="{{ product.url }}" aria-label="{{ product.name }}"> {% endif %}
<div class="images"> <figure class="image -square"> {% for image in image_urls limit: img_limit %} {% capture data_srcset %} {{ image | resize: '350x' }} 350w, {{ image | resize: '420x' }} 420w, {{ image | resize: '480x' }} 480w, {{ image | resize: '767x' }} 767w {% endcapture %}
{% capture data_sizes %} (max-width: 350px) 350px, (max-width: 480px) 480px, (max-width: 991px) 350px, (max-width: 1280px) 420px, (max-width: 1440px) 480px, 767px {% endcapture %}
{% if forloop.index <= imgs_without_lazy %} <img srcset="{{ data_srcset | strip_newlines | strip }}" sizes="{{ data_sizes | strip_newlines | strip }}" alt="Foto do produto {{ product.name }}"/> {% else %} <img class="lazy" loading="lazy" data-srcset="{{ data_srcset | strip_newlines | strip }}" sizes="{{ data_sizes | strip_newlines | strip }}" alt="Foto do produto {{ product.name }}"/> {% endif %} {% endfor %} </figure> </div>
<div class="infos"> <h3 class="name"> {{ product.name }} </h3> </div>
{% if has_customization %} </a> {% endif %} </div>
{% if show_short_description != blank and short_description != blank %} <div class="description"> {{ short_description }} </div> {% endif %}</div>Esse exemplo mostra dois comportamentos importantes:
- Quando o kit pode ser comprado em bloco, o item recebe
data-product-boxedata-quickview-type="bundle"; - Quando existe personalização, esse item deixa de participar do fluxo de compra em bloco e vira apenas um link para a PDP do produto.
Cenários de implementação
Seção intitulada “Cenários de implementação”Implementação com quickview
Seção intitulada “Implementação com quickview”Esse é o cenário em que o formulário dos itens internos é carregado sob demanda.
O fluxo é este:
- o bloco do item é renderizado com
data-product-boxedata-quickview-type="bundle"; - o JavaScript observa esse bloco;
- quando o item entra em viewport, o frontend carrega o formulário de quickview;
- o formulário é anexado dentro do próprio
.product-block-bundle; - esse formulário passa a expor
name="sku"para a compra final do kit.
Exemplo de marcação para quickview do kit nativo
Seção intitulada “Exemplo de marcação para quickview do kit nativo”<div class="product-block-bundle" data-product-box="{{ product.id }}" data-quickview-type="bundle"> <div class="heading"> <div class="images"> <figure class="image -square"> {% assign image_urls = product.images | map: 'url' | uniq %} {% for image in image_urls limit: 1 %} {% capture data_srcset %} {{ image | resize: '350x' }} 350w, {{ image | resize: '420x' }} 420w, {{ image | resize: '480x' }} 480w, {{ image | resize: '767x' }} 767w {% endcapture %}
{% capture data_sizes %} (max-width: 350px) 350px, (max-width: 480px) 480px, (max-width: 991px) 350px, (max-width: 1280px) 420px, (max-width: 1440px) 480px, 767px {% endcapture %}
<img srcset="{{ data_srcset | strip_newlines | strip }}" sizes="{{ data_sizes | strip_newlines | strip }}" alt="Foto do produto {{ product.name }}"/> {% endfor %} </figure> </div>
<div class="infos"> <h3 class="name"> {{ product.name }} </h3> </div> </div></div>Nesse cenário, o formulário não precisa estar presente no HTML inicial. A rotina de quickview o insere dentro do elemento marcado com data-product-box.
Exemplo do carregamento do quickview em JavaScript
Seção intitulada “Exemplo do carregamento do quickview em JavaScript”Neste exemplo, bundleConfig representa as configurações do tema para o formulário do item interno, como exibir botão, usar dropdown e aplicar variação visual.
const QuickviewBundle = { bundleConfig: {},
showButton: false, dropdown: false, style: '-default',
handleBundleForm: async function(product, id) { const isBundle = true; QuickviewBundle.showButton = QuickviewBundle.bundleConfig.showButton || false; QuickviewBundle.dropdown = QuickviewBundle.bundleConfig.dropdown || false; QuickviewBundle.style = QuickviewBundle.bundleConfig.style || '-default';
// getQuickviewForm deve ser importado ou exposto pelo módulo de utilidades do tema. const form = await getQuickviewForm(id, '', QuickviewBundle.dropdown, QuickviewBundle.showButton, QuickviewBundle.style, isBundle);
if (!form) { return; }
const productForm = product.querySelector('form.add-to-cart'); if (!productForm) { product.appendChild(form);
// ProductPurchase é o objeto responsável por inicializar seleção de variantes e compra do formulário inserido. window.ProductPurchase.init(); } },};O efeito prático desse fluxo é: cada .product-block-bundle passa a ter, dentro de si, um form.add-to-cart com o name="sku" que será lido na compra do kit nativo.
Implementação sem quickview
Seção intitulada “Implementação sem quickview”Você também pode implementar o kit nativo sem quickview.
Nesse cenário:
- Cada item do kit já precisa renderizar o formulário de compra diretamente na PDP;
- Esse formulário precisa manter o mesmo contrato de leitura do fluxo padrão;
- No clique final, o kit nativo continua lendo
name="sku"dentro de cada item interno.
O ponto importante é que o quickview não é obrigatório para a lógica do kit nativo. O que é obrigatório é existir, em cada item interno, uma forma confiável de obter o SKU escolhido no momento da compra.
Se você não usar quickview, a recomendação é manter a mesma organização semântica do bloco do item e garantir que o formulário de compra fique dentro do próprio elemento marcado com data-product-box.
Exemplo de item do kit nativo sem quickview mantendo o mesmo contrato
Seção intitulada “Exemplo de item do kit nativo sem quickview mantendo o mesmo contrato”<div class="product-block-bundle" data-product-box="{{ product.id }}"> <div class="heading"> <div class="images"> <figure class="image -square"> {% assign image_urls = product.images | map: 'url' | uniq %} {% for image in image_urls limit: 1 %} {% capture data_srcset %} {{ image | resize: '350x' }} 350w, {{ image | resize: '420x' }} 420w, {{ image | resize: '480x' }} 480w, {{ image | resize: '767x' }} 767w {% endcapture %}
{% capture data_sizes %} (max-width: 350px) 350px, (max-width: 480px) 480px, (max-width: 991px) 350px, (max-width: 1280px) 420px, (max-width: 1440px) 480px, 767px {% endcapture %}
<img srcset="{{ data_srcset | strip_newlines | strip }}" sizes="{{ data_sizes | strip_newlines | strip }}" alt="Foto do produto {{ product.name }}"/> {% endfor %} </figure> </div>
<div class="infos"> <h3 class="name"> {{ product.name }} </h3> </div> </div>
{% comment %} Renderize aqui o formulário de compra do produto interno. Esse formulário precisa gerar um input name="sku" com o SKU escolhido. O formulário pode ser o mesmo usado na compra comum, desde que fique dentro de data-product-box. {% endcomment %}</div>A diferença principal nesse caso é que o formulário já vem renderizado de imediato, em vez de ser injetado depois. O contrato da compra, porém, continua o mesmo: o JavaScript do kit nativo precisa encontrar name="sku" dentro de cada item.
O que o JavaScript faz na compra do kit nativo
Seção intitulada “O que o JavaScript faz na compra do kit nativo”A parte de JavaScript do kit nativo tem três responsabilidades principais:
- ouvir o clique do botão final do kit;
- localizar o SKU principal e os SKUs dos itens internos;
- enviar a compra ao carrinho e tratar retry, erro e sucesso.
Exemplo do disparo da compra do kit nativo
Seção intitulada “Exemplo do disparo da compra do kit nativo”Esse é o comportamento da camada que observa o botão final do kit e delega a compra para a store.
const BundleSelection = { handleBundleSubmit: function() { const bundleEl = document.querySelector('[data-bundle-section]'); if (!bundleEl) return;
const button = bundleEl.querySelector('[data-bundle-add]'); if (!button) return;
button.addEventListener('click', event => { event.preventDefault();
// Store é o objeto responsável por centralizar os fluxos de compra. Store.addProduct(bundleEl, bundleEl.parentElement); }); },
init: function() { BundleSelection.handleBundleSubmit(); }};Responsabilidades da camada de compra
Seção intitulada “Responsabilidades da camada de compra”A camada de compra do frontend precisa executar esta sequência:
- localizar o container principal do kit;
- localizar todos os blocos dos itens internos;
- ler o
name="sku"de cada item; - montar a lista
bundle_skus[]; - ler o SKU principal do kit;
- montar o payload da compra;
- enviar
POST /carrinho/adicionar; - tratar retry, erro e sucesso.
Exemplo completo da rotina de compra do kit nativo
Seção intitulada “Exemplo completo da rotina de compra do kit nativo”addBundle: async function(form, parent) { let bundle_skus = [];
const bundleProducts = form.querySelectorAll('[data-product-box]'); bundleProducts.forEach(product => { bundle_skus.push(product.querySelector('[name="sku"]').value); });
const bundleObj = { sku: document.querySelector('[data-main-bundle-product-id]').value, quantity: 1, bundle_skus };
let formBody = []; for (const key in bundleObj) { if (bundleObj.hasOwnProperty(key)) { const value = bundleObj[key];
if (key === 'bundle_skus' && Array.isArray(value)) { value.forEach(item => { formBody.push(`${encodeURIComponent(key)}[]=${encodeURIComponent(item)}`); }); } else { const encodedValue = Array.isArray(value) ? value.map(item => encodeURIComponent(item)).join(',') : encodeURIComponent(value); formBody.push(`${encodeURIComponent(key)}=${encodedValue}`); } } }
formBody = formBody.join('&');
try { while (true) { const response = await fetch('/carrinho/adicionar', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', 'Accept': 'application/json, text/javascript, */*; q=0.01', }, body: formBody, });
if (response.status === 202) { const retryAfter = response.headers.get('Retry-After'); const delay = retryAfter ? parseInt(retryAfter, 10) : 3000; await new Promise(resolve => setTimeout(resolve, delay)); } else { if (!response.ok) { const button = form.querySelector('[data-bundle-add]'); if (button) { button.classList.add('-unavailable');
const innerHTML = button.innerHTML; button.innerHTML = 'Erro ao adicionar no carrinho';
setTimeout(() => { button.classList.remove('-unavailable'); button.innerHTML = innerHTML; }, 2000); }
return; }
// CartDrawer é o objeto responsável por abrir ou atualizar o carrinho lateral. CartDrawer.show(); break; } } } catch (error) { const button = form.querySelector('[data-bundle-add]'); if (button) { button.classList.add('-unavailable');
const innerHTML = button.innerHTML; button.innerHTML = 'Erro ao adicionar no carrinho';
setTimeout(() => { button.classList.remove('-unavailable'); button.innerHTML = innerHTML; }, 2000); } }},Esse exemplo mostra a lógica esperada para a compra do kit nativo:
- Leitura de
[data-product-box]; - Leitura de
name="sku"dentro de cada item; - Leitura de
[data-main-bundle-product-id]; - Serialização manual de
bundle_skus[]; POST /carrinho/adicionar;- Tratamento de
202com retry; - Fallback visual no botão em caso de erro;
- Abertura do Cart Drawer em caso de sucesso.
O ponto mais importante dessa compra é este: o JavaScript não “descobre” sozinho quais variantes usar. Ele depende de cada item interno já ter resolvido e preenchido corretamente seu name="sku".
Se um item interno não tiver name="sku", ou se esse valor estiver vazio, o kit nativo deixa de ter dados suficientes para uma compra correta.
O que muda quando não existe quickview
Seção intitulada “O que muda quando não existe quickview”Sem quickview, a camada de compra continua com a mesma responsabilidade final: ler o SKU principal e todos os bundle_skus[].
O que muda é a origem desse name="sku" em cada item interno:
- Com quickview, ele costuma ser preenchido por um formulário carregado dinamicamente;
- Sem quickview, ele precisa vir do formulário já renderizado dentro do próprio item.
Ou seja: remover quickview não muda o contrato da compra. Muda apenas quem resolve e expõe o sku de cada item.
Estados de interface que o kit nativo precisa prever
Seção intitulada “Estados de interface que o kit nativo precisa prever”Além da montagem do payload, a implementação do kit precisa prever estados claros de interface:
- Kit carregando os itens internos;
- Item interno aguardando carregamento ou seleção de variante;
- Item interno com SKU resolvido;
- Kit bloqueado por personalização;
- Kit em processamento de compra;
- Kit com erro de adição;
- Kit adicionado com sucesso.
Documentar esses estados ajuda a evitar implementações incompletas que resolvem apenas o payload, mas deixam falhas de experiência e validação.
Ordem recomendada de implementação
Seção intitulada “Ordem recomendada de implementação”Se você estiver implementando um kit nativo do zero, a sequência recomendada é:
- validar se o produto deve entrar no fluxo de kit nativo;
- garantir que os produtos internos estejam disponíveis na PDP;
- definir se a seleção de variante será feita com quickview ou inline;
- renderizar o container principal do kit;
- renderizar os blocos dos itens internos;
- garantir que cada item resolva e exponha seu
name="sku"; - bloquear a compra em bloco se houver personalização;
- consolidar o SKU principal do kit com os SKUs internos;
- enviar o payload ao carrinho;
- tratar sucesso, erro e retry.
Problemas comuns
Seção intitulada “Problemas comuns”Por que o botão do kit fica indisponível?
Seção intitulada “Por que o botão do kit fica indisponível?”O motivo mais comum é existir personalização em algum item interno do kit nativo.
Por que o kit não adiciona no carrinho?
Seção intitulada “Por que o kit não adiciona no carrinho?”Verifique se todos os itens internos do kit têm name="sku" preenchido corretamente no momento do clique.
O kit usa /carrinho/adicionar ou /carrinho/adicionar/kit?
Seção intitulada “O kit usa /carrinho/adicionar ou /carrinho/adicionar/kit?”O kit nativo usa POST /carrinho/adicionar. O fluxo de POST /carrinho/adicionar/kit pertence ao compre junto.
O kit nativo precisa de quickview?
Seção intitulada “O kit nativo precisa de quickview?”Não obrigatoriamente. O quickview é apenas uma estratégia de carregamento da seleção dos itens internos. O requisito real é conseguir resolver o SKU de cada item antes da compra final.
O que precisa existir no bloco principal do kit?
Seção intitulada “O que precisa existir no bloco principal do kit?”No mínimo, a identificação do kit nativo, o SKU principal, os itens internos carregados, a validação de bloqueio e o botão final de compra.
O que precisa existir em cada bloco de item do kit?
Seção intitulada “O que precisa existir em cada bloco de item do kit?”No mínimo, a identificação do item, a seleção de variante e uma forma confiável de disponibilizar o name="sku" final daquele item.
Boas práticas
Seção intitulada “Boas práticas”- Não trate o kit como uma simples variação do botão de compra padrão.
- Não misture kit nativo com compre junto.
- Não esconda o contrato do payload do kit nativo.
- Não altere os seletores principais do fluxo sem ajustar a camada de compra.
- Sempre documente onde o
name="sku"é resolvido em cada item interno. - Sempre teste o fluxo com e sem quickview.
- Se remover quickview, mantenha a mesma lógica de leitura dentro de
data-product-box.