Encapsuler la navigation BuddyPress dans un wp_nav_menu

Publié le

par

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 réponses à “Encapsuler la navigation BuddyPress dans un wp_nav_menu”

  1. […] Ce billet était mentionné sur Twitter par Valentin Brandt et imath, MonsieurPedro. MonsieurPedro a dit: RT @geekeriesfr: Encapsuler la navigation #BuddyPress dans un « wp_nav_menu » #WordPress –> http://t.co/DlyFCa2 /via @imath […]

  2. Avatar de Amine
    Amine

    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,

    1. Avatar de imath

      Bonjour Amine,

      Je vous invite à télécharger puis installer et enfin utiliser le child thème que j’ai joint à ce post.

  3. Avatar de Romuald

    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. Avatar de imath

      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.

  4. […] afin d’ajouter des items à un menu existant. Rappelez-vous j’avais proposé une première méthode pour intégrer la navigation BuddyPress à un wp_nav_menu en février dernier. Or via […]

  5. […] afin d’ajouter des equipment à un menu existant. Rappelez-vous j’avais proposé une première méthode flow intégrer la navigation BuddyPress à un wp_nav_menu en février dernier. Or around […]