
🛒 Encomendas duplicadas no WooCommerce: 3 scripts para bloquear ao nível do carrinho
O cliente clicou em «Encomendar» duas vezes e agora há duas encomendas idênticas no painel de administração, com apenas alguns segundos de diferença. O dinheiro foi cobrado duas vezes, o cliente está furioso e você está a lidar com um reembolso.
As encomendas duplicadas não são uma situação hipotética. Cerca de uma em cada três lojas em WooCommerce depara-se com elas, especialmente com alojamento instável ou gateways de pagamento lentos. Mas mesmo num servidor rápido, um utilizador pode voltar a adicionar um produto via URL ou comprar um produto digital gratuito dezenas de vezes.
Reunimos três scripts funcionais que cobrem diferentes cenários de duplicação: desde forçar vendas de unidade única até bloquear adições repetidas por URL. Abaixo encontra uma análise completa com o código.
Porque é que as encomendas são duplicadas no WooCommerce
💡 Visão geral rápida:
- Vai aprender porque é que as encomendas são duplicadas ao nível do carrinho, URL e compra repetida
- Vai instalar um script para forçar vendas de unidade única através de campos meta
- Vai impedir compras repetidas de variações gratuitas (produtos digitais, cupões)
- Vai eliminar a duplicação via URL com
add-to-cartao atualizar a página - Vai testar a proteção e aprender o que mais pode causar duplicados ao nível do servidor
As duplicações de encomendas surgem de três cenários principais.
Primeiro, o utilizador clica em «Encomendar» várias vezes. Isto acontece quando a página está lenta, a pessoa não vê resposta e clica novamente no botão. Em alojamento lento, uma história comum.
Segundo cenário, produtos gratuitos. Se tiver um produto digital gratuito, nada impede um utilizador de o «comprar» dez vezes seguidas. O WooCommerce de origem não controla se este cliente já levou o mesmo produto gratuito antes.
Terceiro, um link direto com o parâmetro ?add-to-cart=123. Atualizou a página do carrinho, o produto foi adicionado novamente. Seguiu um link de uma newsletter duas vezes, duas unidades no carrinho.
Todos os três cenários são resolvidos do lado do servidor através de hooks do WooCommerce. Sem plugins, apenas código.
Método 1: Forçar vendas de unidade única através de campos meta

O primeiro script força o WooCommerce a tratar um produto específico como «vendido individualmente», mesmo que essa caixa de verificação não esteja assinalada nas definições do produto. O controlo é feito através de um campo meta.
Quando o campo meta maximum_allowed_quantity é igual a 1, o filtro woocommerce_is_sold_individually devolve true e o próprio WooCommerce bloqueia a adição de uma segunda unidade ao carrinho. Funciona tanto para produtos simples como para variações.
Adicione o código ao functions.php do seu tema filho ou através do plugin Code Snippets:
1 function sd_woocommerce_is_sold_individually( $return, $product ) { 2 switch ( $product->get_type() ) { 3 case 'variation': 4 if ( $product->get_meta( 'variation_maximum_allowed_quantity' ) == 1 ) { 5 return true; 6 } 7 break; 8 case 'simple': 9 if ( $product->get_meta( 'maximum_allowed_quantity' ) == 1 ) { 10 return true; 11 } 12 break; 13 } 14 return $return; 15 } 16 add_filter( 'woocommerce_is_sold_individually', 'sd_woocommerce_is_sold_individually', 10, 2 );
O que acontece aqui: o hook woocommerce_is_sold_individually é acionado sempre que o WooCommerce verifica se um produto pode ser adicionado ao carrinho mais do que uma vez. A função consulta os campos meta do produto e, se encontrar maximum_allowed_quantity = 1, ativa forçosamente o modo «Vendido Individualmente». Para variações, o campo chama-se variation_maximum_allowed_quantity.
Como aplicar. Entre na edição de qualquer produto ou variação, adicione um campo personalizado com o nome maximum_allowed_quantity (ou variation_maximum_allowed_quantity para uma variação) e o valor 1. Guarde. Já está, agora este produto não pode ser colocado no carrinho duas vezes.
Método 2: Impedir compras repetidas de variações gratuitas
Os produtos digitais gratuitos são a principal lacuna na proteção contra duplicados. O utilizador tem sessão iniciada, o preço do produto é zero, o WooCommerce deixa a encomenda passar sem questionar. Dez encomendas dessas de um cliente, dez entradas idênticas no painel de administração.
O script abaixo verifica através de wc_customer_bought_product() se este utilizador já comprou o mesmo produto antes. Se sim, a adição ao carrinho é bloqueada com um aviso claro.
1 function sd_disable_repeat_purchase_for_free_products( $passed, $product_id, $quantity, $variation_id = 0 ) { 2 $current_user = wp_get_current_user(); 3 $product = $variation_id > 0 ? wc_get_product( $variation_id ) : wc_get_product( $product_id ); 4 $target_id = $variation_id > 0 ? $variation_id : $product_id; 5 6 if ( floatval( $product->get_price() ) == 0 ) { 7 if ( wc_customer_bought_product( $current_user->user_email, $current_user->ID, $target_id ) ) { 8 wc_add_notice( 9 sprintf( __( 'You have already purchased "%s" and cannot purchase it again.', 'sd' ), $product->get_name() ), 10 'error' 11 ); 12 return false; 13 } 14 } 15 return $passed; 16 } 17 add_filter( 'woocommerce_add_to_cart_validation', 'sd_disable_repeat_purchase_for_free_products', 10, 4 );
Após a instalação, o utilizador vê uma mensagem de erro ao tentar adicionar um produto gratuito já comprado ao carrinho. A encomenda em si não é criada.
Duas condições importantes. Primeiro, o cliente deve ter sessão iniciada. Para visitantes, wp_get_current_user() devolve um objeto vazio e a verificação não funcionará. Segundo, o preço do produto deve ser exatamente zero (floatval elimina problemas de formatação). O script não afetará produtos com preço superior a zero.
Método 3: Proteção contra duplicação via URL com add-to-cart
O WooCommerce permite adicionar um produto ao carrinho através de um link direto: /cart/?add-to-cart=123. Conveniente para marketing, mas se o utilizador atualizar a página ou seguir o link novamente, o produto é adicionado outra vez.
Este script interceta o carregamento da página do carrinho ou finalização da compra e, se o produto do parâmetro URL já estiver no carrinho, remove silenciosamente os parâmetros de consulta e redireciona para um URL limpo.
1 function sd_prevent_duplicate_add_to_cart_redirect() { 2 if ( ( is_cart() || is_checkout() ) && isset( $_GET['add-to-cart'] ) ) { 3 $current_url = home_url( add_query_arg( null, null ) ); 4 $product_id = intval( $_GET['add-to-cart'] ); 5 $variation_id = isset( $_GET['variation_id'] ) ? intval( $_GET['variation_id'] ) : 0; 6 7 foreach ( WC()->cart->get_cart() as $cart_item ) { 8 if ( $cart_item['product_id'] == $product_id 9 && ( $variation_id == 0 || $cart_item['variation_id'] == $variation_id ) ) { 10 wp_redirect( remove_query_arg( array( 'add-to-cart', 'variation_id' ), $current_url ) ); 11 exit; 12 } 13 } 14 } 15 } 16 add_action( 'template_redirect', 'sd_prevent_duplicate_add_to_cart_redirect' );
O hook template_redirect é acionado antes de o WordPress começar a renderizar a página. O script verifica se o parâmetro add-to-cart está no URL, procura esse produto no conteúdo do carrinho (WC()->cart->get_cart()) e, se encontrado, faz um wp_redirect para a mesma página sem parâmetros de consulta.
A adição repetida via URL é eliminada. Ao mesmo tempo, a primeira adição (quando o produto ainda não está no carrinho) funciona como habitualmente.
Juntar tudo
Os três scripts não entram em conflito e funcionam de forma independente:
- O primeiro limita a quantidade de um único produto a 1, proteção contra adições múltiplas.
- O segundo bloqueia compras repetidas de produtos gratuitos, proteção contra «cliques repetidos» em brindes.
- O terceiro remove a duplicação via URL, proteção contra adições repetidas acidentais.
Adicione o código através do plugin Code Snippets no WP.org, não diretamente no functions.php do tema. O plugin permite ativar e desativar snippets um a um sem partir o site em caso de erro e não perde o código ao mudar de tema. Crie três snippets separados, é mais fácil depurar assim.
O que mais verificar se os duplicados persistirem
Os scripts acima cobrem duplicados ao nível do carrinho e da finalização da compra. Mas existem mais duas fontes do problema que o código não consegue resolver.
Cache das páginas de carrinho e finalização da compra. Plugins de cache como o WP Rocket ou o LiteSpeed Cache excluem estas páginas por defeito, mas após uma atualização de definições a exclusão pode ser reposta. Verifique: carrinho, finalização da compra e minha conta não devem estar em cache ao nível do plugin, do servidor ou da CDN.
Novas tentativas do gateway de pagamento. Se o gateway (Stripe, PayPal) não receber a confirmação do servidor a tempo, reenvia a notificação e o WooCommerce cria uma segunda encomenda. A causa é geralmente alojamento lento ou uma firewall a bloquear pedidos de callback. Solução: verifique os logs do gateway para envios repetidos de webhooks e certifique-se de que o URL de callback está acessível do exterior.
Como testar a proteção
Depois de instalar os scripts, não deixe de testar cada cenário num site de teste.
Método 1, crie um produto com o campo meta maximum_allowed_quantity = 1 e tente adicionar duas unidades ao carrinho. Apenas uma deve ser adicionada.
Método 2, inicie sessão, compre um produto gratuito e depois tente comprá-lo novamente. Deverá ver uma mensagem de erro.
Método 3, adicione um produto ao carrinho através de um link direto com ?add-to-cart=ID e depois atualize a página. O número de itens no carrinho não deve mudar.
Teste numa instalação separada ou num site de staging. Numa loja ativa, apenas após uma verificação completa.
⁉️🤔 Perguntas frequentes
Porque é que as encomendas são duplicadas se o botão «Encomendar» foi clicado uma vez?
A razão é quase sempre uma resposta lenta do servidor. O utilizador clica no botão, o pedido é enviado, mas a página não atualiza durante vários segundos. A pessoa pensa que não clicou e volta a clicar. Ambos os pedidos chegam ao WooCommerce e são criadas duas encomendas. Os scripts neste artigo não cobrem esta situação; aqui, ajuda a cache do lado do cliente (desativar o botão após o clique) ou a verificação de unicidade da encomenda do lado do servidor através de um token nonce.
Um gateway de pagamento pode criar duplicados por si só?
Sim. Se o gateway não receber um HTTP 200 do seu servidor em resposta a um IPN/webhook, repete o envio. A cada nova tentativa, o WooCommerce pode criar uma nova encomenda. O problema resolve-se acelerando o alojamento e verificando se o URL de callback do gateway não está bloqueado por uma firewall e não requer autenticação HTTP.
Esta proteção bloqueia encomendas repetidas genuínas de um cliente?
Não. Os scripts funcionam na fase de adicionar ao carrinho, não na fase de criação da encomenda. Se um cliente fez deliberadamente uma encomenda e, uma semana depois, uma segunda, os scripts não interferirão. Exceção: método 2, que proíbe a compra repetida de um produto gratuito pelo mesmo utilizador.
É obrigatório usar o Code Snippets ou pode ser colocado no functions.php?
Pode usar o
functions.php, mas recomendamos o Code Snippets. Com um erro de digitação no código dofunctions.phpfica com um ecrã branco e acesso apenas via FTP. O plugin Code Snippets captura erros fatais e desativa automaticamente o snippet problemático, o site mantém-se de pé.
Os plugins para prevenir duplicados ajudam?
Plugins especializados como o WooCommerce Duplicate Order Blocker funcionam a um nível diferente; rastreiam duplicados por IP, email ou impressão digital do navegador na fase de finalização da compra. Isto cobre o cenário de clique duplo que os nossos scripts não cobrem. No entanto, os plugins não resolvem o problema de duplicados via URL add-to-cart e compras repetidas de um produto gratuito. A opção ideal: os scripts deste artigo mais um plugin bloqueador na finalização da compra.
Resumo: três níveis de proteção contra duplicados
Três scripts cobrem três cenários específicos de duplicação de encomendas. Instale todos de uma vez; cada um é responsável pela sua própria área e, juntos, fornecem uma proteção rigorosa ao nível do carrinho.
Se os duplicados ainda aparecerem após a instalação, olhe para o alojamento e para o gateway de pagamento. Um clique duplo no botão «Encomendar» não pode ser resolvido com código ao nível do carrinho; aqui precisa de um plugin bloqueador ou de proteção personalizada do botão via JavaScript.
Teste a proteção num site de teste e depois mova-a para produção. Quinze minutos para instalar três snippets poupam horas a resolver reembolsos.


