Роли и возможности пользователей в WordPress

Роли и возможности пользователей в WordPress

От автора: управление пользователями в WordPress основано на механизме ролей и возможностей пользователей. Роли (или группе) задается уникальное имя с набором определенных возможностей. Каждая возможность определяет, есть ли у роли доступ к определенному свойству платформы. Разберем механизм роли и возможности пользователей в WordPress более подробно.

Что внутри. Хранение ролей

На странице WordPress Codex можно посмотреть список ролей и возможностей по умолчанию. В базе данных данный список хранится в таблице wp_options. Таблица использует серийный ключ wp_user_roles.

Несериализованные данные выглядят вот так:

array(
    'administrator' => array(
        'name'         => 'Administrator',
        'capabilities' => array(
            'switch_themes'          => true,
            'edit_themes'            => true,
            'activate_plugins'       => true,
            'edit_plugins'           => true,
            'edit_users'             => true,
            // [...]
        )
    ),
    'contributor' => array(
        'name'         => 'Contributor',
        'capabilities' => array(
            'delete_pages'           => true,
            'delete_others_pages'    => true,
            'delete_published_pages' => true,
            'delete_posts'           => true,
            // [...]
        )
    ),
    // [...]
);

Эти метаданные задаются при установке WordPress с нуля. При первом входе на сайт класс WP_Roles загружает список ролей и возможностей из базы данных. Операция происходит между методами plugins_loaded и init.

Привязка ролей пользователям

Для привязки пользователю определенной роли в WordPress используется значение meta_key, которое хранится в таблице wp_usermeta.

После конвертации это выглядит так:

array(
    'administrator' => true
)

Заметьте, что WordPress почему-то использует массив, хотя на данный момент у нас всего одна роль. Это мы разберем немного позже. Также помните, что wp_ это префикс текущего блога. (Его можно получить с помощью $GLOBALS['wpdb']->get_blog_prefix()). Если WordPress установлен на несколько сайтов, то пользователи могут иметь различные роли на этих сайтах:

wp_capabilities => a:1:{s:13:»administrator»;b:1;}

wp_10_capabilities => a:1:{s:11:»contributor»;b:1;}

wp_15_capabilities => a:1:{s:10:»subscriber»;b:1;}

[...]

Такое же правило применяется и к wp_user_roles в таблице wp_options, о котором мы говорили выше. И наконец, мы можем получить значение wp_user_level вместе с ролью. Такой подход использовался для управления ролями в старых версиях WordPress, сейчас он упразднен.

Работа с возможностями на уровне ядра

Мы уже видели, как загружаются роли, и как они прикрепляются к пользователям; и теперь WordPress может предоставлять различные возможности для пользователей по необходимости. Парочка возможностей по умолчанию жестко зашиты в ядре WordPress. К примеру, во время загрузки экрана плагинов, проверяется, а может ли пользователь работать с плагинами. Проверка выполняется с помощью следующего кода:

if (!current_user_can('activate_plugins'))
{
    wp_die(__('You do not have sufficient permissions to manage plugins for this site.'));
}

Роли же никогда жестко не запрограммированы; роль это всего лишь оболочка для возможностей и существует только в БД.

Роли и возможности: WordPress API. Доступ к API

Для облегчения работы с ролями в WordPress есть следующие глобальные функции.

current_user_can() — Проверяет, есть ли у текущего пользователя требуемые права.

add_action('init', function()
{
    if (current_user_can('install_plugins'))
    {
        echo 'you can install plugins';
    }
    else
    {
        echo 'You cannot install plugins';
    }
});

WP_User::has_cap — Проверяет права заданного пользователя.

add_action('init', function()   
{
    $user = get_user_by('slug', 'admin');
    if ($user->has_cap('install_plugins'))
    {
        echo 'Admin can install plugins';
    }
    else
    {
        echo 'Admin cannot install plugins';
    }
});

Также данная функция используется в current_user_can.

get_editable_roles() — Возвращает доступные роли.

add_action('admin_init', function()
{
    $roles = get_editable_roles();
    var_dump($roles);
});

Данный список можно переопределить с помощью фильтра editable_roles. Так что не стоит полностью полагаться на данную функцию, список ролей может быть неполным. Обратите внимание, что хук admin_init загружается еще до выполнения метода init.

get_role() — Получает объект WP_Role.

add_action('init', function()
{
    $role = get_role('administrator');
    var_dump($role);
});

// This will print:
// WP_Role Object
// (
//     [name] => administrator
//     [capabilities] => Array
//         (
//             [switch_themes] => 1
//             [edit_themes] => 1
//             [activate_plugins] => 1
//             [edit_plugins] => 1
//             [...]

WP_Role::has_cap() — Проверяет, обладает ли роль требуемыми возможностями.

add_action('init', function()
{
    $role = get_role('administrator');
    var_dump($role->has_cap('install_plugins')); // Распечатает TRUE
});

Настройка API

В WordPress API помимо всего прочего можно также настроить роли и их возможности.

add_role() — Регистрирует новую роль в базе данных.

add_action('init', function()
{
    add_role('plugins_manager', 'Plugins Manager', array(
        'install_plugins',
        'activate_plugins',
        'edit_plugins'
    ));
});

remove_role() — Удаляет роль из базы данных, если она существует.

add_action('init', function()
{
    remove_role('plugins_manager');
});

WP_Role::add_cap() — Добавляет роли возможность.

add_action('init', function()
{
    $role = get_role('contributor');
    $role->add_cap('install_plugins');
});

Значением может быть как основные возможности (install_plugins, edit_posts, …), так и свои собственные (my_awesome_plugin_cap). Для наших плагинов можно зарегистрировать сколько угодно много возможностей.

WP_Role::remove_cap() — Удаляет возможность из роли, если таковая существует.

add_action('init', function()
{
    $role = get_role('contributor');
    $role->remove_cap('install_plugins');
});

WP_User::add_role() — Добавляет роль заданному пользователю.

add_action('init', function()
{
    $user = get_user_by('slug', 'admin');
    $user->add_role('contributor');
});

Данная функция, теоретически, способна добавить одному пользователю несколько ролей. Так как в backend WordPress заложено показывать одну роль для одного пользователя, то нам не следует добавлять пользователю несколько ролей. Перед использованием данной функции всегда также запускайте WP_User::remove_role().

WP_User::remove_role() — Удаляет роль у заданного пользователя.

add_action('init', function()
{
    $user = get_user_by('slug', 'admin');
    $user->remove_role('administrator');
});

WP_User::add_cap() — Добавляет возможность заданному пользователю.

add_action('init', function()
{
    $user = get_user_by('slug', 'admin');
    $user->add_cap('my_custom_cap');
});

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

WP_User::remove_cap() — Удаляет возможность у заданного пользователя.

add_action('init', function()
{
    $user = get_user_by('slug', 'admin');
    $user->remove_cap('my_custom_cap');
});

Пара проблем с WordPress API

В рассмотренных выше функциях все, вроде бы, выглядит лучше некуда. Все кроме производительности и доступа к базе данных. Главная проблема при работе с ролями и возможностями заключается в том, как определить момент, когда необходимо запустить наш код на выполнение. Чтобы разобраться, взглянем на код ядра WordPress. Сперва, нам необходимо добавить новую пустую роль:

add_action('init', function()
{
    add_role('plugins_manager', 'Plugins Manager', array());
});

Функция add_role на самом деле перенаправляет нас на WP_Roles::add_role:

public function add_role( $role, $display_name, $capabilities = array() ) {
        if ( isset( $this->roles[$role] ) )
            return;

Если добавить новую роль, функция add_role отработает всего раз и больше запускаться не будет. Теперь, скажем, нам нужно добавить возможность к свежесозданной роли:

add_action('init', function()
{
    $role = get_role('plugins_manager');
    $role->add_cap('install_plugins');
});

В WordPress 4.2.2 функция WP_Role::add_cap() выглядит так:

public function add_cap( $role, $cap, $grant = true ) {
    if ( ! isset( $this->roles[$role] ) )
        return;

    $this->roles[$role]['capabilities'][$cap] = $grant;
    if ( $this->use_db )
        update_option( $this->role_key, $this->roles );
}

Данная функция обновляет объект $this->roles. Но еще она каждый раз при выполнении обновляет базу данных, даже если возможность уже зарегистрирована! То есть, если мы хотим позаботиться о производительности, не следует запускать наш код на каждой странице.

Способы обхода

Чтобы избежать проблем с базой данных, существует несколько вариантов.

Настройка запуска плагинов

С помощью функции register_activation_hook() в WordPress авторам плагинов можно настроить их запуск. Создадим простой плагин:

/*
Plugin Name: Our sample role plugin
*/
register_activation_hook(__FILE__, function()
{
    $role = add_role('plugins_manager', 'Plugins Manager', array());
    $role->add_cap('install_plugins');
});

Данный код выполнится всего раз во время активации плагина. Стоит помнить, что данный метод зависит от запуска и приостановки плагинов. Что будет, если плагин уже запущен? Или отключится ли плагин, если началось его обновление? По факту, данный метод также зависит от базы данных.

Обход базы данных WordPress

Есть и второй, незадокументированный способ. В некоторых случаях он довольно неплохо работает. Еще раз рассмотрим момент загрузки объектом WP_Roles ролей из базы данных при старте WordPress:

protected function _init() {
    global $wpdb, $wp_user_roles;
    $this->role_key = $wpdb->get_blog_prefix() . 'user_roles';
    if ( ! empty( $wp_user_roles ) ) {
        $this->roles = $wp_user_roles;
        $this->use_db = false;
    } else {
        $this->roles = get_option( $this->role_key );
    }

Перед тем, как вытянуть данные из БД, WordPress проверяет глобальную переменную $wp_user_roles. Если она не пуста, WordPress берет данные из нее и блокирует доступ к БД, установив значения переменной $this->use_db на false. Опробуем данный метод на закрытой роли administrator:

/*
Plugin Name: Our sample role plugin
*/
$GLOBALS['wp_user_roles'] = array(
    'administrator' => array(
        'name' => 'Administrator',
        'capabilities' => array(
            'activate_plugins' => true,
            'read' => true,
        )
    )
);

Обновив страницу панели администратора замечаем, что наша роль сохранилась:

Такой метод решает проблему с БД, но добавляет других:

Плагины использующие родное API могут работать неправильно.

Каждую роль приходится прописывать вручную, даже те, которые не хотим менять.

Но, если мы создаем пользовательское WordPress веб-приложение, настроенное вручную со статичным списком ролей, то данный метод, в принципе, подходит:

Значение ролей можно изменить.

Вставка своего кода автоматически обновляет значение роли.

С базами данных больше никаких проблем.

Заключение

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

Автор: Johan Satgé

Источник: http://www.sitepoint.com/

Редакция: Команда webformyself.

Хотите быстро научиться создавать сайты и блоги на WordPress с уникальным дизайном?

Получите самую полную в Рунете бесплатную систему обучения создания сайтов на WordPress “Уникальный сайт с нуля”

Получить

Метки:

Комментарии Вконтакте:

Комментарии Facebook:

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Я не робот.

Spam Protection by WP-SpamFree