Hoppa till innehållet
🛒 Dubblettorder i WooCommerce: 3 skript för blockering på varukorgsnivå

🛒 Dubblettorder i WooCommerce: 3 skript för blockering på varukorgsnivå

Kunden klickade på "Lägg beställning" två gånger, och nu finns två identiska beställningar i adminpanelen med bara några sekunders mellanrum. Pengarna har dragits två gånger, kunden är rasande, och du har en återbetalning att hantera.

Dubblettbeställningar är ingen hypotetisk situation. Ungefär var tredje butik på WooCommerce råkar ut för dem, särskilt med instabil hosting eller långsamma betalväxlar. Men även på en snabb server kan en användare lägga till en produkt igen via URL eller köpa en gratis digital produkt dussintals gånger.

Vi har sammanställt tre fungerande skript som täcker olika dubblettscenarier: från att tvinga fram försäljning av enstaka enheter till att blockera upprepade URL-tillägg. Här följer en komplett genomgång med kod.

Varför beställningar dupliceras i WooCommerce

💡 Snabb översikt:

  • Du får lära dig varför beställningar dupliceras på varukorgs-, URL- och återkommande-köp-nivå
  • Du installerar ett skript för att tvinga fram försäljning av enstaka enheter via metafält
  • Du förhindrar upprepade köp av gratis variationer (digitala varor, kuponger)
  • Du eliminerar duplicering via URL med add-to-cart vid siduppdatering
  • Du testar skyddet och lär dig vad mer som kan orsaka dubbletter på servernivå

Beställningsdubbletter uppstår från tre huvudscenarier.

För det första klickar användaren på "Lägg beställning" flera gånger. Detta händer när sidan laggar och personen inte ser något svar och klickar på knappen igen. På långsam hosting en vanlig historia.

Andra scenariot, gratisprodukter. Om du har en gratis digital produkt finns det inget som hindrar en användare från att "köpa" den tio gånger i rad. WooCommerce spårar inte ur lådan om denna kund har tagit samma gratisprodukt tidigare.

Tredje, en direktlänk med parametern ?add-to-cart=123. Uppdaterade varukorgssidan, produkten lades till igen. Följde en länk från ett nyhetsbrev två gånger, två exemplar i varukorgen.

Alla tre scenarier löses på serversidan via WooCommerce-hooks. Inga plugins, bara kod.

Metod 1: Tvinga försäljning av enstaka enheter via metafält

Det första skriptet tvingar WooCommerce att behandla en specifik produkt som "säljs individuellt", även om den kryssrutan inte är ikryssad i produktinställningarna. Styrning sker via ett metafält.

När metafältet maximum_allowed_quantity är lika med 1 returnerar filtret woocommerce_is_sold_individually true, och WooCommerce själv blockerar att en andra enhet läggs till i varukorgen. Fungerar för både enkla produkter och variationer.

Lägg till koden i ditt barntemas functions.php eller via tillägget Code Snippets:

1function 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}
16add_filter( 'woocommerce_is_sold_individually', 'sd_woocommerce_is_sold_individually', 10, 2 );

Vad som händer här: hooken woocommerce_is_sold_individually körs varje gång WooCommerce kontrollerar om en produkt kan läggas till i varukorgen mer än en gång. Funktionen tittar i produktens metafält och, om den ser maximum_allowed_quantity = 1, aktiverar den tvångsvis läget "Säljs individuellt". För variationer heter fältet variation_maximum_allowed_quantity.

Så här tillämpar du det. Gå in i redigering av valfri produkt eller variation, lägg till ett anpassat fält med namnet maximum_allowed_quantity (eller variation_maximum_allowed_quantity för en variation) och värdet 1. Spara. Klart, nu kan denna produkt inte läggas i varukorgen två gånger.

Metod 2: Förhindra upprepade köp av gratis variationer

Gratis digitala produkter är den största luckan i dubblettskyddet. Användaren är inloggad, produktpriset är noll, WooCommerce släpper igenom beställningen utan frågor. Tio sådana beställningar från en kund, tio identiska poster i adminpanelen.

Skriptet nedan kontrollerar via wc_customer_bought_product() om denna användare har köpt samma produkt tidigare. Om ja blockeras tillägg till varukorgen med ett tydligt meddelande.

1function 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}
17add_filter( 'woocommerce_add_to_cart_validation', 'sd_disable_repeat_purchase_for_free_products', 10, 4 );

Efter installation ser användaren ett felmeddelande när hen försöker lägga till en redan köpt gratisprodukt i varukorgen. Själva beställningen skapas inte.

Två viktiga villkor. För det första måste kunden vara inloggad. För gäster returnerar wp_get_current_user() ett tomt objekt, och kontrollen fungerar inte. För det andra måste produktpriset vara exakt noll (floatval eliminerar formateringsproblem). Skriptet rör inte produkter med ett pris över noll.

Metod 3: Skydd mot duplicering via URL med add-to-cart

WooCommerce tillåter att en produkt läggs till i varukorgen via en direktlänk: /cart/?add-to-cart=123. Bekvämt för marknadsföring, men om användaren uppdaterar sidan eller följer länken igen läggs produkten till igen.

Detta skript fångar upp laddningen av varukorgs- eller kassasidan och, om produkten från URL-parametern redan finns i varukorgen, tar det tyst bort frågeparametrarna och omdirigerar till en ren URL.

1function 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}
16add_action( 'template_redirect', 'sd_prevent_duplicate_add_to_cart_redirect' );

Hooken template_redirect körs innan WordPress börjar rendera sidan. Skriptet kontrollerar om parametern add-to-cart finns i URL:en, letar efter den produkten i varukorgens innehåll (WC()->cart->get_cart()), och om den hittas gör det en wp_redirect till samma sida utan frågeparametrar.

Upprepad tillägg via URL elimineras. Samtidigt fungerar den första tillägget (när produkten ännu inte finns i varukorgen) som vanligt.

Sätta ihop allt

Alla tre skripten krockar inte och fungerar oberoende av varandra:

  • Det första begränsar kvantiteten av en enskild produkt till 1, skydd mot flera tillägg.
  • Det andra blockerar upprepade köp av gratisprodukter, skydd mot "klickspam" av gratisprodukter.
  • Det tredje tar bort duplicering via URL, skydd mot oavsiktliga upprepade tillägg.

Lägg till koden via tillägget Code Snippets på WP.org, inte direkt i temats functions.php. Tillägget låter dig aktivera och inaktivera snippets en och en utan att sajten kraschar vid fel, och förlorar inte kod när du byter tema. Skapa tre separata snippets, det är lättare att felsöka då.

Vad mer att kontrollera om dubbletter kvarstår

Skripten ovan täcker dubbletter på varukorgs- och kassanivå. Men det finns ytterligare två källor till problemet som kod inte kan åtgärda.

Cachning av varukorgs- och kassasidor. Cachningstillägg som WP Rocket eller LiteSpeed Cache exkluderar dessa sidor som standard, men efter en inställningsuppdatering kan exkluderingen återställas. Kontrollera: varukorg, kassa och mitt konto får inte cachas på tilläggsnivå, servernivå eller i CDN:t.

Återförsök från betalväxeln. Om betalväxeln (Stripe, PayPal) inte får bekräftelse från servern i tid skickar den notifieringen igen, och WooCommerce skapar en andra beställning. Orsaken är vanligtvis långsam hosting eller en brandvägg som blockerar callback-anrop. Lösning: kontrollera betalväxelns loggar för upprepade webhook-utskick och se till att callback-URL:en är tillgänglig utifrån.

Hur man testar skyddet

Efter installation av skripten, se till att testa varje scenario på en testsajt.

Metod 1, skapa en produkt med metafältet maximum_allowed_quantity = 1 och försök lägga till två enheter i varukorgen. Endast en ska läggas till.

Metod 2, logga in, köp en gratisprodukt, försök sedan köpa den igen. Du bör se ett felmeddelande.

Metod 3, lägg till en produkt i varukorgen via en direktlänk med ?add-to-cart=ID, uppdatera sedan sidan. Antalet artiklar i varukorgen ska inte ändras.

Testa i en separat installation eller på en staging-sajt. På en livebutik, först efter en fullständig kontroll.

⁉️🤔 Vanliga frågor

Varför dupliceras beställningar om knappen "Lägg beställning" klickades en gång?

Orsaken är nästan alltid ett långsamt serversvar. Användaren klickar på knappen, förfrågan skickas, men sidan uppdateras inte på flera sekunder. Personen tror att de inte klickade och klickar igen. Båda förfrågningarna når WooCommerce, och två beställningar skapas. Skripten i denna artikel fångar inte denna situation; här hjälper cachning på klientsidan (inaktivera knapp efter klick) eller unikhetskontroll av beställning på serversidan via en nonce-token.

Kan en betalväxel skapa dubbletter på egen hand?

Ja. Om betalväxeln inte får ett HTTP 200 från din server som svar på en IPN/webhook upprepar den utskicket. Vid varje nytt försök kan WooCommerce skapa en ny beställning. Problemet löses genom att snabba upp hostingen och kontrollera att betalväxelns callback-URL inte blockeras av en brandvägg och inte kräver HTTP-autentisering.

Blockerar detta skydd genuina återkommande beställningar från en kund?

Nej. Skripten fungerar i stadiet för tillägg till varukorg, inte i stadiet för att skapa beställning. Om en kund medvetet la en beställning, och en vecka senare en andra, kommer skripten inte att störa. Undantag: metod 2, som förbjuder ett upprepat köp av en gratisprodukt av samma användare.

Är det obligatoriskt att använda Code Snippets, eller kan det ligga i functions.php?

Du kan använda functions.php, men vi rekommenderar Code Snippets. Med ett stavfel i functions.php-kod får du en vit skärm och åtkomst endast via FTP. Tillägget Code Snippets fångar fatala fel och inaktiverar automatiskt den problematiska snippeten, sajten håller sig på benen.

Hjälper tillägg för att förhindra dubbletter?

Specialiserade tillägg som WooCommerce Duplicate Order Blocker fungerar på en annan nivå; de spårar dubbletter via IP, e-post eller webbläsarens fingeravtryck i kassasteget. Detta täcker dubbelklickscenariot som våra skript inte täcker. Däremot löser tillägg inte problemet med dubbletter via add-to-cart URL och upprepade köp av en gratisprodukt. Det ideala alternativet: skripten från denna artikel plus ett blockertillägg i kassan.

Sammanfattning: tre nivåer av dubblettskydd

Tre skript täcker tre specifika scenarier för beställningsduplicering. Installera alla på en gång; var och en ansvarar för sitt eget område, och tillsammans ger de ett tätt skydd på varukorgsnivå.

Om dubbletter fortfarande dyker upp efter installation, titta mot hosting och betalväxeln. Ett dubbelklick på knappen "Lägg beställning" kan inte botas med kod på varukorgsnivå; här behöver du antingen ett blockertillägg eller anpassat knappskydd via JavaScript.

Testa skyddet på en testsajt, flytta det sedan till produktion. Femton minuter för att installera tre snippets sparar timmar av arbete med att reda ut återbetalningar.