Encapsuler la navigation BuddyPress dans un wp_nav_menu

Depuis WordPress 3.0, il est possible de facilement concevoir des menus personnalis√©s gr√Ęce √† l’interface Menus de l’espace Apparence de l’administration WordPress. Mon propos n’est pas de d√©crire cette fonctionnalit√© mais de voir comment faire en sorte que les diff√©rents composants de BuddyPress s’int√®grent dans un wp_nav_menu.

Pour ceux qui ne ma√ģtrisent pas compl√®tement cette fonctionnalit√©, je vous invite √† lire l’excellent tutoriel de Justin Tadlock : elle n’aura plus de secret pour vous.

L’objectif de ce tuto : cr√©er un drop down menu ¬ę¬†Communaut√©¬†¬Ľ dans lequel seront encapsul√©s les composants BuddyPress : Activit√©, Membres, Groupes, Forums, Blogs mais aussi les composants ajout√©s par d’autres plugins BuddyPress.

Illustration de l’objectif √† atteindre

Pour y parvenir, nous aurons besoin de :

  1. WordPress 3.0.+ et BuddyPress (évidemment !!)
  2. une bonne dose de CSS
  3. un léger jQuery
  4. un child theme de BP-Default avec le précieux functions.php

I. Activation du support et création du Menu de notre thème

Pour activer le support des menus pour notre child thème, il suffit de commencer par écrire quelques lignes de code dans notre script functions.php

<?php
function register_my_menu() {
   register_nav_menu( 'primary-menu', __( 'Primary Menu' ) );
}
add_action( 'init', 'register_my_menu' );

Ainsi, depuis l’administration WordPress, il sera d√©sormais possible de param√©trer notre menu. Avant de s’y jeter comme des morts de faim, n’oublions pas d’ajouter les autres fichiers de notre th√®me !!

Les fichiers du thème

Tr√®s important notre feuille de style devra indiquer que notre th√®me est un th√®me enfant de BP-default, pour cela il ne faut pas oublier d’ajouter dans les commentaires du header de ce fichier la mention Template: bp-default.
Ensuite, on ¬ę¬†overwrite¬†¬Ľ le header.php en copiant celui de bp-default dans notre th√®me.

On active le th√®me dans l’administration, et direction Apparence/Menus pour terminer notre menu.

Illustration du menu configuré

La premi√®re chose √† faire dans la box de droite est d’ajouter le nom de notre menu ¬ę¬†buddy¬†¬Ľ (c’est important que √ßa soit ce terme, car l’id g√©n√©r√© par WordPress – qui nous sera utile dans le css – sera menu-buddy) puis de cliquer sur le bouton de cr√©ation de menu.
A ce moment de la partie les autres boxes qui √©taient jusqu’√† pr√©sent gris√©es sont disponibles et nous allons indiquer dans la box ¬ę¬†theme locations¬†¬Ľ que pour le menu du th√®me nous allons utiliser notre ¬ę¬†buddy¬†¬Ľ en le s√©lectionnant dans la liste d√©roulante. Apr√®s avoir cliqu√© sur le bouton d’enregistrement de cette box, nous pouvons lui ajouter des liens, des pages etc..

Il sera important de pouvoir personnaliser la classe de certains √©l√©ments de notre menu, aussi, il s’agit de veiller depuis les screen options que la case √† cocher soit bien activ√©e.

Dans notre exemple, j’ai pr√©alablement cr√©er une page ¬ę¬†home¬†¬Ľ que j’ai ensuite fix√©e comme page d’accueil statique du blog √† l’aide du menu ¬ę¬†R√©glages/Lecture¬†¬Ľ de l’Admin WordPress. Depuis la box Pages de l’interface de management des menus, j’ai s√©lectionn√© cette page puis l’ai ajout√©e au menu. Ensuite, j’ai utilis√© la box ¬ę¬†Custom Links¬†¬Ľ pour ajouter ma ¬ę¬†BuddyPress-nav¬†¬Ľ en indiquant une URL dans un premier temps, puis une fois ajout√©e au menu, j’ai retir√© cette URL. En effet, BuddyPress-nav nous servira uniquement √† afficher sur click un drop down des composants BuddyPress.
Il est cependant important d’ajouter la classe dropdown √† cet item, car le javascript en aura besoin pour l’effet de d√©pliage des liens BuddyPress. Il nous reste plus qu’√† enregistrer le menu avant de passer √† la suite.

II. Adaptation du header.php et ajout des fonctions dans functions.php

Nous avons donc r√©cup√©rer dans la premi√®re partie le header.php de BP-default en le copiant dans le r√©pertoire de notre th√®me, il s’agit d√©sormais de le pr√©parer √† accueillir notre menu.Pour cela, il suffit de supprimer les lignes 46 √† 82 c’est √† dire depuis <ul id="nav"> jusqu'√† </ul><!-- #nav -->.

Pour tester que le menu est bien appelé, on peut éventuellement remplacer ce code supprimé par

<?php
wp_nav_menu( array(
 'theme_location' => 'primary-menu',
 'fallback_cb' => '',
 'container' =>'',
 'echo' => '1'
) );

Si vous affichez le blog, vous devriez voir un lien vers home et dessous le terme BuddyPress-nav juste en dessous de la top barre de BuddyPress. Ceci fait, il nous reste du pain sur la planche car nous allons remplacé cet appel à wp_nav_menu() par une fonction personnalisée qui sera contenu dans notre functions.php

Cette fonction s’appelle imath_nav_menu() ūüėČ elle est √† ajouter au script functions.php de notre th√®me

function imath_nav_menu() {
   //if echo is set to 0 then we can set a variable to store the html code of the menu
   $menu = wp_nav_menu( array(
    'theme_location' => 'primary-menu',
    'fallback_cb' => '',
    'container' =>'',
    'echo' => '0' )
    );
   $buddynav = imath_buddy_nav();

   //Let's parse this thanks to simple_xml
   $xml = simplexml_load_string( $menu );

   if( $xml ){
     foreach( $xml->li as $bp_items ) {
       //if the xml item is BuddyPress-nav, then we can build the dropdown list of BP components !
       if( $bp_items->a == "BuddyPress-nav" ) {
         $bp_items->a = BP_IMATH_NAV_TITLE;

         if( imath_is_selected_subitem( $buddynav ) ) {
           $bp_items->attributes()->class = $bp_items->attributes()->class.' selected';
         }

         $bp_items->addChild( 'ul' );
         $bp_items->ul->addAttribute( 'class','sub-menu' );

         if( count( buddynav )>=1 ) {
           for( $i=0; $i < count( $buddynav ); $i++ ) {
             $bp_items->ul->addChild('li');
             $bp_items->ul->li[$i]->addAttribute( 'class','imath-subitems '.$buddynav[ $i ]['class'] );
             $bp_items->ul->li[ $i ]->addChild( 'a', $buddynav[ $i ]['content']);
             $bp_items->ul->li[ $i ]->a->addAttribute( 'href', $buddynav[ $i ]['href']);
             $bp_items->ul->li[ $i ]->a->addAttribute( 'title', $buddynav[ $i ]['title'] );
           }
         }
       }
     }
     // let's display the menu !     echo $xml->asXML();
   } else {
     echo '<ul id="menu-buddy"><li><a href="'.site_url('wp-admin').'/nav-menus.php">add a custom menu and call it buddy !</a></li></ul>';
   }
}

La premi√®re chose que fait cette fonction est de r√©cup√©rer le code html du menu et de le stocker dans la variable $menu. Ensuite, elle fait appel √† une autre fonction que je d√©taillerai plus bas afin de stocker dans la variable $buddynav la navigation BuddyPress sous la forme d’un tableau. A l’aide de simplexml, nous parsons le code html du menu √† la recherche de BuddyPress-nav. Une fois identifi√©, il s’agit de recomposer le code html de notre futur menu pour y encapsuler les composants BuddyPress.

Pour permettre de variabiliser le titre de la navigation BuddyPress-nav, j’utilise une constante qu’il convient de d√©finir au tout d√©but de notre script functions.php :

define( 'BP_IMATH_NAV_TITLE', "Communauté");

Intéressons nous désormais à la fonction imath_buddy_nav qui est déterminante dans la constitution du tableau $buddynav.

<?php
function imath_buddy_nav(){
    $buddy_comps = array();
    // let's create an array of the bp main directories navigation

    if ( 'activity' != bp_dtheme_page_on_front() && bp_is_active( 'activity' ) ) {
        if ( bp_is_page( BP_ACTIVITY_SLUG ) ) {
            $buddy_comps[] = array(
                'class'   => 'selected',
                'href'    => site_url() .'/'. BP_ACTIVITY_SLUG.'/',
                'title'   => __( 'Activity', 'buddypress' ),
                'content' => __( 'Activity', 'buddypress' )
            );
        } else {
            $buddy_comps[] = array(
                'href'    => site_url() .'/'. BP_ACTIVITY_SLUG.'/',
                'title'   => __( 'Activity', 'buddypress' ),
                'content' => __( 'Activity', 'buddypress' )
            );
        }
    }

    if ( bp_is_page( BP_MEMBERS_SLUG ) || bp_is_member() ) {
        $buddy_comps[] = array(
            'class'   => 'selected',
            'href'    => site_url() .'/'. BP_MEMBERS_SLUG.'/',
            'title'   => __( 'Members', 'buddypress' ),
            'content' => __( 'Members', 'buddypress' )
        );
    } else {
        $buddy_comps[] = array(
            'href'    => site_url() .'/'. BP_MEMBERS_SLUG.'/',
            'title'   => __( 'Members', 'buddypress' ),
            'content' => __( 'Members', 'buddypress' )
        );
    }

    if ( bp_is_active( 'groups' ) ) {
        if ( bp_is_page( BP_GROUPS_SLUG ) || bp_is_group() ) {
            $buddy_comps[] = array(
                'class'   =>"selected",
                'href'    => site_url() .'/'. BP_GROUPS_SLUG.'/',
                'title'   => __( 'Groups', 'buddypress' ),
                'content' => __( 'Groups', 'buddypress' )
            );
        } else {
            $buddy_comps[] = array(
                'href'    => site_url() .'/'. BP_GROUPS_SLUG.'/',
                'title'   => __( 'Groups', 'buddypress' ),
                'content' => __( 'Groups', 'buddypress' )
            );
        }
    }
    
    if ( bp_is_active( 'forums' ) && ( function_exists( 'bp_forums_is_installed_correctly' ) && !(int) bp_get_option( 'bp-disable-forum-directory' ) ) && bp_forums_is_installed_correctly() ){
        if ( bp_is_page( BP_FORUMS_SLUG ) ) {
            $buddy_comps[] = array(
                'class'   =>"selected",
                'href'    => site_url() .'/'. BP_FORUMS_SLUG.'/',
                'title'   => __( 'Forums', 'buddypress' ),
                'content' => __( 'Forums', 'buddypress' )
            );
        } else {
            $buddy_comps[] = array(
                'href'    => site_url() .'/'. BP_FORUMS_SLUG.'/',
                'title'   => __( 'Forums', 'buddypress' ),
                'content' => __( 'Forums', 'buddypress' )
            );
        }
    }
    
    if ( bp_is_active( 'blogs' ) && bp_core_is_multisite() ) {
        if ( bp_is_page( BP_BLOGS_SLUG ) ){
            $buddy_comps[] = array( 
                'class'=>"selected",
                'href'=> site_url() .'/'. BP_BLOGS_SLUG.'/',
                'title'=> __( 'Blogs', 'buddypress' ),
                'content' => __( 'Blogs', 'buddypress' )
            );
        } else {
            $buddy_comps[] = array(
                'href'    => site_url() .'/'. BP_BLOGS_SLUG.'/',
                'title'   => __( 'Blogs', 'buddypress' ),
                'content' => __( 'Blogs', 'buddypress' )
            );
        }
    }

    //to catch the bp_nav_items of other BuddyPress plugins, we use the buffer to store it in a variable
    ob_start();
    do_action( 'bp_nav_items' );
    
    $bp_plugins_nav = ob_get_contents();
    ob_end_clean();
    
    //if some plugins use bp_nav_items hook, then simplexml will help us to parse it and add it to our array
    if( $bp_plugins_nav ){
        $xml_bp_nav_items = simplexml_load_string( '<ul>' . $bp_plugins_nav . '</ul>' );
        
        foreach( $xml_bp_nav_items->li as $item ){
            $li_class = $item->attributes();
            
            foreach( $item->a as $link ){
                $link_attr = $link->attributes();
                
                if( $li_class ) {
                    $buddy_comps[] = array(
                        'class'   =>$li_class['class'],
                        'href'    => $link_attr['href'],
                        'title'   => $link_attr['title'],
                        'content' => $link
                    );
                } else {
                    $buddy_comps[] = array(
                        'href'    => $link_attr['href'],
                        'title'   => $link_attr['title'],
                        'content' => $link
                    );
                } 
            }
        }
    }
    
    //send the array to imath_nav_menu function
    return $buddy_comps;
}

Le tableau $buddy_comps r√©cup√®re donc les composants BuddyPress activ√©s ainsi que ceux des plugins BuddyPress qui utilisent le hook do_action(‘bp_nav_items’);. Dans ma config, c’est le cas de mon plugin BP Code Snippets ou du tr√®s int√©ressant BuddyPress Links.

Il y a une fonction appel√©e par imath_nav_menu que nous n’avons pas d√©taill√©e et qui permet d’ajouter la classe ¬ę¬†selected¬†¬Ľ au menu ¬ę¬†Communaut√©¬†¬Ľ et donc un affichage particulier pour que l’utlisateur sache qu’il est bien en train de naviguer sur un composant BuddyPress comme illustr√© ci-dessous.

Illustration du dropdown menu

Voici donc cette fonction :

<?php
function imath_is_selected_subitem( $buddy_nav ) {
    foreach( $buddy_nav as $look_selected ) {
        // if one of the element of the array contains the key class set to selected then we're browsing a community component
        if( $look_selected['class'] == "selected"  ){
            return true;
        }
    }
    
    return false;
}

Pour terminer cette partie, il convient de retourner dans le script header.php pour remplacer l’appel √† wp_nav_menu par notre fameuse fonction imath_nav_menu. Rien de plus simple ūüôā

<?php imath_nav_menu();?>

La touche finale : css et jQuery ūüėČ

En ce qui concerne la feuille de style, je vous laisse la d√©couvrir dans le fichier style.css du th√®me en t√©l√©chargement. S’agissant du jQuery, il suffit d’intercepter le hook wp_head de WordPress pour charger le code javascript qui permettra de r√©aliser l’effet de drop down suite au click du menu ¬ę¬†Communaut√©¬†¬Ľ.

<?php
function imath_add_js_head() {
    if( ! is_admin () ) {
        ?>
        <script type="text/javascript">
        jQuery( document ).ready( function() {
            jQuery( '.dropdown' ).click( function() {
                jQuery( this ).find( '.imath-subitems' )
                              .slideDown('fast')
                              .show();
                              //Drop down the subnav on click

                jQuery( this ).hover( function() {}, function(){
                    jQuery(this).find( '.imath-subitems').slideUp( 'slow' );
                    //When the mouse hovers out of the subnav, move it back up
                } );
            } );
        } );
        </script>
        
        <?php
    }
}
add_action( 'wp_head', 'imath_add_js_head' );

Conclusion

Bien entendu, il serait tout √† fait possible de faire autrement, notamment en ajoutant manuellement les liens vers les composants BuddyPress en utilisant la box Custom Links de l’interface d’administration des menus autant de fois que de composants. Je trouve que l’avantage de cette solution est de le faire une bonne fois pour toute !!

A+

7 commentaires sur “Encapsuler la navigation BuddyPress dans un wp_nav_menu

  1. Bonjour,

    Je suis un enseignant, je viens de débuter avec wordpress je veux faire un réseau social pour nous les enseignants a Tunis.

    Ton tutoriel tombe a pic pour mon probleme.

    Malheureusement, j’ai suivi mais cela ne marche pas. D‚Äôailleurs des la premi√®re √©tape je me bloc car je trouve pas le meme menu que vous.

    Apparence/menu , je creer je menu buddy et puis je trouve pas Home et Buddypress-nav.

    Si cela ne vous d√©range pas, pourriez vous m’expliquer d’avantage.

    J’utilise le theme par d√©faut de buddypress.

    Merci beaucoup,

  2. Bonjour,

    Je suis infographiste (Illustration / 3D) avec un niveau relativement avancé sur wordpress et le codage web.

    J’ai install√© votre th√®me sur un site de d√©mo.

    J’ai bien int√©gr√© le fonctionnement du menu d√©roulant ¬ę¬†communaut√©¬†¬Ľ, mais il semble que le th√®me ne prend plus en compte correctement la mise en place de sous-menu standard du theme Buddypress par d√©faut.

    En effet ils apparaissent du coup directement ¬ę¬†d√©roul√©¬†¬Ľ

    Y’a t’il une class CSS particuli√®re a entrer ? J’ai essay√© dropdown mais cela ne donne rien.

    Je regarde de plus pr√®s le code de mon c√īt√© ( l’ajout d’une classe qui int√®gre la mise en forme menu standard peut √™tre).

    Merci de votre aide,

    Romuald

    1. Bonjour Romuald,

      Dans WP backend > Apparence > Menus du child th√®me, tu peux essayer d’ajouter une nouvelle entr√©e de menu ayant pour class ¬ę¬†dropdown¬†¬Ľ et pour les pages que tu rattacheras √† cette entr√©e, utilises la class ¬ę¬†imath-subitems¬†¬Ľ..

      J’ai test√© : √ßa fonctionne.

Les commentaires sont fermés.