1
2
3
4
5
6
7
8
9
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
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
|
<?php /** * Abstraction of WordPress roles and capabilities and how they apply to Loco. * * - Currently only one capability exists, proving full access "loco_admin" * - Any user with super admin privileges automatically inherits this permission * - A single custom role is added called "translator" */ class Loco_data_Permissions { /** * Loco capabilities applicable to roles * @var array */ private static $caps = ['loco_admin']; /** * Polyfill for wp_roles which requires WP >= 4.3 * @return WP_Roles */ private static function wp_roles(){ global $wp_roles; if( ! isset($wp_roles) ){ get_role('ping'); } return $wp_roles; }
/** * Set up default roles and capabilities * @return WP_Roles */ public static function init(){ $roles = self::wp_roles(); $apply = []; // ensure translator role exists and is not locked out $role = $roles->get_role('translator'); if( $role instanceof WP_Role ){ $role->has_cap('read') || $role->add_cap('read'); } // else absence of translator role indicates first run // by default we'll initially allow full access to anyone that can manage_options else { $apply['translator'] = $roles->add_role( 'translator', 'Translator', ['read'=>true] ); foreach( $roles->role_objects as $id => $role ){ if( $role->has_cap('manage_options') ){ $apply[$id] = $role; } } } // fix broken permissions whereby super admin cannot access Loco at all. // this could happen if another plugin added the translator role beforehand. if( ! isset($apply['administrator']) && ! is_multisite() ){ $apply['administrator'] = $roles->get_role('administrator'); } foreach( $apply as $role ){ if( $role instanceof WP_Role ){ foreach( self::$caps as $cap ){ $role->has_cap($cap) || $role->add_cap($cap); } } } return $roles; }
/** * Construct instance, ensuring default roles and capabilities exist */ public function __construct(){ self::init(); }
/** * @return WP_Role[] */ public function getRoles(){ $roles = self::wp_roles(); return $roles->role_objects; }
/** * Check if role is protected such that user cannot lock themselves out when modifying settings * @param WP_Role WordPress role object to check * @return bool */ public function isProtectedRole( WP_Role $role ){ // if current user has this role and is not the super user, prevent lock-out $user = wp_get_current_user(); if( $user instanceof WP_User && ! is_super_admin($user->ID) && $user->has_cap('manage_options') ){ return in_array( $role->name, $user->roles, true ); } // admin users of single site install must never be denied access // note that there is no such thing as a network admin role, but network admins have all permissions return is_multisite() ? false : $role->has_cap('delete_users'); }
/** * Completely remove all Loco permissions, as if uninstalling * @return Loco_data_Permissions */ public function remove(){ /* @var $role WP_Role */ foreach( $this->getRoles() as $role ){ foreach( self::$caps as $cap ){ $role->has_cap($cap) && $role->remove_cap($cap); } } // we'll only remove our custom role if it has no capabilities other than admin access // this avoids breaking other plugins that use it, or added it before Loco was installed. if( $role = get_role('translator') ){ if( ! $role->capabilities || ['read'] === array_keys($role->capabilities) ){ remove_role('translator'); } } return $this; }
/** * Reset to default: roles include no Loco capabilities unless they have super admin privileges * @return WP_Role[] */ public function reset(){ $roles = $this->getRoles(); /* @var $role WP_Role */ foreach( $roles as $role ){ // always provide access to site admins on first run $grant = $this->isProtectedRole($role); foreach( self::$caps as $cap ){ if( $grant ){ $role->has_cap($cap) || $role->add_cap($cap); } else { $role->has_cap($cap) && $role->remove_cap($cap); } } } return $roles; }
/** * Get translated WordPress role name * @param string * @return string */ public function getRoleName( $id ){ if( 'translator' === $id ){ $label = _x( 'Translator', 'User role', 'loco-translate' ); } else { $names = self::wp_roles()->role_names; $label = isset($names[$id]) ? translate_user_role( $names[$id] ) : $id; } return $label; }
/** * Populate permission settings from posted checkboxes * @param string[] * @return self */ public function populate( array $caps ){ // drop all permissions before adding (cos checkboxes) $roles = $this->reset(); foreach( $caps as $id => $checked ){ if( isset($roles[$id]) ){ $role = $roles[$id]; /* @var $role WP_Role */ foreach( self::$caps as $cap ){ if( ! empty($checked[$cap]) ){ $role->has_cap($cap) || $role->add_cap($cap); } } } } return $this; }
}
|