Это учебное пособие из четырех частей, охватывающее тему пользователей, ролей и возможностей WordPress. Серия будет посвящена архитектуре и дизайну пользовательских ролей в WordPress; выделить наиболее важные функции для взаимодействия с пользователями и управления ролями и возможностями; и в последнем уроке мы собираемся создать реальный пример, демонстрирующий полезность этого API.
Вступление
Этот урок будет сфокусирован на создании практического решения с использованием системы ролей и возможностей WordPress. Если вы пропустили два последних урока, я настоятельно рекомендую вам ознакомиться с ними. Первая часть « Роли и возможности WordPress: основы » объясняет конструкцию этой системы; в то время как вторая часть « Роли и возможности WordPress: функции заметок » посвящена функциям и классам, которые WordPress предлагает взаимодействовать с системой.
Решение, предложенное в этом руководстве, является тем же, что я использую для одного из своих премиальных плагинов WordPress. Я выбрал его после попытки разных подходов. Это просто, коротко и заключено в один класс. Вы можете легко адаптировать его под свой плагин. Код доступен на GitHub ; и не имеет лицензии. Он также поставляется без каких-либо гарантий, и вы можете свободно использовать и лицензировать его по своему желанию.
Шаг 1 Сценарий
Мы создаем плагин WordPress, который имеет специальную клиентскую панель администратора. Эта панель администратора должна быть доступна только ограниченному кругу пользователей. Эти пользователи могут быть выбраны администратором блога. Он может разрешить различным ролям пользователей или всем им доступ к клиентской панели администратора или функциям.
Кроме того, мы должны иметь ограниченный доступ к библиотеке мультимедиа для пользователей с доступом к клиентской панели. WordPress имеет специальную возможность доступа и загрузки файлов в медиатеку: « upload_files
». Однако это дает пользователю (или роли) полный доступ к библиотеке мультимедиа. Это не очень хорошая вещь, тем более что фотографии (или файлы) не могут быть иерархически распределены по разным категориям, где вы можете ограничить доступ для каждой из них.
Нам нужно ограничить доступ к библиотеке мультимедиа только файлами, загруженными пользователем. У него не должно быть доступа к загрузкам других пользователей. Это ограничение должно применяться только к пользователям, у которых нет возможности « upload_files
». Другие пользователи и роли не обеспокоены этим ограничением, поскольку они уже имеют полный доступ к библиотеке мультимедиа.
Наш блог будет иметь следующие четыре категории пользователей:
Первые два набора пользователей — это те, кто не будет иметь доступа к плагину Client Panel. Я подчеркнул тот факт, что есть пользователи, которые имеют доступ к библиотеке мультимедиа, и набор, который не имеет. Важно, чтобы наше решение не влияло на первые две категории и не затрагивало их возможности.
Имея это в виду, наш класс должен сделать две вещи:
- Установите правильные разрешения для третьего и четвертого набора пользователей
- Разрешить ограниченный доступ к библиотеке мультимедиа для четвертой категории. Следует убедиться, что после отключения плагина или изменения прав пользователей эта категория пользователей вернется к своим первоначальным разрешениям.
Шаг 2 Интерфейс плагина
Прежде чем создавать наш класс, давайте разберемся с плагином. Плагин имеет довольно простую структуру. Он состоит из двух разных меню: одно для администратора и служит административной панелью, доступной только для пользователей с возможностью manage_options
. Второе меню предназначено для клиентов и предоставляет доступ к панели клиентов. Эта панель требует возможности » wptuts_client_page
«.
Эта возможность не существует в WordPress; нам нужно добавить и назначить его указанным пользователям или ролям. Но перед этим давайте посмотрим на плагин.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
/*
Plugin Name: WordPress Roles Plugin
Plugin URI: https://github.com/omarabid/WordPress-Roles-Plugin
Description: A WordPress Roles Plugin
Author: Abid Omar
Author URI: http://omarabid.com
Version: 1.0
*/
// Add an Admin user menu to the WordPress Dashboard
add_action(‘admin_menu’, ‘wptuts_admin_menu’);
function wptuts_admin_menu() {
add_menu_page(‘Admin Access’, ‘Admin Access’, ‘manage_options’, ‘wptuts-admin’, ‘wptuts_admin_page’);
}
function wptuts_admin_page() {
echo ‘Admin Page’;
}
// Add a client user menu to the WordPress Dashboard
add_action(‘admin_menu’, ‘wptuts_client_menu’);
function wptuts_client_menu() {
add_menu_page(‘Client Access’, ‘Client Access’, ‘wptuts_client’, ‘wptuts-client’, ‘wptuts_client_page’);
}
function wptuts_client_page() {
echo ‘Client Page’;
}
|
У нас есть две функции « admin_menu
», которые добавляют меню администратора для администратора и клиента. Мы можем сократить его только до одного крючка, который добавляет их обоих; но я предпочитаю разделить два. Каждая функция » add_menu_page
» add_menu_page
к другой функции, которая будет отображать содержимое страницы.
Далее нам нужно инициализировать наш класс ролей. Код класса помещается в другой файл; и процесс инициализации выполняется во время ловушки init
которая обеспечивает завершение загрузки WordPress.
Функция конструктора принимает три параметра:
-
$all
Boolean (Необязательно) Если вы хотите предоставить клиенту доступ ко всем пользователям в блоге, вы можете установить для него значение true и игнорировать оставшиеся параметры. - Массив
$roles
role (Необязательно) Массив с идентификаторами ролей, которые будут иметь доступ к клиентской панели. -
$users
Array (Необязательно) Массив с именами пользователей, которые будут иметь доступ к клиентской панели.
1
2
3
4
5
6
7
8
9
|
// Loads and initialize the roles class
add_action(‘init’, ‘wptuts_start_plugin’);
function wptuts_start_plugin() {
require_once(‘roles_class.php’);
$all = false;
$roles = array(‘subscriber’);
$users = array(3);
new wpttuts_roles($all, $roles, $users);
}
|
Шаг 3 Класс Роли
Свойства
Класс имеет только 3 свойства: $all
, $roles
и $users
. Это те же переменные, которые вы передаете в функцию конструктора. Значение переменных не изменяется в нашем примере; но в реальном практическом случае вы можете объединиться с другим источником. Для этого у вас есть функция set_entities
. Вы можете приспособить его к своим потребностям.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
/**
* @var boolean
*/
private $all;
/**
* @var array
*/
private $roles;
/**
* @var array
*/
private $users;
/**
* Set the permission entities
*
* @param boolean $all
* @param array $roles
* @param array $users
*/
private function set_entities($all, $roles, $users) {
$this->all = $all;
$this->roles = $roles;
$this->users = $users;
}
|
Функция конструктора
На первом этапе функция конструктора инициализирует переменные $all
, $roles
set_entitites()
и $users
с помощью функции set_entitites()
. Затем он вызывает частную функцию для настройки возможностей, а другую — для ограничения библиотеки мультимедиа. Это именно те шаги, которые мы определили в нашем сценарии.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
/**
* Creates a new instance of the Roles Class
*
* @param boolean $all
* @param array $roles
* @param array $users
*/
function __construct($all = false, $roles = array(), $users = array()) {
// Set the allowed entities
$this->set_entities($all, $roles, $users);
// Set the user access permission
$this->set_permissions();
// Media Library Filter
$this->media_filter();
}
|
Статические функции
Статические функции не требуют инициализации класса. Они похожи на независимые функции, но просто связаны с указанным классом. Я решил сохранить некоторые функции статичными, потому что они могут использоваться независимо; и вы можете найти их полезными в другом контексте.
Этими функциями являются filter_roles()
и filter_users()
; которые связаны с двумя другими функциями role_has_caps()
и user_has_caps()
. Функции играют роль фильтра. Они фильтруют роли (или пользователей) по возможностям, которые они имеют и не имеют.
Обе функции принимают два аргумента:
-
$include
Array Массив возможностей, которые имеет роль. -
$exclude
Array Массив возможностей, которых нет в роли.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
/**
* Filter all roles of the blog based on capabilities
*
* @static
* @param array $include Array of capabilities to include
* @param array $exclude Array of capabilities to exclude
* @return array
*/
static function filter_roles($include, $exclude) {
$filtered_roles = array();
global $wp_roles;
$roles = $wp_roles->get_names();
foreach ($roles as $role_id => $role_name) {
$role = get_role($role_id);
if (self::role_has_caps($role, $include) && !self::role_has_caps($role, $exclude)) {
$filtered_roles[] = $role_id;
}
}
return $filtered_roles;
}
/**
* Filter all users of the blog based on capabilities
*
* @static
* @param array $include Array of capabilities to include
* @param array $exclude Array of capabilities to exclude
* @return array
*/
static function filter_users($include, $exclude) {
$filtered_users = array();
$users = get_users();
foreach ($users as $user) {
$user = new WP_User($user->ID);
if (self::user_has_caps($user, $include) && !self::user_has_caps($user, $exclude)) {
$filtered_users[] = $user->ID;
}
}
return $filtered_users;
}
|
Функции перебирают все роли и пользователей в базе данных. Для каждой роли (или пользователя) она проверяет, обладает ли она необходимыми возможностями, и не имеет возможностей для исключения. Эта проверка выполняется с помощью role_has_caps()
и user_has_caps()
.
Эти две функции ( role_has_caps()
и user_has_caps()
) принимают два аргумента:
- $ role (или $ user ) String Идентификатор роли или идентификатор пользователя.
- $ caps Array Массив возможностей для проверки.
Если роль (или пользователь) имеет указанные возможности в массиве $caps
, функция возвращает значение true. В другом случае функция возвращает false. Функция в основном проходит по каждой возможности и проверяет, имеет ли роль (или пользователь) указанную возможность.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
/**
* Returns true if a role has the capabilities in the passed array
*
* @static
* @param $role
* @param $caps
* @return bool
*/
static function role_has_caps($role, $caps) {
foreach ($caps as $cap) {
if (!$role->has_cap($cap)) {
return false;
}
}
return true;
}
/**
* Returns true if a user has the capabilities in the passed array
*
* @static
* @param $user
* @param $caps
* @return bool
*/
static function user_has_caps($user, $caps) {
foreach ($caps as $cap) {
if (!$user->has_cap($cap)) {
return false;
}
}
return true;
}
|
Добавление разрешений
Это первый шаг навязывания закона нашего плагина. Я распределил функциональность по 3 функциям: одна для установки разрешений для всех пользователей, одна для установки разрешений для ролей и другая для установки разрешений для указанных пользователей. Основная функция просто решает, какие функции вызывать.
01
02
03
04
05
06
07
08
09
10
|
/**
* Set the Menu and Pages access permissions
*/
private function set_permissions() {
$this->set_all_permissions();
if (!$this->all) {
$this->set_roles_permissions();
$this->set_users_permissions();
}
}
|
Функция set_all_permissions()
проходит по всем пользователям блога и добавляет (или удаляет) возможность « wptuts_client
» в зависимости от значения переменной $all
. Мы получаем полный список пользователей, используя get_users()
; и инициализировать новый объект WP_User
чтобы получить доступ к add_cap()
и remove_cap()
.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
/**
* Set the permissions for ALL users
*/
private function set_all_permissions() {
$users = get_users();
foreach ($users as $user) {
$user = new WP_User($user->ID);
if ($this->all) {
$user->add_cap(‘wptuts_client’);
}
else {
$user->remove_cap(‘wptuts_client’);
}
}
}
|
Функция set_roles_permissions()
перебирает все роли в блоге и удаляет возможность « wptuts_client
». После этого он перебирает роли в массиве $roles
wptuts_client
и добавляет возможность « wptuts_client
». Первым шагом было обеспечение того, чтобы мы очистили возможность от ролей, которые могли иметь ее ранее.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
/**
* Set the permissions for Roles
*/
private function set_roles_permissions() {
global $wp_roles;
$roles = $wp_roles->get_names();
foreach ($roles as $role_id => $role_name) {
$role = get_role($role_id);
$role->remove_cap(‘wptuts_client’);
}
if (!empty($this->roles)) {
foreach ($this->roles as $role_id) {
$role = get_role($role_id);
$role->add_cap(‘wptuts_client’);
}
}
}
|
Функция set_users_permissions()
делает то же самое, что и последняя функция. Разница лишь в том, что он нацелен на пользователей, а не на роли.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
/**
* Set the permissions for specific Users
*/
private function set_users_permissions() {
$users = get_users();
foreach ($users as $user) {
$user = new WP_User($user->ID);
$user->remove_cap(‘wptuts_client’);
}
if (!empty($this->users)) {
foreach ($this->users as $user_id) {
$user = new WP_User($user_id);
$user->add_cap(‘wptuts_client’);
}
}
}
|
Фильтр медиа библиотеки
Теперь мы установили правильные разрешения для правильных сущностей. (Будучи пользователем или ролью) Мы также должны ограничить доступ к библиотеке мультимедиа для четвертой категории, которую мы различали в сценарии.
Эта категория ролей (или пользователей) имеет возможность » wptuts_client
«, но не имеет возможности » upload_files
«. И здесь наши функции фильтра вступают в игру. Они помогут нам отфильтровать и вернуть эту категорию ролей (или пользователей).
Для этой категории мы добавим две возможности « upload_files
» и « remove_upload_files
». « upload_files
» предоставит полный доступ к библиотеке мультимедиа; а другая возможность будет использоваться для фильтрации сообщений в библиотеке мультимедиа, а также будет использоваться для удаления возможности « upload_files
» после wptuts_client
возможности « wptuts_client
».
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
/**
* Restrict Media Access
*/
private function media_filter() {
// Apply the media filter for current Clients
$roles = self::filter_roles(array(‘wptuts_client’), array(‘upload_files’));
$users = self::filter_users(array(‘wptuts_client’), array(‘upload_files’));
$this->roles_add_cap($roles, ‘upload_files’);
$this->roles_add_cap($roles, ‘remove_upload_files’);
$this->users_add_cap($users, ‘upload_files’);
$this->users_add_cap($users, ‘remove_upload_files’);
// Restrict Media Library access
add_filter(‘parse_query’, array(&$this, ‘restrict_media_library’));
// For cleaning purposes
$clean_roles = self::filter_roles(array(‘remove_upload_files’), array(‘wptuts_client’));
$clean_users = self::filter_users(array(‘remove_upload_files’), array(‘wptuts_client’));
$this->roles_remove_cap($clean_roles, ‘upload_files’);
$this->roles_remove_cap($clean_roles, ‘remove_upload_files’);
$this->users_remove_cap($clean_users, ‘upload_files’);
$this->users_remove_cap($clean_users, ‘remove_upload_files’);
}
|
После установки возможностей для этой категории, мы подключаемся к parse_query
» parse_query
«. Этот фильтр позволяет нам изменять сообщения, возвращаемые WP_Query
. В нашем случае мы собираемся установить переменную запроса « author
». В результате возвращаются только сообщения, созданные указанным автором.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
/**
* Restrict Media Library access
*
* @param $wp_query
*/
public function restrict_media_library($wp_query) {
if (strpos($_SERVER[‘REQUEST_URI’], ‘/wp-admin/upload.php’)) {
if (current_user_can(‘remove_upload_files’)) {
global $current_user;
$wp_query->set(‘author’, $current_user->ID);
}
}
else if (strpos($_SERVER[‘REQUEST_URI’], ‘/wp-admin/media-upload.php’)) {
if (current_user_can(‘remove_upload_files’)) {
global $current_user;
$wp_query->set(‘author’, $current_user->ID);
}
}
}
|
Полный код
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
|
if (!class_exists(‘wpttuts_roles’)) {
class wpttuts_roles {
/**
* Determines if all users will have the required permissions
*
* @var boolean
*/
private $all;
/**
* An array with the roles which have the required permissions
*
* @var array
*/
private $roles;
/**
* An array with the user names which have the required permissions
*
* @var array
*/
private $users;
/**
* Creates a new instance of the Roles Class
*
* @param boolean $all
* @param array $roles
* @param array $users
*/
function __construct($all = false, $roles = array(), $users = array()) {
// Set the allowed entities
$this->set_entities($all, $roles, $users);
// Set the user access permission
$this->set_permissions();
// Media Library Filter
$this->media_filter();
}
/**
* Set the permission entities
*
* @param boolean $all
* @param array $roles
* @param array $users
*/
private function set_entities($all, $roles, $users) {
$this->all = $all;
$this->roles = $roles;
$this->users = $users;
}
/**
* Set the Menu and Pages access permissions
*/
private function set_permissions() {
$this->set_all_permissions();
if (!$this->all) {
$this->set_roles_permissions();
$this->set_users_permissions();
}
}
/**
* Set the permissions for ALL users
*/
private function set_all_permissions() {
$users = get_users();
foreach ($users as $user) {
$user = new WP_User($user->ID);
if ($this->all) {
$user->add_cap(‘wptuts_client’);
}
else {
$user->remove_cap(‘wptuts_client’);
}
}
}
/**
* Set the permissions for Roles
*/
private function set_roles_permissions() {
global $wp_roles;
$roles = $wp_roles->get_names();
foreach ($roles as $role_id => $role_name) {
$role = get_role($role_id);
$role->remove_cap(‘wptuts_client’);
}
if (!empty($this->roles)) {
foreach ($this->roles as $role_id) {
$role = get_role($role_id);
$role->add_cap(‘wptuts_client’);
}
}
}
/**
* Set the permissions for specific Users
*/
private function set_users_permissions() {
$users = get_users();
foreach ($users as $user) {
$user = new WP_User($user->ID);
$user->remove_cap(‘wptuts_client’);
}
if (!empty($this->users)) {
foreach ($this->users as $user_id) {
$user = new WP_User($user_id);
$user->add_cap(‘wptuts_client’);
}
}
}
/**
* Restrict Media Access
*/
private function media_filter() {
// Apply the media filter for currenct AdPress Clients
$roles = self::filter_roles(array(‘wptuts_client’), array(‘upload_files’));
$users = self::filter_users(array(‘wptuts_client’), array(‘upload_files’));
$this->roles_add_cap($roles, ‘upload_files’);
$this->roles_add_cap($roles, ‘remove_upload_files’);
$this->users_add_cap($users, ‘upload_files’);
$this->users_add_cap($users, ‘remove_upload_files’);
// Restrict Media Library access
add_filter(‘parse_query’, array(&$this, ‘restrict_media_library’));
// For cleaning purposes
$clean_roles = self::filter_roles(array(‘remove_upload_files’), array(‘wptuts_client’));
$clean_users = self::filter_users(array(‘remove_upload_files’), array(‘wptuts_client’));
$this->roles_remove_cap($clean_roles, ‘upload_files’);
$this->roles_remove_cap($clean_roles, ‘remove_upload_files’);
$this->users_remove_cap($clean_users, ‘upload_files’);
$this->users_remove_cap($clean_users, ‘remove_upload_files’);
}
/**
* Add a capability to an Array of roles
*
* @param $roles
* @param $cap
*/
private function roles_add_cap($roles, $cap) {
foreach ($roles as $role) {
$role = get_role($role);
$role->add_cap($cap);
}
}
/**
* Add a capability to an Array of users
*
* @param $users
* @param $cap
*/
private function users_add_cap($users, $cap) {
foreach ($users as $user) {
$user = new WP_User($user);
$user->add_cap($cap);
}
}
/**
* Remove a capability from an Array of roles
*
* @param $roles
* @param $cap
*/
private function roles_remove_cap($roles, $cap) {
foreach ($roles as $role) {
$role = get_role($role);
$role->remove_cap($cap);
}
}
/**
* Remove a capability from an Array of users
*
* @param $users
* @param $cap
*/
private function users_remove_cap($users, $cap) {
foreach ($users as $user) {
$user = new WP_User($user);
$user->remove_cap($cap);
}
}
/**
* Filter all roles of the blog based on capabilities
*
* @static
* @param array $include Array of capabilities to include
* @param array $exclude Array of capabilities to exclude
* @return array
*/
static function filter_roles($include, $exclude) {
$filtered_roles = array();
global $wp_roles;
$roles = $wp_roles->get_names();
foreach ($roles as $role_id => $role_name) {
$role = get_role($role_id);
if (self::role_has_caps($role, $include) && !self::role_has_caps($role, $exclude)) {
$filtered_roles[] = $role_id;
}
}
return $filtered_roles;
}
/**
* Returns true if a role has the capabilities in the passed array
*
* @static
* @param $role
* @param $caps
* @return bool
*/
static function role_has_caps($role, $caps) {
foreach ($caps as $cap) {
if (!$role->has_cap($cap)) {
return false;
}
}
return true;
}
/**
* Filter all users of the blog based on capabilities
*
* @static
* @param array $include Array of capabilities to include
* @param array $exclude Array of capabilities to exclude
* @return array
*/
static function filter_users($include, $exclude) {
$filtered_users = array();
$users = get_users();
foreach ($users as $user) {
$user = new WP_User($user->ID);
if (self::user_has_caps($user, $include) && !self::user_has_caps($user, $exclude)) {
$filtered_users[] = $user->ID;
}
}
return $filtered_users;
}
/**
* Returns true if a user has the capabilities in the passed array
*
* @static
* @param $user
* @param $caps
* @return bool
*/
static function user_has_caps($user, $caps) {
foreach ($caps as $cap) {
if (!$user->has_cap($cap)) {
return false;
}
}
return true;
}
/**
* Restrict Media Library access
*
* @param $wp_query
*/
public function restrict_media_library($wp_query) {
if (strpos($_SERVER[‘REQUEST_URI’], ‘/wp-admin/upload.php’)) {
if (current_user_can(‘remove_upload_files’)) {
global $current_user;
$wp_query->set(‘author’, $current_user->ID);
}
}
else if (strpos($_SERVER[‘REQUEST_URI’], ‘/wp-admin/media-upload.php’)) {
if (current_user_can(‘remove_upload_files’)) {
global $current_user;
$wp_query->set(‘author’, $current_user->ID);
}
}
}
}
}
|
Вывод
В этом уроке я попытался использовать материал, который мы узнали из предыдущих двух постов, чтобы создать собственное решение для ролей и возможностей. Решение было заключено в один класс, который можно настроить для ваших собственных нужд или плагинов. Вы можете найти код на Github .
Если у вас есть какие-либо вопросы, предложения или улучшения, не стесняйтесь размещать их в комментариях.