web-dev-qa-db-fra.com

Afficher un élément de menu de navigation conditionnellement en fonction des capacités de l'utilisateur

J'ai une "branche" de l'arborescence de navigation de mon site principal qui ne devrait être accessible qu'à un ensemble d'utilisateurs enregistrés et connectés. Je comprends comment interroger le rôle et les capacités d'un utilisateur. Cette question concerne spécifiquement le meilleur moyen de tirer parti du menu de navigation intégré, tout en masquant un élément de manière conditionnelle.

Dois-je surcharger la navigation par défaut intégrée, écrire une requête personnalisée et construire la structure de navigation manuellement? J'aimerais éviter cela si possible.

Je n'ai pas besoin d'échantillons de code complets, juste de vos idées et du cadre général/de l'approche.

Appréciez le conseil!

T

5
Tom Auger

Utilisez votre propre walker et vérifiez la capacité avant de créer un élément.

4
fuxia

Quelqu'un a fait un plugin brillant pour le faire sans codage. Même a des cases à cocher dans l'interface de l'éditeur de menu pour sélectionner les rôles approuvés par élément de menu.

http://wordpress.org/extend/plugins/nav-menu-roles/

4
somatic

La réponse toscho affichée est correcte mais pour les quelques personnes qui savent ce qu’elles font et comment le faire. :) J'ajoute ceci pour le reste du monde en tant que solution plus simple pour les utilisateurs moins avancés. L'idée serait d'avoir différents menus et de les afficher uniquement en fonction du rôle de l'utilisateur.

Donc, disons que vous avez 3 menus nommés éditeur, auteur et par défaut:

if (current_user_can('Editor')){
    //menu for editor role
    wp_nav_menu( array('menu' => 'editor' ));

}elseif(current_user_can('Author')){
    //menu for author role
    wp_nav_menu( array('menu' => 'author' ));

}else{
    //default menu
    wp_nav_menu( array('menu' => 'default' ));
}
3
Bainternet

Le problème avec l'annulation de start_el et end_el est que cela ne fait que contrôler l'affichage de l'élément de menu en question - cela n'affecte pas l'affichage des enfants. Je pense que vous devez également remplacer display_element pour masquer les enfants.

En outre, il est possible d’utiliser le champ de description de l’élément de menu pour stocker des informations sur chaque élément de menu, qu’il s’agisse de les afficher ou non.

Ce code recherche dans la description de chaque élément de menu une liste de fonctionnalités séparées par des virgules, telles que [capacité: this_one, next_one], et si l'utilisateur actuel ne dispose d'aucune de ces fonctionnalités, il n'affiche pas l'élément (ni aucun de ses enfants). Il est assez facile de supprimer les chaînes de la description si vous souhaitez réellement utiliser la description dans le but recherché.

/*
 * hide or display menus based on user capabilities
 *
 * Use the description field of the custom menu item. If it contains a string like [capability: xx, xx] 
 * display the menu item only if the user has at least one of the capabilities.
 * If a menu item is not displayed, nor are any of its sub items.
 */
/* Custom Walker */
class NASS_Nav_Walker extends Walker_Nav_Menu {

        // override parent method
        function display_element( $element, &$children_elements, $max_depth, $depth=0, $args, &$output ) {
            // we know the $element is a menu item  
            // we want to check its description field to see if it's OK to display it
            // in which case we just retreat to the parent method
            $desc = $element->description;
            if ( should_display_menu_item($desc) ) {
                parent::display_element( $element, &$children_elements, $max_depth, $depth=0, $args, &$output );
            } else {
                return;
            }
        }    
}
/* should we display the menu item, if this is its description? */
function should_display_menu_item( $desc ) {
    // first see if the description contains a capability specification of the form
    // [capability: comma, delimited, list]
    // we assume all capability names consist only of lower case with underbars
    $prefix = "\[capability:";
    $postfix = "\]";
    $pattern = '@' . $prefix . '([a-z_, ]+)' . $postfix . '@';
    $answer = true;
    if ( preg_match($pattern, $desc, $matches) ) { // if we've got a match
        $found = $matches[1];   // the parenthesized bit of the regex
        $caps = array_map('trim', explode(",", $found));
        if ( count ($caps) > 0 ) { // there is at least one
            $answer = false;
            // now see if the user has any of them
            foreach ($caps as $cap) {
                if ( current_user_can ($cap) ) $answer = true;
            }
        }
    }
    return $answer;

}
2
lpryor

J'ai essayé d'utiliser le champ de description pour savoir quels rôles peuvent accéder à quels éléments de menu et mes modifications sont basées sur le code obtenu - Pimp my WP Menu

Ma version modifiée:

<?php

/***
* Menu WALKER - for restricting the menu items visibility
* Code modified by - Trupti Bhatt (http://3sided.co.in)
* using original code posted here - http://www.tisseur-de-toile.fr/wordpress-tricks/pimp-my-wordpress-menu-part-2-access-granted-to-authorized-personnel-only.html
***/
class description_walker extends Walker_Nav_Menu
{
        /*
                 *      Custom var to store current role
                 */
                private $current_user_role = "";

                /*
                 *      Get te current user role
                 */
                private function getCurrentUserRole()
                {
                                global $current_user;
                                if ( is_user_logged_in() )
                                {
                                        if ( $this->current_user_role == "" )
                                        {
                                                $this->current_user_role = $current_user->roles[0];
                                        }

                                        return $this->current_user_role;
                                }
                                else
                                {
                                        $this->current_user_role='visitor';
                                        return $this->current_user_role;
                                }
                }

                /*
                 *      Check if the user is an administrator
                 */
                private function isAdmin()
                {
                                $current_role = $this->getCurrentUserRole();

                if ( $current_role == "administrator" )
                                {
                                                return true;
                                }
                                else
                                {
                                                return false;
                                }
                }

                /*
                 *      Get all restrictions
                 */
                private function getAllRestrictions()
                {
                        global $menu_restricted_access_array;


                                $all_restrictions_array = array();

                                foreach ( $menu_restricted_access_array as $one_restriction )
                                {
                                        $all_restrictions_array = array_merge($all_restrictions_array, $one_restriction);
                                }
                                $all_restrictions_array = array_unique($all_restrictions_array);

                                return $all_restrictions_array;
                }

                /*
                 *      Check the access
                 */
                private function isAccessGranted( $id_menu_item )
                {
                                global $menu_restricted_access_array;

                if ( $this->isAdmin() )
                                {
                                                return true;
                                }
                else if ( isset($menu_restricted_access_array[$this->current_user_role]) )
                {
                    $restricted_access = $menu_restricted_access_array[$this->current_user_role];

                    if ( in_array($id_menu_item, $restricted_access) )
                                        {
                        return true;
                                        }
                                        else
                                        {
                        return false;
                                        }
                }
                else {
                        return true;
                                        }

                }

     /*
                 *      Element render
                 */
                function start_el(&$output, $item, $depth, $args)
        {

            global $wp_query, $menu_restricted_access_array;
            global $g_role,$g_pageid;
            $indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';
                        $g_role=strtolower((trim($item->description)));

                        $str = explode(',',$g_role);
                        for( $i=0; $i< count($str); $i++)
                                {                      

                                        if (strtolower(trim($str[$i]))==$this->current_user_role)
                                        {                      
                                                $restriction =$item->object_id;        
                                                $menu_restricted_access_array[$this->current_user_role] =array( $restriction);
                                        }


                                }


            $class_names = $value = '';

            $classes = empty( $item->classes ) ? array() : (array) $item->classes;
            $classes[] = 'menu-item-' . $item->ID;


            /*
             *  First test, add custom class to each menu item
             */
                $classes[] = 'my-custom-menu-class';

            /*
             *  Detect the menu item matching the unpublished page
             *  Detect the menu item matching the unpublished page
             */
                // -> FLag to display the output
                $item_to_display = true;
                $is_item_published = true;

                // -> Gather data of linked object
                $item_data = get_post($item->object_id);

                // --> If it's a page, act on the flag

                if ( !empty($item_data) && ($item->object == "page") )
                {
                    $is_item_published = ( $item_data->post_status == "publish" ) ? true : false;
                    $item_output = "";
                }

            /*
             *  Detect and display by user Role
             **/
                if ( _USE_RESTRICTED_ACCESS )
                {
                    $restrictions_array = $this->getAllRestrictions();
                    $this->isAccessGranted($item->object_id);

                }
                else
                {
                    $item_to_display = $is_item_published;
                }

            $class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item ) );
            $class_names = ' class="' . esc_attr( $class_names ) . '"';



            $id = apply_filters( 'nav_menu_item_id', 'menu-item-'. $item->ID, $item, $args );
            $id = strlen( $id ) ? ' id="' . esc_attr( $id ) . '"' : '';

            $output .= $indent . '<li id="menu-item-'. $item->ID . '"' . $value . $class_names .'>';

            $attributes  = ! empty( $item->attr_title ) ? ' title="'  . esc_attr( $item->attr_title ) .'"' : '';
            $attributes .= ! empty( $item->target )     ? ' target="' . esc_attr( $item->target     ) .'"' : '';
            $attributes .= ! empty( $item->xfn )        ? ' rel="'    . esc_attr( $item->xfn        ) .'"' : '';
            $attributes .= ! empty( $item->url )        ? ' href="'   . esc_attr( $item->url        ) .'"' : '';



                        if($depth != 0)
                        {
                    $description = $append = $prepend = "";
                        }

            // --> If the flag is true, when display the output

            if ( $item_to_display )
            {
                $item_output = $args->before;
                $item_output .= '<a'. $attributes .'>';
                $item_output .= $args->link_before .apply_filters( 'the_title', $item->title, $item->ID ).$append; // this is where the strong tags are prepend and append to the description

                                $item_output .= '</a>';
                $item_output .= $args->after;
            }

            $output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
        }
}
/*
 *      Restrictions configuration
* 2 is page id of Homepage
 **/
define("_USE_RESTRICTED_ACCESS", true);
$menu_restricted_access_array['subscriber'] = array('2');

?>

Ce n'est pas encore la version la plus propre, mais ça marche. J'espère que quelqu'un d'autre pourra en faire un bon usage également.

1
tejas

Je vais poster ma solution pour les autres qui peuvent arriver sur ce fil. Je ne suis pas satisfait à 100%, car vous ne devriez pas associer un modèle à une fonctionnalité de menu (l'approche de Toscho consistant à utiliser des métadonnées ou une taxonomie personnalisée est probablement plus correcte). Cependant, c'est rapide et sale. J'ai essayé d'atténuer le couplage étroit en fournissant des constantes proches du sommet de functions.php pour aider les futurs développeurs à maintenir le code:

// define the custom password-protected template that is used to determine whether this item is protected or not in the menus
define ('ZG_PROTECTED_PAGE_TEMPLATE', 'page-membersonly.php');
// define the custom capability name for protected pages
define ('ZG_PROTECTED_PAGE_CAPABILITY', 'view_member_pages');

Ainsi, le modèle de page protégée est simplement une variante de single.php, mais il vérifiera si current_user_can (ZG_PROTECTED_PAGE_CAPABILITY) avant d'afficher du contenu, pour des raisons de sécurité.

Ensuite, je mets en place un marcheur personnalisé, selon la suggestion de Toscho. Dans ce cas, le lecteur est extrêmement simple: nous substituons les méthodes publiques start_el et end_el publiques de Walker_Nav_Menu, nous les interceptons suffisamment longtemps pour poser la question: avons-nous accès à l'élément de menu?

La règle est simple: si la page n'est pas une page "privée" (qui dans ce cas est déterminée par cette page à l'aide d'un modèle de page particulier), elle est visible. Si IS une page "privée" et si l'utilisateur est authentifié dans un rôle doté de la fonctionnalité personnalisée recherchée, celle-ci est visible. Sinon, ce n'est pas visible.

Si nous avons un accès, nous devons simplement utiliser les méthodes intégrées du Walker_Nav_Menu sans modification, nous appelons donc la méthode parent :: du même nom.

/* Custom Walker to prevent password-protected pages from appearing in the list */
    class HALCO_Nav_Walker extends Walker_Nav_Menu {

        protected $is_private = false;
        protected $page_is_visible = false;

        // override parent method
        function start_el(&$output, $item, $depth, $args) {
            // does this menu item refer to a page that is using our protected template?
            $is_private = get_post_meta($item->object_id, '_wp_page_template', true) == ZG_PROTECTED_PAGE_TEMPLATE;
            $page_is_visible = !$is_private || ($is_private && current_user_can(ZG_PROTECTED_PAGE_CAPABILITY));

            if ($page_is_visible){
                parent::start_el(&$output, $item, $depth, $args);
            }
        }

        // override parent method
        function end_el(&$output, $item, $depth) {
            if ($page_is_visible){
                parent::end_el(&$output, $item, $depth);
            }
        }
    }
0
Tom Auger