tomauger
  • 0
Эксперт

Отображать пункт меню навигации в зависимости от возможностей пользователя

  • 0

У меня есть одна «ветвь» дерева навигации моего основного сайта, которая должна быть доступна только для набора зарегистрированных, вошедших в систему пользователей. Я понимаю, как запросить роль и возможности пользователя. Этот вопрос касается именно того, как лучше всего использовать встроенное навигационное меню, но просто условно скрыть элемент.

Нужно ли мне перегружать встроенную навигацию по умолчанию, писать собственный запрос и создавать структуру навигации вручную? Я хотел бы избежать этого, если это возможно.

Мне не нужны полные примеры кода, только ваши идеи и общая структура/подход.

Зацените совет!

Т

Share
  1. Я написал сообщение в блоге, связанное с этой проблемой. Конкретный вариант использования сокрытия пунктов меню от пользователей, не имеющих доступа, см. в этом подробном посте.

    • 0
    • Абсолютно блестящий. Спасибо за это — хотя я удивлен, что это так сложно. Как вы сказали, возможно, оплошность?

      • 0
    • Таким образом, ходок хорош для того, чтобы убедиться, что пункт меню, помеченный как «защищенный», не появляется. Но как создать элемент меню, помеченный как «защищенный» или, что еще лучше, относящийся к определенной роли или возможности? Похоже, мы расширяем элементы меню и добавляем еще несколько настраиваемых пользователем параметров в форму элемента меню…?

      • 0
    • @TomAuger Добавьте соответствующие метаданные в связанный объект записи, например пользовательскую таксономию или метаполе публикации. Проверьте значение поля в ходунке.

      • 0
    • Спасибо за разъяснения. Абсолютно индивидуальная таксономия или настраиваемое поле были бы правильным выбором. Другой вариант, который я придумал, основан на шаблоне. Мне не так нравится мое решение, потому что вы не должны связывать шаблон со встроенной функциональностью, как это, но есть логическая связь между шаблоном (который должен проверять, есть ли у пользователя доступ для просмотра содержимого) и меню. Я собираюсь опубликовать свой код в ответе ниже для других пользователей с тем же вопросом.

      • 0
    • Теперь вам нужно управлять одним меню для каждой роли. Я бы предпочел добавить флажки к пунктам меню в редакторе. К сожалению, для этого нет do_action() встроенного class Walker_Nav_Menu_Edit API. Похоже на оплошность.

      • 0
    • Я согласен, и я сам предпочел бы добавить флажок или простое поле ввода для хранения нужного имени роли, но снова я опубликовал этот ответ в качестве альтернативы вашему. Существует возможность использовать поле описания для каждого элемента, и на основе этого вы можете проверить роль, но тогда вы потеряете возможность описания. это новый API, дайте ему немного времени и откройте много билетов на треки, сколько сможете, чтобы он заработал 🙂

      • 0
    • Спасибо за этот более простой подход. Я лично содрогаюсь от необходимости определять свои меню через код — для меня это полностью подрывает одну из основных функций wp_admin, но, возможно, нет более простой альтернативы.

      • 0
    • Я добавил этот ответ, хотя с тех пор, как этот вопрос был активен, прошло некоторое время, потому что я подумал, что он может быть полезен другим.

      • 0
    • +1 Спасибо, что нашли время добавить свое решение! Это всегда ценят другие, которые натыкаются на вопрос в поиске Google или SE. Ваше здоровье!

      • 0
  2. Используйте свой собственный ходун и проверьте возможности, прежде чем создавать предмет.

    • 0
  3. Кто-то сделал блестящий плагин, чтобы сделать это без кодирования. Даже имеет флажки в интерфейсе редактора меню для выбора утвержденных ролей для каждого пункта меню.

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

    • 0
  4. Опубликованный ответ toscho правильный, но для немногих людей, которые знают, что они делают и как это делать. 🙂 Я добавляю это для остального мира как более простое решение для менее продвинутых пользователей. Идея заключалась бы в том, чтобы иметь разные меню и просто отображать их в зависимости от роли пользователя.

    Итак, скажем, у вас есть 3 меню с именами редактор, автор и по умолчанию:

    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' ));
    }
    
    • 0
  5. Проблема с переопределением start_el и end_el заключается в том, что это управляет только отображением рассматриваемого пункта меню — это не влияет на отображение дочерних элементов. Я думаю, вам нужно переопределить display_element, чтобы скрыть дочерние элементы.

    Кроме того, можно использовать поле описания пункта меню для хранения информации для каждого пункта меню о том, отображать его или нет.

    Этот код ищет в описании каждого пункта меню список возможностей, разделенных запятыми, таких как [capability: this_one, next_one], и ​​если текущий пользователь не имеет ни одной из возможностей, он не будет отображать элемент (или любой из его дочерних элементов). Довольно легко удалить строки из описания, если вы действительно хотите использовать описание по назначению.

    /*
     * 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;
    
    }
    
    • 0
  6. Я попробовал свои силы в использовании поля описания, чтобы определить, какие роли могут получить доступ к каким пунктам меню, и основывал свои модификации на коде, который я получил отсюда — Прокачай мое меню WP.

    Моя модифицированная версия:

    <?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');
    
    ?>
    

    Это еще не самая чистая версия, но она работает. Я надеюсь, что кто-то еще может использовать его с пользой.

    • 0
  7. Я собираюсь опубликовать свое решение для других, которые могут встретиться в этой теме. Я не на 100% доволен этим, потому что вы не должны сочетать шаблон с функциональностью меню (подход Toscho с использованием метаданных или пользовательской таксономии, вероятно, более правильный). Однако это быстро и грязно. Я попытался смягчить тесную связь, предоставив некоторые константы в верхней части functions.php, чтобы помочь будущим разработчикам поддерживать код:

    // 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');
    

    Таким образом, шаблон защищенной страницы — это просто вариант single.php, но он будет проверять, может ли current_user_can(ZG_PROTECTED_PAGE_CAPABILITY) перед отображением любого контента по соображениям безопасности.

    Затем я реализую собственный ходок, как предложил Тошо. Ходок в данном случае предельно прост — мы переопределяем публичные методы start_el и end_el у Walker_Nav_Menu, просто перехватывая их достаточно долго, чтобы задать вопрос: есть ли у нас доступ для просмотра пункта меню?

    Правило простое: если страница не является «приватной» страницей (что в данном случае определяется этой страницей с использованием определенного шаблона страницы), она видна. Если это ЯВЛЯЕТСЯ «частной» страницей, и пользователь аутентифицирован в роли, которая имеет настраиваемую возможность, которую мы ищем, тогда она видна. В противном случае его не видно.

    Если у нас есть доступ, то нам просто нужно использовать встроенные методы Walker_Nav_Menu без изменений, поэтому мы вызываем метод parent:: с тем же именем.

    /* 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

Оставить ответ

You must login to add an answer.