
🛒 Päällekkäiset tilaukset WooCommercessa: 3 skriptiä estämiseen ostoskoritasolla
Asiakas klikkasi "Tilaa" kahdesti, ja nyt hallintapaneelissa on kaksi identtistä tilausta vain parin sekunnin välein. Rahat veloitettiin kahdesti, asiakas on raivoissaan, ja sinä hoidat palautusta.
Päällekkäiset tilaukset eivät ole hypoteettinen tilanne. Noin joka kolmas WooCommerce-verkkokauppa törmää niihin, erityisesti epävakaan hostingin tai hitaiden maksuyhdyskäytävien kanssa. Mutta nopeallakin palvelimella käyttäjä voi lisätä tuotteen uudelleen URL:n kautta tai ostaa ilmaisen digituotteen kymmeniä kertoja.
Kokosimme kolme toimivaa skriptiä, jotka kattavat eri kahdentumisskenaariot: yksittäismyynnin pakottamisesta toistuvien URL-lisäysten estämiseen. Alla on täydellinen erittely koodeineen.
Miksi tilaukset kahdentuvat WooCommercessa
💡 Pikakatsaus:
- Opit, miksi tilaukset kahdentuvat ostoskorin, URL:n ja toistuvan oston tasolla
- Asennat skriptin pakottamaan yksittäismyynnin metakenttien avulla
- Estät ilmaisten variaatioiden (digituotteet, kupongit) toistuvat ostot
- Poistat kahdentumisen URL:n kautta
add-to-cart-parametrilla sivun päivityksessä - Testaat suojauksen ja opit, mikä muu voi aiheuttaa kahdentumia palvelintasolla
Tilausten kahdentumat syntyvät kolmesta pääskenaariosta.
Ensimmäinen: käyttäjä klikkaa "Tilaa"-painiketta useita kertoja. Näin käy, kun sivu lagaa eikä henkilö näe vastetta ja klikkaa painiketta uudelleen. Hitaalla hostingilla tämä on tavallinen tarina.
Toinen skenaario: ilmaiset tuotteet. Jos sinulla on ilmainen digituote, mikään ei estä yhtä käyttäjää "ostamasta" sitä kymmenen kertaa peräkkäin. WooCommerce ei vakiona seuraa, onko tämä asiakas ottanut saman ilmaistuotteen aiemmin.
Kolmas: suora linkki ?add-to-cart=123-parametrilla. Ostoskorisivu päivitettiin, tuote lisättiin uudelleen. Uutiskirjeen linkkiä seurattiin kahdesti, korissa on kaksi kappaletta.
Kaikki kolme skenaariota ratkaistaan palvelinpuolella WooCommerce-koukkujen avulla. Ei lisäosia, vain koodia.
Tapa 1: Yksittäismyynnin pakottaminen metakenttien avulla

Ensimmäinen skripti pakottaa WooCommercen käsittelemään tietyn tuotteen "myydään yksittäin" -tilassa, vaikka tätä valintaruutua ei olisi rastitettu tuoteasetuksissa. Ohjaus tapahtuu metakentän kautta.
Kun metakentän maximum_allowed_quantity arvo on 1, woocommerce_is_sold_individually -suodatin palauttaa true, ja WooCommerce itse estää toisen yksikön lisäämisen koriin. Toimii sekä yksinkertaisille tuotteille että variaatioille.
Lisää koodi lapsiteemasi functions.php-tiedostoon tai Code Snippets -lisäosan kautta:
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 );
Mitä tässä tapahtuu: woocommerce_is_sold_individually-koukku laukeaa aina, kun WooCommerce tarkistaa, voiko tuotteen lisätä koriin useammin kuin kerran. Funktio katsoo tuotteen metakenttiin ja, jos se näkee maximum_allowed_quantity = 1, pakottaa "Myydään yksittäin" -tilan päälle. Variaatioille kentän nimi on variation_maximum_allowed_quantity.
Kuinka soveltaa. Mene muokkaamaan mitä tahansa tuotetta tai variaatiota, lisää mukautettu kenttä nimellä maximum_allowed_quantity (tai variation_maximum_allowed_quantity variaatiolle) ja arvolla 1. Tallenna. Siinä kaikki, nyt tätä tuotetta ei voi laittaa koriin kahdesti.
Tapa 2: Ilmaisten variaatioiden toistuvien ostojen estäminen
Ilmaiset digituotteet ovat suurin aukko kahdentumissuojauksessa. Käyttäjä on kirjautunut sisään, tuotteen hinta on nolla, WooCommerce päästää tilauksen läpi kyselemättä. Kymmenen tällaista tilausta yhdeltä asiakkaalta, kymmenen identtistä merkintää hallintapaneelissa.
Alla oleva skripti tarkistaa wc_customer_bought_product()-funktiolla, onko tämä käyttäjä ostanut saman tuotteen aiemmin. Jos on, koriin lisääminen estetään selkeällä ilmoituksella.
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 );
Asennuksen jälkeen käyttäjä näkee virheilmoituksen yrittäessään lisätä jo ostetun ilmaistuotteen koriin. Itse tilausta ei luoda.
Kaksi tärkeää ehtoa. Ensinnäkin asiakkaan on oltava kirjautunut sisään. Vieraileville käyttäjille wp_get_current_user() palauttaa tyhjän objektin, eikä tarkistus toimi. Toiseksi tuotteen hinnan on oltava täsmälleen nolla (floatval eliminoi muotoiluongelmat). Skripti ei koske tuotteisiin, joiden hinta on nollan yläpuolella.
Tapa 3: Suojaus URL:n kautta tapahtuvaa kahdentumista vastaan add-to-cart-parametrilla
WooCommerce sallii tuotteen lisäämisen koriin suoran linkin kautta: /cart/?add-to-cart=123. Kätevää markkinointiin, mutta jos käyttäjä päivittää sivun tai seuraa linkkiä uudelleen, tuote lisätään uudestaan.
Tämä skripti sieppaa ostoskorin tai kassan sivulatauksen ja, jos URL-parametrin tuote on jo korissa, poistaa hiljaisesti kyselyparametrit ja ohjaa puhtaaseen URL-osoitteeseen.
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' );
template_redirect-koukku laukeaa ennen kuin WordPress alkaa renderöidä sivua. Skripti tarkistaa, onko add-to-cart-parametri URL:ssa, etsii kyseistä tuotetta korin sisällöstä (WC()->cart->get_cart()), ja jos löytyy, tekee wp_redirect-ohjauksen samalle sivulle ilman kyselyparametreja.
Toistuva lisääminen URL:n kautta on eliminoitu. Samalla ensimmäinen lisäys (kun tuote ei vielä ole korissa) toimii normaalisti.
Kaiken yhdistäminen
Kaikki kolme skriptiä eivät ole ristiriidassa keskenään ja toimivat itsenäisesti:
- Ensimmäinen rajoittaa yksittäisen tuotteen määrän yhteen, suoja useita lisäyksiä vastaan.
- Toinen estää ilmaistuotteiden toistuvat ostot, suoja ilmaistuotteiden "klikkausspämmäystä" vastaan.
- Kolmas poistaa kahdentumisen URL:n kautta, suoja vahingossa tapahtuvia toistuvia lisäyksiä vastaan.
Lisää koodi Code Snippets WP.orgissa -lisäosan kautta, ei suoraan teeman functions.php-tiedostoon. Lisäosa antaa sinun ottaa käyttöön ja poistaa käytöstä koodinpätkät yksi kerrallaan rikkomatta sivustoa virhetilanteessa, eikä se menetä koodia teemaa vaihdettaessa. Luo kolme erillistä koodinpätkää, sitä on helpompi debugata.
Mitä muuta tarkistaa, jos kahdentumat jatkuvat
Yllä olevat skriptit kattavat kahdentumat ostoskorin ja kassan tasolla. Mutta on kaksi muuta ongelman lähdettä, joita koodi ei voi korjata.
Ostoskorin ja kassasivujen välimuistitus. Välimuistilisäosat, kuten WP Rocket tai LiteSpeed Cache, sulkevat nämä sivut oletuksena pois, mutta asetuspäivityksen jälkeen poissulkeminen voi nollautua. Tarkista: ostoskori, kassa ja oma tili eivät saa olla välimuistissa lisäosatasolla, palvelintasolla tai CDN:ssä.
Maksuyhdyskäytävän uudelleenyritykset. Jos yhdyskäytävä (Stripe, PayPal) ei saa vahvistusta palvelimelta ajoissa, se lähettää ilmoituksen uudelleen, ja WooCommerce luo toisen tilauksen. Syynä on yleensä hidas hosting tai palomuuri, joka estää takaisinkutsupyynnöt. Ratkaisu: tarkista yhdyskäytävän lokit toistuvien webhook-lähetysten varalta ja varmista, että takaisinkutsun URL on tavoitettavissa ulkopuolelta.
Kuinka testata suojaus
Skriptien asennuksen jälkeen muista testata jokainen skenaario testisivustolla.
Tapa 1: luo tuote metakentällä maximum_allowed_quantity = 1 ja yritä lisätä kaksi yksikköä koriin. Vain yksi pitäisi lisätä.
Tapa 2: kirjaudu sisään, osta ilmainen tuote ja yritä sitten ostaa se uudelleen. Sinun pitäisi nähdä virheilmoitus.
Tapa 3: lisää tuote koriin suoran linkin kautta ?add-to-cart=ID-parametrilla ja päivitä sitten sivu. Tuotteiden määrä korissa ei saisi muuttua.
Testaa erillisessä asennuksessa tai staging-sivustolla. Live-kaupassa vasta täyden tarkistuksen jälkeen.
⁉️🤔 Usein kysytyt kysymykset
Miksi tilaukset kahdentuvat, jos "Tilaa"-painiketta klikattiin kerran?
Syy on lähes aina hidas palvelimen vaste. Käyttäjä klikkaa painiketta, pyyntö lähtee, mutta sivu ei päivity useaan sekuntiin. Henkilö luulee, ettei klikannut, ja klikkaa uudelleen. Molemmat pyynnöt saavuttavat WooCommercen, ja kaksi tilausta luodaan. Tämän artikkelin skriptit eivät nappaa tätä tilannetta; tässä auttaa selainpuolen välimuistitus (poista painike käytöstä klikkauksen jälkeen) tai palvelinpuolen tilauksen uniikkiustarkistus nonce-tokenin avulla.
Voiko maksuyhdyskäytävä luoda kahdentumia itsestään?
Kyllä. Jos yhdyskäytävä ei saa palvelimeltasi HTTP 200 -vastausta IPN/webhook-pyyntöön, se toistaa lähetyksen. Jokaisella uudelleenyrityksellä WooCommerce voi luoda uuden tilauksen. Ongelma ratkaistaan nopeuttamalla hostingia ja tarkistamalla, ettei yhdyskäytävän takaisinkutsun URL ole palomuurin estämä eikä vaadi HTTP-todennusta.
Estääkö tämä suojaus asiakkaan aidot uusintatilaukset?
Ei. Skriptit toimivat koriin lisäämisen vaiheessa, eivät tilauksen luomisen vaiheessa. Jos asiakas teki tarkoituksella yhden tilauksen ja viikkoa myöhemmin toisen, skriptit eivät puutu asiaan. Poikkeus: tapa 2, joka kieltää saman käyttäjän toistuvan ilmaistuotteen oston.
Onko pakko käyttää Code Snippetsiä, vai voiko sen laittaa functions.php-tiedostoon?
Voit käyttää
functions.php-tiedostoa, mutta suosittelemme Code Snippetsiä. Kirjoitusvirhefunctions.php-koodissa antaa valkoisen ruudun ja pääsyn vain FTP:n kautta. Code Snippets -lisäosa nappaa vakavat virheet ja poistaa ongelmallisen koodinpätkän automaattisesti käytöstä, sivusto pysyy pystyssä.
Auttaako kahdentumisen estoon tarkoitetut lisäosat?
Erikoistuneet lisäosat, kuten WooCommerce Duplicate Order Blocker, toimivat eri tasolla; ne seuraavat kahdentumia IP:n, sähköpostin tai selaimen sormenjäljen perusteella kassavaiheessa. Tämä kattaa tuplaklikkausskenaarion, jota meidän skriptimme eivät kata. Lisäosat eivät kuitenkaan ratkaise kahdentumien ongelmaa add-to-cart-URL:n ja ilmaistuotteen toistuvien ostojen kautta. Ihanteellinen vaihtoehto: tämän artikkelin skriptit plus estolisäosa kassalla.
Yhteenveto: kolme kahdentumissuojauksen tasoa
Kolme skriptiä kattaa kolme erityistä tilauksen kahdentumisskenaariota. Asenna ne kaikki kerralla; jokainen vastaa omasta alueestaan, ja yhdessä ne tarjoavat tiukan suojauksen ostoskoritasolla.
Jos kahdentumia ilmenee edelleen asennuksen jälkeen, katso hostingin ja maksuyhdyskäytävän suuntaan. "Tilaa"-painikkeen tuplaklikkausta ei voi parantaa koodilla ostoskoritasolla; tässä tarvitset joko estolisäosan tai mukautetun painikkeen suojauksen JavaScriptillä.
Testaa suojaus testisivustolla ja siirrä se sitten tuotantoon. Viisitoista minuuttia kolmen koodinpätkän asentamiseen säästää tunteja palautusten selvittelyä.


