Роль і можливості користувачів WordPress

17

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

Що всередині. Зберігання ролей

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

Роль і можливості користувачів WordPress

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

array(
‘administrator’ => array(
‘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.

Роль і можливості користувачів WordPress

Після конвертації це виглядає так:

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’);
});

Роль і можливості користувачів WordPress

Функція корисна, якщо нам необхідно додати лише одну можливість користувачеві, а не створювати цілу роль.

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. Випробуємо цей метод на закритій ролі sanyok:

/*
Plugin Name: Our sample role plugin
*/
$GLOBALS[‘wp_user_roles’] = array(
‘administrator’ => array(
‘name’ => ‘Адміністратор’,
‘capabilities’ => array(
‘activate_plugins’ => true,
‘read’ => true,
)
)
);

Оновивши сторінку панелі адміністратора помічаємо, що наша роль збереглася:

Роль і можливості користувачів WordPress

Такий метод вирішує проблему з БД, але додає інших:

Плагіни використовують рідне API можуть працювати неправильно.

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

Але, якщо ми створюємо користувача WordPress веб-додаток, налаштоване вручну зі статичним списком ролей, то даний метод, в принципі, підходить:

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

Вставка свого коду автоматично оновлює значення ролі.

З базами даних більше ніяких проблем.

Висновок

У цій статті я розповів вам про ролі і можливостях WordPress. Незважаючи на те, що в API надані всі важелі для будь-яких мислимих і немислимих завдань, все ж основна проблема, зв’язок з БД, залишається. Доведеться пам’ятати про це під час розробки плагінів та тем.