WooCommerce, validation par email du compte utilisateur

WooCommerce, validation par email du compte utilisateur

Tech web
|

L’environnement de développement était le suivant : Wordpress 4.8, WooCommerce 3.0.9

Ce tutoriel est né des suites d’un problème concret que nous avons eu chez karac lors de la création d’un site d’e-commerce réalisé avec Wordpress et le célèbre plugin WooCommerce.

En effet, lors de la création d’un nouveau compte utilisateur, la réaction par défaut de WooCommerce est d’envoyer un email à l’utilisateur pour lui confirmer la création du compte. Le problème, c’est que l’utilisateur n’avait pas besoin de confirmer la validité de son adresse email. Il pouvait donc se connecter directement à son compte, même s’il avait entré une adresse email non-valide lors de l’enregistrement.

À première vue, il y a bien quelques plugins qui pourraient faire l’affaire. Je pense notamment à « Woocommerce User Email Verification » (https://fr.wordpress.org/plugins/woo-confirmation-email/)

qui semble être une petite perle jusqu’à ce que l’on se rende compte que l’email de vérification ne parte pas pour une raison obscure.

Mais, à l’heure où j’écris ces lignes, force est de constater qu’il est difficile de trouver un plugin qui fait le job, et juste le job. J’entends par là que je ne veux pas changer mon formulaire d’inscription en entier ou quoi que ce soit dans le genre.

Il existe pourtant une solution miracle. Il s’agit d’un code, quelques fonctions facilement personnalisables qu’il suffit d’écrire dans un seul fichier, le fameux functions.php. Un code sur lequel on tombe un peu fortuitement sur Stack Overflow ou ailleurs et que l’on essaie sans trop y croire. Et pourtant, c’est une petite merveille. Dans ce tutoriel, je vais le décrire et le « pimper » un peu, afin qu’il devienne encore un peu plus sympathique.

 

Le script ultime

Ouvrez tout d’abord le fichier functions.php se trouvant dans le dossier wp-includes.

Si vous utilisez l’extension Child Theme, ce que je vous conseille vivement de faire afin de ne pas écraser le fichier d’origine, vous trouverez le fichier functions.php dans wp-content/themes/votretheme-child.

Nous allons écrire notre petit script à la fin de ce fichier. Pour commencer, il nous faut rediriger l’utilisateur lorsqu’il crée son compte afin qu’il ne soit pas connecté automatiquement après son enregistrement. Pour ce faire, nous allons ajouter un callback à la fonction wc_registration_redirect() de WooCommerce et la modifier un tout petit peu :

function wc_registration_redirect( $redirect_to ) {
        wp_logout();
        wp_redirect( '/mon-compte/?q=');
        exit;
}

 

Pensez bien entendu à remplacer « mon-compte » par l’url qui mène à votre formulaire de connexion.

Il faut ensuite envoyer un email à l’utilisateur lorsqu’il s’est enregistré avec un lien comprenant le code d’activation de son compte. Pour ce faire, allons créer un nouveau callback pour la fonction user_register() de Wordpress. Pour stocker le code d’activation et le statut pour savoir si l’utilisateur est activé ou non, nous allons créer 2 nouvelles « meta_key » (dans la table wp_usermeta).

Les meta_key nous permettent de créer des « champs » à la volée pour des entités spécifiques (dans ce cas, il s’agit d’utilisateurs).

Ensuite, nous allons générer l’url d’activation comprenant toujours le chemin vers votre page de connexion, l’id de l’utilisateur et le code d’activation.

Enfin, nous allons mettre dans une variable le contenu de l’email, c’est-à-dire un petit texte avec un lien contenant l’url précédemment créée et envoyer l’email avec la fonction wc_mail(). Le lien que l’utilisateur recevra devrait ressembler à ceci :

http://monsite.com/mon-compte/?p=YToyOntzOjI6ImlkIjtpOjI0O3M6NDoiY29kZSI7czoz...

function my_user_register($user_id) {
        // obtenir les données de l’utilisateur
        $user_info = get_userdata($user_id);
        // créer un hash md5 pour la vérification du compte
        $code = md5(time());
        // créer une chaine contenant le hash et l’id de l’utilisateur
        $string = array('id'=>$user_id, 'code'=>$code);
        // créer une meta_key “is_activated” pour l’utilisateur et lui mettre le statut 0
        update_user_meta($user_id, 'is_activated', 0);
        // créer une meta_key “activationcode” pour l’utilisateur et lui mettre en tant que valeur le code d’activation généré précédemment
        update_user_meta($user_id, 'activationcode', $code);
        // créer l’url qui figurera dans le mail
        $url = get_site_url(). '/mon-compte/?p=' .base64_encode( serialize($string));

        $html = 'Pour activer votre compte, vous devez cliquer sur le lien suivant : '.$url .''

        // envoyer l’email à l’utilisateur
        wc_mail($user_info->user_email, __('Activation de votre compte utilisateur'), $html);

}

 

Lorsqu’un utilisateur essaie de se connecter, il faut alors vérifier que ce dernier a bien activé son compte via l’email qu’il a reçu. Cela va se faire au moment de l’authentification grâce à la fonction de wp_authenticate_user() et au callback que nous allons y ajouter :

function wp_authenticate_user( $userdata ) {
        $isActivated = get_user_meta($userdata->ID, 'is_activated', true);
        if ( !$isActivated ) {
                $userdata = new WP_Error(
                                'inkfool_confirmation_error',
                                __( 'ERREUR : Votre compte doit être activé avant de pouvoir vous connecter. Vous pouvez renvoyer l’email de confirmation en cliquant ici', 'inkfool' )
                                );
        }
        return $userdata;
}

 

On vérifie d’abord si l’utilisateur qui a essayé de se connecter est bien activé. Si c’est le cas, on retourne les informations de l’utilisateur. Dans le cas contraire, on remplace les $userdata par une petite erreur proposant d’envoyer à nouveau l’email. Remplacez à nouveau « mon-compte » par ce que vous avez mis précédemment. Notez que le paramètre « u » dans l’url nous servira plus tard à déterminer si un email a été renvoyé.

Plus concrètement, ça donne quelque chose de ce style en cas d’erreur :

 

 

affichage du message d'erreur

 

La dernière fonction à créer ne sera pas un callback ajouté à une fonction existante de Wordpress ou WooCommerce comme précédemment. En effet, nous allons la fabriquer de toutes pièces et nous l’utiliserons à l’aide du « hook » init() qui est lancé lorsque Wordpress a été complètement chargé.

On vérifie d’abord si nous avons bien reçu le paramètre « p » en GET contenant le code d’activation et l’id de l’utilisateur. Si c’est le cas, on vérifie qu’il correspond au code stocké dans la base de données pour l’utilisateur courant. Si tout est ok, on change le statut « is_activated » à 1 et l’on ajoute un petit message de succès. Si le code ne correspond pas, on affiche un message d’erreur. Dans le cas où l’on n’aurait pas reçu le paramètre « p », on affiche une autre erreur disant que le compte doit être activé pour pouvoir se connecter.

Rappelez-vous, nous avions envoyé un paramètre « u » si l’utilisateur cliquait sur le lien pour envoyer à nouveau l’email. Et bien si nous recevons ce paramètre, nous allons afficher un petit message stipulant le fait qu’un email a été à nouveau envoyé à l’utilisateur.

function my_init(){
        // on vérifie si on a bien reçu le paramètre contenant le code d'activation et l'id de l'utilisateur
        if(isset($_GET['p'])){
                $data = unserialize(base64_decode($_GET['p']));
                $code = get_user_meta($data['id'], 'activationcode', true);
                // si oui, on vérifie que le code correspond à celui stocké dans la base de données pour l'utilisateur
                if($code == $data['code']){
                        // on met à jour le statut 'is_activated' du compte de l'utilisateur
                        update_user_meta($data['id'], 'is_activated', 1);
                        wc_add_notice( __( 'Succès : Votre compte a été activé avec succès !', 'inkfool' )  );
                }else{
                        wc_add_notice( __( 'Erreur : L\'activation a échouée, veuillez contacter l\'administrateur. ', 'inkfool' )  );
                }
        }
        if(isset($_GET['q'])){
                wc_add_notice( __( 'Succès : Votre compte doit avoir été validé avant de pouvoir vous y connecter. Veuillez vérifier vos emails.', 'inkfool' ) );
        }
        if(isset($_GET['u'])){
                my_user_register($_GET['u']);
                wc_add_notice( __( 'Succès : Votre email d\'activation à été réenvoyé. Veuillez vérifier vos emails.', 'inkfool' ) );
        }
}

 

Voilà, il ne nous reste plus qu’à :

  • Lancer la fonction my_init() après le chargement de Wordpress
  • Ajouter nos callbacks à leurs fonctions respectives (avec add_filter())
add_action( 'init', 'my_init' );
add_filter('woocommerce_registration_redirect', 'wc_registration_redirect');
add_filter('wp_authenticate_user', 'wp_authenticate_user',10,2);
add_action('user_register', 'my_user_register',10,2);

 

C’est tout ! Comme c’est ma tournée, je vous offre le script en entier et j’y intègre en bonus un petit peu de HTML/CSS tout simple (que vous pourrez bien entendu modifier à souhait) pour mettre en forme un minimum l’email. Vous n’avez qu’à copier tout ça dans wp-content/themes/votretheme-child/functions.php.

Notez que vous pouvez même y accéder par le biais du plugin Child Theme, dans le menu Apparence/Editeur, sans ouvrir le fichier ou vous rendre sur le FTP.

Si tout fonctionne, voici l’email que vous devriez recevoir :

 

email généré par le script

 

Et voici le code en entier :

// Rediriger l'utilisateur après l'enregistrement pour éviter qu'il soit directement connecté
function wc_registration_redirect( $redirect_to ) {
        wp_logout();
        wp_redirect( '/mon-compte/?q=');
        exit;
}
// Vérifier lorsqu'un utilisateur se connecte que son email a été validé
function wp_authenticate_user( $userdata ) {
        $isActivated = get_user_meta($userdata->ID, 'is_activated', true);
        if ( !$isActivated ) {
                $userdata = new WP_Error(
                                'inkfool_confirmation_error',
                                __( 'ERREUR : Votre compte doit être activé avant de pouvoir vous connecter. Vous pouvez renvoyer l’email de confirmation en cliquant <a href="/mon-compte/?u='.$userdata->ID.'">ici</a>', 'inkfool' )
                                );
        }
        return $userdata;
}
// Envoyer un email à un utilisateur qui s'enregistre
function my_user_register($user_id) {
        // obtenir les données de l’utilisateur
        $user_info = get_userdata($user_id);
        // créer un hash md5 pour la vérification du compte
        $code = md5(time());
        // créer une chaine contenant le hash et l'id de l'utilisateur
        $string = array('id'=>$user_id, 'code'=>$code);
        // créer une meta_key "is_activated" pour l'utilisateur et lui mettre le statut 0
        update_user_meta($user_id, 'is_activated', 0);
        // créer une meta_key "activationcode" pour l'utilisateur et lui mettre en tant que valeur le code d'activation généré précédemment
        update_user_meta($user_id, 'activationcode', $code);
        // créer l'url qui figurera dans le mail
        $url = get_site_url(). '/mon-compte/?p=' .base64_encode( serialize($string));
        // contenu principal du mail
        $content = __('Cliquez sur le lien suivant pour valider votre compte :');
        // titre de l'email
        $title = __('monsite.com');
        // sous-titre de l'email
        $subtitle = __('Validation du compte');
        // signature de l'email
        $signature = __('Votre team monsite.com.');
        // contenu html de l'email

$html = <<<EOT
        <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
        <html xmlns="http://www.w3.org/1999/xhtml">
            <head>
                <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
                <meta name="viewport" content="initial-scale=1.0">
                <meta name="format-detection" content="telephone=no">
                <title>Validation du compte</title>
                <style type="text/css">

                    .container {
                    border: none;
                    width: 100%;
                    background-color: white;

                    font-family: Verdana, Geneva, Tahoma, sans-serif;
                    margin-top: 30px;
                    margin-bottom: 30px;

                    }

                    .maintitle {
                    background-color: #D01012;
                    padding-top: 60px;
                    padding-bottom: 60px;
                    color: white;
                    font-weight: bold;
                    font-size: 30px;
                    text-align: center;
                    text-transform: uppercase;
                    }

                    .text {
                    padding-left: 30px;
                    padding-right: 30px;
                    color: lightgray;
                    }

                    .subtitle {
                    padding-left: 30px;
                    padding-right: 30px;
                    padding-top: 30px;
                    padding-bottom: 30px;
                    color: grey;
                    font-weight: bold;
                    font-size: 20px;
                    text-align: left;
                    text-transform: uppercase;
                    }

                    .signature {
                    padding-top: 30px;
                    padding-left: 30px;
                    padding-right: 30px;
                    color: lightgray;

                    }

                </style>
            </head>
            <body>
                <div class="main">
                    <table class="container">
                        <thead>
                            <tr>
                                <td class="maintitle">$title</td>
                            </tr>
                        </thead>
                        <tbody>
                            <tr>
                                <td class="subtitle">$subtitle</td>
                            </tr>
                            <tr>
                                <td class="text">
                                    $content <br/><br/> <a href="$url">$url</a>
                                </td>
                            </tr>
                            <tr>
                                <td class="signature">
                                    $signature
                                </td>
                            </tr>
                        </tbody>
                    </table>
                </div>
            </body>
        </html>
EOT;
        
        // envoyer l'email à l'utilisateur
        wc_mail($user_info->user_email, __('Validation de votre compte utilisateur'), $html);

}
// récupération et utilisation des valeurs passées en GET
function my_init(){
        // on vérifie si on a bien reçu le paramètre contenant le code d'activation et l'id de l'utilisateur
        if(isset($_GET['p'])){
                $data = unserialize(base64_decode($_GET['p']));
                $code = get_user_meta($data['id'], 'activationcode', true);
                // si oui, on vérifie que le code correspond à celui stocké dans la base de données pour l'utilisateur
                if($code == $data['code']){
                        // on met à jour le statut 'is_activated' du compte de l'utilisateur
                        update_user_meta($data['id'], 'is_activated', 1);
                        wc_add_notice( __( 'Succès : Votre compte a été activé avec succès !', 'inkfool' )  );
                }else{
                        wc_add_notice( __( 'Erreur : L\'activation a échouée, veuillez contacter l\'administrateur. ', 'inkfool' )  );
                }
        }
        if(isset($_GET['q'])){
                wc_add_notice( __( 'Succès : Votre compte doit avoir été validé avant de pouvoir vous y connecter. Veuillez vérifier vos emails.', 'inkfool' ) );
        }
        if(isset($_GET['u'])){
                my_user_register($_GET['u']);
                wc_add_notice( __( 'Succès : Votre email d\'activation à été réenvoyé. Veuillez vérifier vos emails.', 'inkfool' ) );
        }
}
// hooks et callbacks
add_action( 'init', 'my_init' );
add_filter('woocommerce_registration_redirect', 'wc_registration_redirect');
add_filter('wp_authenticate_user', 'wp_authenticate_user',10,2);
add_action('user_register', 'my_user_register',10,2);

 

Attention ! Il y a tout de même un petit bémole avec ce script. En effet, si le script vérifie lors de la création d'un compte "client" que le "user_meta" "is_activated" est bien à "1" (et donc que le compte est activé), il ne fait pas la différence entre un compte "client" et un compte "administrateur" ou "éditeur" du site. Il vous faudra donc activer les futurs comptes que vous allez créer par le biais des mails d'activations que vous recevrai. Pour les comptes déjà existants, essayez de vous connecter une première fois. Cela ne fonctionnera pas, mais un message d'erreur vous proposera de vous renvoyer un email de validation. Activez le compte depuis cet email, et le tour est joué !

Source

 

Catégories :
Tech web

Tags :
Wordpress WooCommerce PHP