Coupon WooCommerce solo per utenti registrati: guida

Coupon WooCommerce solo per utenti registrati

Come riservare un coupon WooCommerce solo per utenti registrati

Hai creato un codice sconto di benvenuto per spingere le persone a registrarsi, ma poi ti accorgi che chiunque lo può usare: basta che il codice finisca su un gruppo Telegram di offerte e il “vantaggio riservato” diventa uno sconto per tutti, ospiti compresi.

La configurazione delle preferenze nella sezione Marketing, non offre un’opzione per limitare un coupon WooCommerce solo per utenti registrati. Ci sono il limite di utilizzi, la scadenza, la spesa minima e la restrizione per indirizzo email, ma manca proprio la condizione più ovvia: questo sconto vale solo se hai un account. La buona notizia è che bastano poche righe nel functions.php e in questa guida vediamo quali, dove metterle, come testarle e soprattutto quali errori evitare.

Perché le restrizioni native non bastano

Prima di scrivere codice conviene escludere le alternative, perché a volte una basta.

La restrizione “Indirizzi email consentiti” funziona solo se conosci in anticipo l’elenco delle persone: va bene per una promozione one-to-one, non per un coupon pubblico. Il limite di utilizzi per utente è ancora più ingannevole: WooCommerce lo applica sull’email dell’ordine, quindi un ospite con dieci indirizzi diversi lo usa dieci volte. E il limite di utilizzi totali limita i danni, ma non cambia chi può approfittarne.

Nessuna delle tre risponde alla domanda “questa persona ha un account?”. Per quella serve un aggancio al codice.

Il punto giusto dove intervenire

WooCommerce valida ogni coupon dentro il metodo WC_Discounts::is_coupon_valid(), che esegue in sequenza tutti i controlli nativi e poi, come ultimo passaggio, applica il filtro woocommerce_coupon_is_valid. È il gancio pensato esattamente per aggiungere una regola personalizzata.

Il dettaglio interessante è che quel filtro viene eseguito dentro un blocco try/catch. Significa che dal filtro puoi sollevare un’eccezione con un messaggio testuale, e WooCommerce lo intercetta e lo mostra all’utente così com’è, al posto del generico “Coupon non valido”. Se invece ti limiti a restituire false, l’utente riceve un messaggio standard che non spiega nulla e un cliente che non capisce perché lo sconto non funziona è un cliente che abbandona il carrello.

Un secondo vantaggio, spesso trascurato: il controllo non vale solo al momento in cui il codice viene inserito. WooCommerce rivalida i coupon a ogni caricamento di carrello e checkout, quindi se un utente applica lo sconto da loggato e poi la sessione scade, il coupon viene rimosso da solo. Non c’è una scorciatoia.

Il prerequisito che quasi tutti saltano

Prima di scrivere una riga di codice apri WooCommerce → Impostazioni → Account e privacy e guarda il gruppo “Creazione dell’account”. Ci sono tre caselle, e una sola serve al nostro scopo.

OpzioneQuando nasce l’accountIl coupon funziona?
Dopo il pagamentoa ordine conclusoNo, troppo tardi
Durante il pagamentoal clic su “Effettua ordine”No, in cassa è ancora un ospite
Nella pagina “Il mio account”subito, prima di acquistare
Creazione dell'account WooCommerce

Il punto è che nel sorgente delle impostazioni quell’ultima voce ha ‘default’ => ‘no’: su un’installazione appena fatta è disattivata. Se la lasci così, il messaggio che stiamo per costruire inviterà a creare un account su una pagina dove l’unica cosa possibile è accedere.

C’è anche un’insidia nella combinazione. Con “Durante il pagamento” attiva, il cliente vede in cassa la casella “crea un account”, la spunta convinto di aver risolto e si becca comunque il rifiuto del coupon. Non è sbagliato tenerla attiva, ma rende ancora più importante che il messaggio di errore indirizzi in modo esplicito all’area account.

Il codice

Ecco il blocco completo da incollare nel file functions.php. Fa tre cose, numerate nei commenti: blocca il coupon per chi non ha l’account, riporta al carrello dopo il login e avvisa in anticipo accanto al campo coupon.

/**
 * Coupon WooCommerce solo per utenti registrati — WooCommerce
 * Da incollare nel functions.php del child theme o in un plugin di snippet.
 */
 
defined( 'ABSPATH' ) || exit;
 
// Il guard evita il fatal error "Cannot redeclare function" se lo snippet
// finisce due volte nel sito (child theme + plugin di snippet, per esempio).
if ( ! function_exists( 'wz_coupon_solo_utenti_registrati' ) ) {
 
	/**
	 * 1. Blocca i coupon riservati per chi non ha effettuato l'accesso.
	 */
	function wz_coupon_solo_utenti_registrati( $is_valid, $coupon ) {
 
		// I codici da riservare. Scrivili come preferisci: WooCommerce li salva
		// sempre in minuscolo, quindi qui vengono normalizzati in maiuscolo.
		$riservati = array_map( 'wc_strtoupper', array(
			'BENVENUTO10',
			'PROMO-MEMBRI',
		) );
 
		$codice = wc_strtoupper( $coupon->get_code() );
 
		if ( ! in_array( $codice, $riservati, true ) || is_user_logged_in() ) {
			return $is_valid;
		}
 
		$messaggio = sprintf(
			'Il coupon "%s" è riservato agli utenti registrati.',
			esc_html( $codice )
		);
 
		// Se la registrazione dalla pagina account è disattivata — ed è il
		// default di WooCommerce — invitare a "creare un account" manderebbe
		// l'utente contro un muro: da lì si può solo accedere.
		$etichetta = 'yes' === get_option( 'woocommerce_enable_myaccount_registration' )
			? 'Accedi o crea un account'
			: 'Accedi al tuo account';
 
		// Sul carrello classico il messaggio passa da wc_kses_notice() e il tag
		// <a> sopravvive. Sul carrello a blocchi la Store API applica
		// wp_strip_all_tags(): resta il solo testo, quindi la frase deve
		// funzionare anche senza link.
		$messaggio .= sprintf(
			' <a href="%s">%s</a>',
			esc_url( add_query_arg( 'wz_return', 'cart', wc_get_page_permalink( 'myaccount' ) ) ),
			$etichetta
		);
 
		$messaggio .= ' e reinserisci il codice: il carrello resta salvato.';
 
		// La barra rovesciata davanti a Exception serve se un domani sposti
		// questo codice in un file con namespace.
		throw new \Exception( $messaggio, WC_Coupon::E_WC_COUPON_INVALID_FILTERED );
	}
	add_filter( 'woocommerce_coupon_is_valid', 'wz_coupon_solo_utenti_registrati', 10, 2 );
 
	/**
	 * 2. Riporta al carrello dopo il login o la registrazione.
	 *
	 * WC_Form_Handler usa $_POST['redirect'] quando è presente. La destinazione
	 * la calcoli tu lato server: il parametro nell'URL è solo un interruttore.
	 */
	function wz_coupon_campo_redirect() {
		$return = isset( $_GET['wz_return'] ) ? sanitize_key( wp_unslash( $_GET['wz_return'] ) ) : '';
 
		if ( 'cart' !== $return ) {
			return;
		}
 
		printf( '<input type="hidden" name="redirect" value="%s" />', esc_url( wc_get_cart_url() ) );
	}
	add_action( 'woocommerce_login_form_end', 'wz_coupon_campo_redirect' );
	add_action( 'woocommerce_register_form_end', 'wz_coupon_campo_redirect' );
 
	/**
	 * 3. Avviso preventivo accanto al campo coupon del carrello.
	 *
	 * Con i blocchi Carrello/Checkout gli hook PHP dei template non vengono
	 * eseguiti: in quel caso aggiungi l'avviso come blocco Paragrafo.
	 */
	function wz_coupon_avviso_carrello() {
		if ( is_user_logged_in() ) {
			return;
		}
 
		echo '<p class="wz-coupon-hint"><small>Alcuni codici sconto sono riservati agli utenti registrati.</small></p>';
	}
	add_action( 'woocommerce_cart_coupon', 'wz_coupon_avviso_carrello' );
}

Riportare il cliente al carrello dopo il login

È la parte 2 del blocco, e vale la pena capire perché serve. Il link nel messaggio porta l’utente all’area account, ma di default WooCommerce dopo il login lo rimanda dove capita: il referer, se c’è, altrimenti la pagina “Il mio account”. Agganciando un campo nascosto ai form di login e registrazione, il rientro diventa deterministico.

WC_Form_Handler usa $_POST['redirect'] quando è presente, sia per il login sia per la registrazione. Il valore lo calcoli tu lato server con wc_get_cart_url(), quindi non stai aprendo la porta a un open redirect: il parametro nell’URL è solo un interruttore, non la destinazione.

La parte 3 è l’avviso accanto al campo coupon: una riga, mostrata solo agli ospiti, che anticipa il problema invece di lasciare che il cliente ci sbatta contro. Attenzione però: con i blocchi Carrello e Checkout gli hook PHP dei template non vengono eseguiti, quindi lì l’avviso va aggiunto a mano come blocco Paragrafo.

Il passo successivo: una casella nel pannello

L’array dei codici coupon da inserire nel codice (functions.php o plugin di snippets) va benissimo finché chi ci mette le mani è dotato di basi minime da sapere dove intervenire. Se il sito lo gestisce un cliente, chiedergli di aprire il functions.php per cambiare un codice è la ricetta per una telefonata il sabato mattina. La soluzione di installare il plugin è la più adatta per gli utenti che non vogliono complicazioni: Crea il coupon, seleziona “Solo utenti registrati” e Salva.

Dove incollarlo (non nel tema padre)

Tre opzioni, in ordine di preferenza:

  1. Un piccolo plugin custom, scarica ed installa il plugin.
  2. Un plugin di snippet (Code Snippets o simili): il codice sopravvive a cambi di tema ed è disattivabile in un clic se qualcosa va storto (ricordati di aggiungere i codici coupon nel sezione 1 del codice, dove ci sono gli altri codici di esempio).
  3. Il functions.php del child theme: accettabile, ma il codice sparisce se un domani cambi tema (ricordati di aggiungere i codici coupon nel sezione 1 del codice, dove ci sono gli altri codici di esempio).

Quello che non devi fare è metterlo nel functions.php del tema padre: al primo aggiornamento è perso.

Come testarlo in due minuti

Non fidarti del fatto che “sembra funzionare”. I casi da provare sono quattro:

ScenarioRisultato atteso
Ospite + coupon riservatoBloccato, con il messaggio personalizzato
Ospite + coupon normaleApplicato
Utente loggato + coupon riservatoApplicato
Utente loggato + coupon normaleApplicato

Il modo più rapido è una finestra anonima del browser per la parte “ospite” e la sessione normale per quella “loggato”.

Domande frequenti

Il blocco del coupon sì, identico: la validazione passa dallo stesso metodo del core.

No. È un confronto tra stringhe che viene eseguito solo quando qualcuno applica un coupon.

Sì: al posto di ! is_user_logged_in() puoi verificare il ruolo dell’utente corrente e riservare lo sconto, per esempio, ai soli clienti all’ingrosso.

Sicuro di aver aggiunto il codice coupon anche nel codice incollato in “Code Snippets o functions.php?
Verifica che nell’array sia stato aggiunto il nuovo coupon nella seguente sezione del codice:
$riservati = array_map( 'wc_strtoupper', array(
'BENVENUTO10',
'PROMO-MEMBRI',
) );

In sintesi

Riservare un coupon WooCommerce solo per utenti registrati richiede una decina di righe e un filtro che WooCommerce mette a disposizione proprio per questo.

Hai un e-commerce WooCommerce con regole promozionali che il pannello non copre? Raccontaci le tue necessità e scrivici per una consulenza: spesso si tratta di poche righe nel posto giusto.