BuddyPress Registration : mon expérience fumante !

Crédits Photo (125/365) The Absent Minded Professor by BrandonHambright.com, on Flickr

Ce vendredi, après 1 bon mois d’interlude flex à manipuler de l’actionscript et du mxml, je me suis enfin replongé dans mes expérientations BuddyPress. Aussi, je vous propose de suivre une nouvelle expérience consistant à faire en sorte de permettre à un utilisateur de s’inscrire sur un blog fils directement depuis le frontend.

Mise à jour !

Date : 16/12/2012

Hello, je viens de faire une mise à jour des scripts utilisés dans ce tuto afin de prendre en compte les config classique de WordPress. Ainsi, en utilisant le code décrit dans ce gist, il vous sera possible d’ajouter des usermetas WordPress classique dans votre formulaire d’inscription et ce que votre WordPress soit multisite ou non 😉

Hypothèse :

Etant donné que depuis le backend de WordPress, il est possible d’affecter un membre à un blog différent du principal, il doit être jouable de le faire depuis le frontend au moment des étapes register et activate.

Conditions de réalisation de l’expérience :

  1. WordPress 3.0.4 avec Network activé,
  2. Seule la création de nouveaux comptes utilisateur est autorisée,
  3. BuddyPress 1.2.7,
  4. 1 child thème de BP-Default pour le blog principal
  5. 1 autre child thème, cette fois de 2010, pour un des blogs du réseau.

I. Dissection du mécanisme d’enregistrement d’un nouvel utilisateur sous BuddyPress/WPMU

Lorsqu’un utilisateur s’enregistre, il y a deux phases : le register et l’activate. Dans le thème BP-Default de BuddyPress, les templates appelés sont situés dans le dossier registration. Le script core qui se charge de réaliser les opérations est bp-core-signup.php notamment à l’aide de la fonction bp_core_signup_user() qui, en cas d’installation multisite active, se contente d’appeler la fonction wpmu_signup_user() de WordPress.

I.a Etape Register

Lorsque l’utilisateur souhaite s’inscrire depuis le frontend, il est automatiquement dirigé vers siteurl/register/ du blog principal et le template register.php de BP-Default lui est servi. C’est le formulaire qui permet de recueillir les infos nécessaires à son pré-enregistrement.

La table des signups

Lorsque le formulaire est validé, les données nécessaires à son enregistrement sont stockées dans la table wp_signups (sauf si comme moi vous changez la valeur du table prefix pour plus de sécurité 😉 ). A ce moment de la partie, l’utilisateur n’est pas encore dans la table wp_users et n’a donc pas encore d’ID. Dans cette table wp_signups, le champ meta nous sera d’une grande utilité, mais on y reviendra plus tard.

I.b Etape d’activation

Mail d’activation du compte

L’utilisateur reçoit un email contenant un lien avec la valeur contenu dans le champ activation_key de wp_signups. Lorsque ce lien est cliqué, l’utilisateur est créé dans wp_users, xprofile fields et usermetas sont également créés grâce notamment au champ meta de la table wp_signups.

II. Les usermetas déterminantes :

Dans la table wp_usermeta, il y a 3 usermetas qui sont responsables de l’affectation d’un utilisateur et de son rôle dans le blog principal.

  1. wp_capabilities
  2. wp_user_level
  3. primary_blog

Ainsi ma première idée a été d’utiliser ces meta_key pour attacher l’utilisateur à un blog de son choix. Pour cela il suffisait de modifier la valeur des meta_key en intercalant l’identifiant du blog fils dans les 2 premières et en fixant la valeur de la troisième selon ce même identifiant de blog (dans mon cas blog id = 2).

Les meta_key du processus

Sauf que comme on l’a vu plus haut au moment du register, l’utilisateur n’existe pas encore et donc son ID non plus. Or pour attacher un usermeta à un utilisateur, son ID est légèrement indispensable !

Aussi, Je pousse un peu plus loin l’exploration du mécanisme, mais cette fois-ci du côté administration WordPress. Quand j’ajoute un utilisateur à un blog fils, je m’aperçois que le champ meta de wp_signups est différent. En effet, ce champ contient un tableau serialisé et deux nouvelles paires clé/valeur ont été ajoutées : add_to_blog/id_du_blog et new_role/subscriber.

Le champ meta du signup

Par ailleurs, les usermetas nécessaires au rattachement d’un blog fils ont été ajoutées, j’en déduis que si j’enrichis le champ meta de ces deux nouveaux éléments au moment de l’étape register en personnalisant le blog id alors, au moment de l’activation, l’utilisateur sera automatiquement affecté sur le blog id spécifié.

III. Mise en pratique : tweaking themes !

Pour éviter toute difficulté, j’utilise systématiquement des child thèmes pour mes expériences, je construis donc rapido 1 child thème basé sur BP-default pour le blog principal et un autre basé sur 2010 pour le blog secondaire.

III.1 2010 child theme pour blog fils

Je fais le nécessaire concernant le style puis je copie/colle simplement le script sidebar.php de 2010 dans le répertoire de mon child thème et j’y insère ce code :

<?php if ( ! is_user_logged_in() ) :
    global $blog_id;?>
    <li id="li-register" class="widget-container">
        <a href="<?php echo get_blog_option (1, 'siteurl' ) . '/' . BP_REGISTER_SLUG . '/?site_id=' . $blog_id ;?>">
            Register an account
        </a>
    </li>
<?php endif;?>

Je récupère la variable globale $blog_id pour la passer en paramètre $_GET au template register du blog principal. Ci-dessous, une illustration du child thème de 2010 :

Un bouton register dans la sidebar du blog enfant

III.b BP-Default child theme pour blog principal

Notre objectif est donc de récupérer ce paramètre $_GET pour le stocker dans le champ meta de la table wp_signups. Pour ce faire, au delà du style.css qui permet d’indiquer que mon thème a pour template BP-Default, j’ajoute le fameux « fichier à tout faire » functions.php. D’abord j’y ajoute une fonction qui me permet de construire un tableau contenant des informations sur tous les blogs de mon réseau. Cela me permettra d’indiquer le nom du blog sur lequel l’utilisateur est sur le point de s’inscrire.

<?php
/**
 * imath_list_blogs
 * queries blog list
 */
function imath_list_blogs() {
    global $wpdb;
    $list = array();
    $list_blogs = $wpdb->get_col( "SELECT blog_id FROM {$wpdb->base_prefix}blogs" );
    
    foreach ($list_blogs as $blog_id ){
        $list[ $blog_id ]= array(
            'blogname'   => get_blog_option( $blog_id, 'blogname' ),
            'blogurl'    => get_blog_option( $blog_id, 'siteurl'),
            'mail_admin' => get_blog_option( $blog_id, 'admin_email' )
        );
    }
    
    return $list;
}

Ensuite, je me sers du tag bp_before_account_details_fields du template register.php de BP-Default pour insérer de nouveaux éléments. Bien entendu un champ hidden qui contiendra le blog_id sur lequel enregistrer l’utilisateur, mais aussi une mention précisant qu’il sera inscrit sur tel blog et enfin, pour des besoins persos un nouveau usermeta (imath_user_meta) qui me permettra de stocker une donnée qui ne sera pas visible dans le profil de l’utilisateur (raison pour laquelle je n’utilise pas un xprofile 😉 ).

<?php
function imath_add_wp_usermeta_fields() {
    if ( isset( $_GET['site_id'] ) ){
        $siteid = $_GET['site_id'];
        $list_of_blogs = imath_list_blogs();
    }
    ?>
        <h4>Vous êtes sur le point de vous inscrire sur le
            <?php if ( $siteid ) echo 'blog <i><a href="'. $list_of_blogs[$siteid]["blogurl"] .'">'. $list_of_blogs[$siteid]["blogname"] .'</a></i> du';?>
            réseau <i><a href="<?php bloginfo( 'siteurl' );?>"><?php bloginfo( 'name' );?></a></i>
        </h4>
        
        <!--to add a custom user meta-->
        <label for="imath_user_meta">
            Imath user meta <?php _e( '(required)', 'buddypress' ) ?>
        </label>
        <input type="text" name="imath_user_meta" id="imath_user_meta" value="" style="width:100px"/>
        
        <?php if( isset( $_GET['site_id'] ) ): ?>
            <!-- to register the user to blog with id : $_GET['site_id']-->
            <input type="hidden" name="site_id" value="<?php echo $_GET['site_id'];?>"/>
        <?php endif;?>
        
        <hr/>
    <?php
}
add_action( 'bp_before_account_details_fields','imath_add_wp_usermeta_fields' );

Pour être certain que mon champ imath_user_meta soit bien rempli, j’ajoute une fonction qui permet d’insérer un javascript si nous nous situons dans la page de registration :

<?php
/**
 * imath_js_check_register
 * to add js form check in footer
 */
function imath_js_check_register() {
    if( bp_is_page( 'register' ) ) {
        ?>
        <script type="text/javascript">
        jQuery( '#signup_form' ).submit( function() {
            //here you check for data before submiting
            if( jQuery( '#imath_user_meta').val().length < 1 ) {
                alert( 'Oops champ Imath user meta vide, merci de remplir !' );
                return false;
            }

            return true;
        } );
        </script>
        <?php
    }
}
add_action( 'wp_footer','imath_js_check_register' );

Le formulaire est donc en place, il ne nous reste plus qu’à ajouter nos nouvelles données dans le champ meta de wp_signups. Voici une illustration de ces lignes de code, avant de poursuivre :

Formulaire d’inscription

Une fois que l’utilisateur a complété son inscription, nous allons récupérer le champ meta de la table wp_signups pour l’enrichir des paires clé/valeur souhaitées (pour mémoire add_to_blog, new_role et mon custom meta ‘imath_user_meta’). Pour cela, il suffit d’ajouter une action lorsque la fonction bp_complete_signup est jouée.

<?php
/**
 * imath_custom_registration
 * to add custom user meta, blog and role to base_prefix->signups
 */
function imath_custom_registration() {
    global $wpdb;
    $userlogin = $_POST['signup_username'];
    $new_usermeta = maybe_unserialize( $wpdb->get_var( "SELECT meta FROM {$wpdb->base_prefix}signups WHERE user_login='$userlogin'") );
    
    if( $new_usermeta ){
        $new_usermeta['imath_user_meta'] = $_POST['imath_user_meta'];
        
        if( isset($_POST['site_id'] ) && $_POST['site_id'] !=1 ) {
            //this will add the user to the site_id once he activated his account
            $new_usermeta['add_to_blog'] = $_POST['site_id'];
            $new_usermeta['new_role'] = 'subscriber';
        }
        
        $update_usermeta = $wpdb->update( $wpdb->base_prefix.'signups', array(
            'meta' => maybe_serialize( $new_usermeta)
        ), array( 
            'user_login' => $userlogin )
        );
    }
}
add_action( 'bp_complete_signup','imath_custom_registration' );

Ainsi lorsque le nouvel utilisateur activera son compte, il sera automatiquement inscrit sur le blog qu’il a choisi. Il nous reste cependant à traiter le cas de mon custom meta qui lui ne bénéficiera pas des fonctions intégrées par WordPress ou BuddyPress. Pour cela, dés que la fonction bp_core_activated_user est jouée par BuddyPress, on l’intercepte pour lui ajouter une action spécifique pour le traitement de mon custom meta.

<?php
/**
 * imath_add_custom_meta
 * to add custom user meta once user has activated his account
 */
function imath_add_custom_meta( $user_id ) {
    global $wpdb;
    $add_rhmeta = maybe_unserialize( $wpdb->get_var( "SELECT meta FROM {$wpdb->base_prefix}signups LEFT JOIN {$wpdb->base_prefix}users ON({$wpdb->base_prefix}signups.user_login = {$wpdb->base_prefix}users.user_login) WHERE {$wpdb->base_prefix}users.ID='$user_id'" ) );
    
    if( $add_rhmeta ){
        add_user_meta( $user_id, 'imath_user_meta', $add_rhmeta['imath_user_meta'], true );
    }
}
add_action( 'bp_core_activated_user','imath_add_custom_meta' );

IV. Vérification

Pour tester que tout fonctionne bien il suffit de simuler l’inscription d’un nouvel utilisateur, puis une fois le compte activé, de se logger. Ensuite dans le backend de WordPress, on peut vérifier le sous menu « Mes Sites » du Dashboard. Et voilà CQFD !

Tada!

Pour récupérer les 2 child themes utilisés dans cette exprérience..

9 commentaires sur “BuddyPress Registration : mon expérience fumante !

  1. Bonsoir,
    Merci pour ce tuto
    Par ailleurs est-il possible de déplacer le formulaire d’inscription pour qu’il n’apparaisse pas dans la sidebar mais dans une div de mon choix ?

  2. @judejst, bonsoir,

    En fait le formulaire d’inscription n’est pas dans la sidebar, je pense que tu veux parler du lien vers ce formulaire.

    Effectivement tu peux déplacer ce lien à l’endroit de ton choix. La seule chose sur laquelle tu dois être vigilant c’est de bien embarquer le code du point III.1 s’il s’agit d’un blog enfant.

    Merci pour ton commentaire
    A+

  3. Très intéressant cette expérience, je découvre ton blog avec plaisir et j’y ai déjà appris quelques astuces sur cette page !

    Je vais m’abonner.

    A très vite, amicalement

  4. Après avoir lu ton excellent article, je suis tombé sur ce plugin :
    http://wordpress.org/extend/plugins/bp-registration-options/
    il y a aussi BP Xtra Signup…
    Ce que je trouverai particulièrement intéressant serait un plugin qui permette de simplifier AU MAXIMUM le formulaire d’inscription Buddypress, pour ne garder que les champs suivants (comme dans la plupart des réseaux sociaux) :

    1- username
    2- email
    3- mot de passe (x2)…

    La piste serait peut-être de dérouter l’utilisateur vers la page d’inscription native de WordPress et désactiver le dossier registration de BP et utiliser à la place : wp-login.php?action=register
    En utilisant un plugin de customisation de cette page (plugins plus nombreux pour la page WP d’inscription « classique »…)
    Qu’en penses-tu ?

  5. Salut @ Mecanographik,

    Merci pour ton commentaire et ton compliment sur son contenu. Dernièrement on m’a demandé d’inclure le formulaire de registration dans le header, une autre fois dans une fenêtre modale.. Minimiser pour simplifier l’inscription est effectivement intéressant. Simplement, il me semble qu’en fonction de ta config (si upload avatar autorisé, création de blog autorisée…), le nombre d’étapes peut être différent. Faire un plugin, c’est nécessairement envisager tous ces cas de figure..

    J’ai regardé le code source pour répondre aux demandes dont je parle au début de ma réponse. Le plus simple en général est de créer (dans le thème actif) son propre template ‘registration/register.php’ et de l’adapter en fonction de ses besoins. Mon expérience sur le sujet a consisté à créer un header minimal et spécifique ensuite, je n’avais plus qu’à utiliser thickbox par exemple..

    Sinon, je pense qu’il serait intéressant de réfléchir à une fonction d’enregistrement de l’utilisateur via AJAX par exemple.. Ce qui accélèrerai le processus 😉

    A+

Les commentaires sont fermés.