Как создать пользовательскую роль с определенными возможностями?

30 нояб. 2011 г., 19:15:51
Просмотры: 56.9K
Голосов: 29

Я хочу создать пользовательскую возможность для доступа к интерфейсу моего плагина.

  • Должен ли плагин управлять добавлением этой возможности ко всем учетным записям администратора при активации?
  • Если да: Управляет ли WordPress добавлением возможности всем администраторам дочерних блогов и суперадминистраторам в мультисайтовых установках, или эта функция должна обрабатываться плагином?
1
Комментарии

Подробный блог: http://goo.gl/xNuafH

Suresh Kamrushi Suresh Kamrushi
14 янв. 2016 г. 11:18:27
Все ответы на вопрос 4
3
20

Для плагина, над которым я сейчас работаю, мне нужно было предоставить/ограничить доступ к настройкам плагина (т.е. к соответствующим страницам меню админки) на основе ролей пользователей.
Для этого мне потребовалось добавить новую плагино-специфичную capability (возможность) к user roles (ролям пользователей).

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


План действий

Прежде чем поделиться кодом, вот краткое описание того, что он делает:

  1. При активации плагина добавляем новую возможность THE_NEW_CAP для ролей, у которых уже есть встроенная возможность BUILT_IN_CAP (в моем случае — edit_pages).
  2. При каждой загрузке страницы повторяем пункт 1 (т.е. снова добавляем возможность). Это необходимо только в том случае, если нужно учитывать новые роли, созданные после активации плагина. Такие роли не будут иметь плагино-специфичной возможности, даже если у них есть требуемая встроенная.
  3. Используем новую возможность по своему усмотрению. В моём случае — для управления доступом к страницам меню плагина в админке. Пример кода ниже.
  4. При деактивации плагина удаляем эту возможность. Конечно, можно сделать это и при удалении плагина. В любом случае, это нужно сделать.

Код

А вот реализация описанного выше:

» Настройка

class WPSE35165Plugin {

    public function __construct() {
        // Регистрируем хуки
        register_activation_hook(__FILE__, array(__CLASS__, 'activation'));
        register_deactivation_hook(__FILE__, array(__CLASS__, 'deactivation'));

        // Добавляем действия
        add_action('admin_menu', array(__CLASS__, 'admin_menu'));
    }

    public function activation() {
        self::add_cap();
    }

    // Добавляем новую возможность всем ролям, у которых есть определённая встроенная возможность
    private static function add_cap() {
        $roles = get_editable_roles();
        foreach ($GLOBALS['wp_roles']->role_objects as $key => $role) {
            if (isset($roles[$key]) && $role->has_cap('BUILT_IN_CAP')) {
                $role->add_cap('THE_NEW_CAP');
            }
        }
    }

» Использование

    // Добавляем страницы плагина в меню админки
    public function admin_menu() {
        // Удалите следующую строку, если вас не интересуют новые роли,
        // созданные после активации плагина
        self::add_cap();

        // Настраиваем меню админки плагина
        add_menu_page('Меню', 'Меню', 'THE_NEW_CAP', …);
        add_submenu_page('wpse35165', 'Подменю', 'Подменю', 'THE_NEW_CAP', ...);
    }

» Очистка

    public function deactivation() {
        self::remove_cap();
    }

    // Удаляем плагино-специфичную возможность
    private static function remove_cap() {
        $roles = get_editable_roles();
        foreach ($GLOBALS['wp_roles']->role_objects as $key => $role) {
            if (isset($roles[$key]) && $role->has_cap('THE_NEW_CAP')) {
                $role->remove_cap('THE_NEW_CAP');
            }
        }
    }

}

Примечание: Пожалуйста, не используйте возможности в верхнем регистре. Это сделано только для удобства чтения.

14 мар. 2013 г. 04:24:38
Комментарии

Всегда используйте get_editable_roles() для получения ролей, которые вы хотите редактировать. В противном случае вы можете сломать работу плагинов.

fuxia fuxia
28 апр. 2013 г. 20:38:38

@toscho Ну ладно, видимо, это одна из тех функций, о которых даже Кодекс не знает... ;) Конечно, эта функция имеет право на существование, но в моем случае я не вижу, как использование глобального массива WP_Roles может сломать какие-либо плагины.

tfrommen tfrommen
28 апр. 2013 г. 20:44:42

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

fuxia fuxia
28 апр. 2013 г. 20:54:13
0
12

Удаляйте то, что добавляете

Во-первых, убедитесь, что всё, что вы добавляете при активации, также удаляется при деактивации. У меня есть краткое руководство с примером кода для вас.

Тестируем с небольшим плагином:

Я не очень разбираюсь в MU, но насколько я понимаю, объект ролей является глобальным для всех блогов. Просто попробуйте этот небольшой плагин и посмотрите, что получится:

<?php
/*
Plugin Name:    MU Roles check
Plugin URI:     https://github.com/franz-josef-kaiser/
Description:    Проверка ролей при просмотре блога
Author:     Franz Josef Kaiser
Author URI:     https://plus.google.com/u/0/107110219316412982437
Version:        0.1
Text Domain:    murc
License:        GPL v2 - http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*/

/**
 * Показывает данные блога и названия ролей в этом блоге
 * Также показывает, была ли кастомная возможность успешно добавлена, или отображает n/a для роли
 * 
 * @return void
 */
function wpse35165_role_check()
{
    $blog = get_current_site();
    $custom_cap = 'name_of_your_custom_capability';

    $html = "<hr /><table>";
    $html .= "<caption>Список ролей в (Блоге) {$blog->site_name} / ID#{$blog->id}</caption>"
    $html .= "<thead><tr><th>Название роли</th><th>Возможности</th></tr></thead><tbody>";
    foreach ( $GLOBALS['wp_roles'] as $name => $role_obj )
    {
        $cap = in_array( $custom_cap, $role_obj->caps ) ? $custom_cap : 'n/a';
        $cap = $cap OR in_array( $custom_cap, $role_obj->allcaps ) ? $custom_cap : 'n/a';
        $html .= "<tr><td>{$name}</td><td>{$cap}</td></tr>";
    }
    $html .= '</tbody></table>';

    print $html;
}
add_action( 'shutdown', 'wpse35165_role_check' );

Добавление возможностей

/**
 * Добавляет возможность к объектам ролей
 * Должно быть в вашей функции активации и выполнено до проверки вашим плагином
 * 
 * @return void
 */
function wpse35165_add_cap()
{
    $custom_cap = 'name_of_your_custom_capability';
    $min_cap    = 'the_minimum_required_built_in_cap'; // Проверьте "Таблица ролей и объектов" в кодексе!
    $grant      = true; 

    foreach ( $GLOBALS['wp_roles'] as $role_obj )
    {
        if ( 
            ! $role_obj->has_cap( $custom_cap ) 
            AND $role_obj->has_cap( $min_cap )
        )
            $role_obj->add_cap( $custom_cap, $grant );
    }
}

Примечание: Вы можете добавить возможность к роли без предоставления доступа к ней — просто установите второй аргумент $grant = false;. Это позволяет вручную добавлять возможность отдельным пользователям, установив последний аргумент в true.

30 нояб. 2011 г. 23:26:14
0

Протестировано с WordPress 6.0 и работает:

add_action( 'activated_plugin',function( $plugin,$network_activation ){
    add_role( 'your_custom_role_slug', __( 'Название вашей кастомной роли','your-plugin-domain' ),
        array(
            'read' => true,
            'view_admin_dashboard' => true,
            'activate_plugins' => false,
            'deactivate_plugins' => false,
            'your_custom_capability' => true
        )
    );
}, 10, 2 );

В массиве приведены лишь некоторые примеры возможностей (capabilities). Вы можете без проблем добавить свою собственную возможность. Эта кастомная возможность будет сохранена вместе с остальными.

С этим методом вы не сможете указать, что именно можно делать с "your_custom_capability", но в большинстве случаев, как в данном вопросе, вам нужно лишь проверить, имеет ли текущий пользователь эту возможность. Если вы хотите показывать страницы настроек вашего плагина только пользователям с возможностью "your_custom_capability", вы можете сделать это без проблем. Используйте встроенные возможности при создании роли, чтобы определить, что ещё могут видеть и делать пользователи с ролью "your_custom_role_slug".

Это вернёт true, если пользователь имеет роль "your_custom_role_slug":

current_user_can( 'your_custom_capability' );

А это покажет страницу настроек только если пользователь имеет возможность "your_custom_capability":

add_menu_page( __( 'Ваш заголовок','eos-dp' ),__( 'Ваш заголовок','your-domain' ),'your_custom_capability,'your_page_slug','your_function_callback','dashicons-your-icon',20 );

Затем при удалении плагина я бы удалил пользовательскую роль с помощью:

remove_role( 'your_custom_role_slug' );
10 июн. 2022 г. 18:38:30
1

Это работает для меня:

add_action('admin_init', 'add_custom_cap');
function add_custom_cap()
{
  $custom_cap = 'test_cap';
  $min_cap    = 'read';
  $grant      = true;
  $to_role = 'your_user_role';
  $role = 'user_role';

  foreach ( $GLOBALS['wp_roles'] as $role_obj )
  {
    if (is_object($role_obj[$role])) {
      if (!$role_obj[$role]->has_cap( $custom_cap ) && $role_obj[$role]->has_cap( $min_cap )) {
        $role_obj[$role]->add_cap( $custom_cap, $grant );
      }
    }
  }
}
31 авг. 2018 г. 14:48:45
Комментарии

Никогда не изменяйте глобальные роли! Никогда. Не делайте этого! Вы не сработаете ни на какие хуки, отключите фильтры и сделаете ваш код подвижной мишенью. Никто никогда не узнает, когда и где вы зарегистрировали эту роль (вы не регистрировали её, вы просто затолкали её туда где-то, когда-то, как-то). Пожалуйста: никогда так не делайте. Особенно с ролями.

kaiser kaiser
13 окт. 2019 г. 19:46:19