PluginProbe ʕ •ᴥ•ʔ
PublishPress Capabilities – User Role Editor, Access Permissions, User Capabilities, Admin Menus / trunk
PublishPress Capabilities – User Role Editor, Access Permissions, User Capabilities, Admin Menus vtrunk
2.45.0 2.44.0 trunk 1.10 1.10.1 1.4.1 1.4.10 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.9 1.5 1.5.1 1.5.10 1.5.11 1.5.2 1.5.3 1.5.4 1.5.5 1.5.7 1.5.8 1.5.9 1.6 1.6.1 1.7 1.7.1 1.7.2 1.7.3 1.7.4 1.7.5 1.8.1 1.9 1.9.10 1.9.12 1.9.2 1.9.3 1.9.4 1.9.5 1.9.6 1.9.9 2.0 2.0.2 2.0.3 2.1 2.1.1 2.10.0 2.10.1 2.10.2 2.10.3 2.11.1 2.12.1 2.12.2 2.13.0 2.14.0 2.15.0 2.16.0 2.17.0 2.18.0 2.18.2 2.19.0 2.19.1 2.19.2 2.2 2.2.1 2.20.0 2.21.0 2.22.0 2.23.0 2.3 2.3.1 2.3.2 2.3.3 2.3.4 2.3.5 2.3.6 2.30.0 2.31.0 2.32.0 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.40.0 2.41.0 2.42.0 2.43.0 2.5.0 2.5.1 2.5.2 2.6.0 2.6.1 2.7.0 2.7.1 2.8.0 2.8.1 2.9.0 2.9.1
capability-manager-enhanced / includes / handler.php
capability-manager-enhanced / includes Last commit date
admin-notices 2 months ago features 2 weeks ago plugin-capabilities 2 months ago redirects 2 months ago roles 1 month ago admin-load.php 1 month ago admin.php 2 weeks ago application-passwords.php 2 weeks ago backup-handler.php 2 weeks ago backup.php 1 month ago cap-helper.php 6 months ago dashboard.php 2 months ago extractor-capabilities.php 6 months ago filters-admin.php 6 months ago filters-woocommerce.php 6 months ago filters-wp_rest_workarounds.php 6 months ago filters.php 5 months ago functions-admin.php 2 weeks ago functions.php 2 weeks ago handler.php 2 weeks ago inflect-cme.php 6 months ago manager.php 2 weeks ago network.php 6 months ago plugin-capabilities.php 2 months ago pp-handler.php 6 months ago pp-ui.php 3 months ago publishpress-roles.php 6 months ago settings-handler.php 6 months ago settings-ui.php 2 weeks ago settings.php 6 months ago test-user-ui.php 1 month ago test-user.php 5 months ago
handler.php
509 lines
1 <?php
2 /*
3 * PublishPress Capabilities [Free]
4 *
5 * Process update operations from the Capabilities screen
6 *
7 */
8
9 class CapsmanHandler
10 {
11 var $cm;
12
13 function __construct($manager_obj = false) {
14 if ($manager_obj) {
15 $this->cm = $manager_obj;
16 } else {
17 global $capsman;
18 $this->cm = $capsman;
19 }
20
21 require_once (dirname(CME_FILE) . '/includes/roles/roles-functions.php');
22 }
23
24 function processAdminGeneral() {
25 global $wpdb, $wp_roles;
26
27 check_admin_referer('capsman-general-manager');
28
29 if ( empty ($_POST['caps']) ) {
30 $_POST['caps'] = array();
31 }
32
33 if (!empty($_REQUEST['page']) && ('pp-capabilities-settings' == $_REQUEST['page'])) {
34 do_action('publishpress-caps_process_update');
35 return;
36 }
37
38 // Create a new role.
39 if ( ! empty($_POST['CreateRole']) ) {
40 if (!empty($_POST['create-name'])) {
41 $newrole = $this->createRole(sanitize_text_field($_POST['create-name']));
42 }
43
44 if (!empty($newrole)) {
45 ak_admin_notify(__('New role created.', 'capability-manager-enhanced'));
46 $this->cm->set_current_role($newrole);
47 } else {
48 if ( empty($_POST['create-name']) && in_array(get_locale(), ['en_EN', 'en_US']) )
49 ak_admin_error('Error: No role name specified.');
50 else
51 ak_admin_error(__('Error: Failed creating the new role.', 'capability-manager-enhanced'));
52 }
53
54 // Save role changes. Already saved at start with self::saveRoleCapabilities()
55 } elseif ( ! empty($_POST['SaveRole']) && !empty($_POST['current'])) {
56 if ( defined( 'MULTISITE' ) && MULTISITE ) {
57 ( method_exists( $wp_roles, 'for_site' ) ) ? $wp_roles->for_site() : $wp_roles->reinit();
58 }
59
60 $current_subject = sanitize_key($_POST['current']);
61
62 if (function_exists('pp_capabilities_can_manage_application_password_subject') && pp_capabilities_can_manage_application_password_subject($current_subject)) {
63 $this->saveApplicationPasswordCapabilities(
64 $current_subject,
65 isset($_POST['caps']) && is_array($_POST['caps']) ? $_POST['caps'] : []
66 );
67 return;
68 }
69
70 if (!pp_capabilities_is_editable_role($current_subject)) {
71 ak_admin_error(__('The selected role is not editable.', 'capability-manager-enhanced'));
72 return;
73 }
74
75 $level = (isset($_POST['level'])) ? (int) $_POST['level'] : 0;
76 $this->saveRoleCapabilities($current_subject, array_map('boolval', $_POST['caps']), $level);
77
78 if (defined( 'PRESSPERMIT_ACTIVE' ) && !empty($_POST['role'])) { // log customized role caps for subsequent restoration
79 // for bbPress < 2.2, need to log customization of roles following bbPress activation
80 $plugins = ( function_exists( 'bbp_get_version' ) && version_compare( bbp_get_version(), '2.2', '<' ) ) ? array( 'bbpress.php' ) : array(); // back compat
81
82 if ( ! $customized_roles = get_option( 'pp_customized_roles' ) )
83 $customized_roles = array();
84
85 $_role = sanitize_key($_POST['role']);
86
87 $customized_roles[$_role] = (object) array( 'caps' => array_map( 'boolval', $_POST['caps'] ), 'plugins' => $plugins );
88 update_option( 'pp_customized_roles', $customized_roles, false );
89 }
90 // Create New Capability and adds it to current role.
91 } elseif (!empty($_POST['AddCap']) && !empty($_POST['current']) && !empty($_POST['capability-name'])) {
92 if ( defined( 'MULTISITE' ) && MULTISITE ) {
93 ( method_exists( $wp_roles, 'for_site' ) ) ? $wp_roles->for_site() : $wp_roles->reinit();
94 }
95
96 if (empty($_POST['current']) || !pp_capabilities_is_editable_role(sanitize_key($_POST['current']))) {
97 ak_admin_error(__('The selected role is not editable.', 'capability-manager-enhanced'));
98 return;
99 }
100
101 $role = get_role(sanitize_key($_POST['current']));
102 $role->name = sanitize_key($_POST['current']); // bbPress workaround
103
104 $newname = $this->createNewName(sanitize_text_field($_POST['capability-name']), ['allow_dashes' => true]);
105
106 if (empty($newname['error'])) {
107 $role->add_cap($newname['name']);
108
109 // for bbPress < 2.2, need to log customization of roles following bbPress activation
110 $plugins = ( function_exists( 'bbp_get_version' ) && version_compare( bbp_get_version(), '2.2', '<' ) ) ? array( 'bbpress.php' ) : array(); // back compat
111
112 if ( ! $customized_roles = get_option( 'pp_customized_roles' ) )
113 $customized_roles = array();
114
115 $customized_roles[sanitize_key($_POST['role'])] = (object) array( 'caps' => array_merge( $role->capabilities, array( $newname['name'] => 1 ) ), 'plugins' => $plugins );
116 update_option( 'pp_customized_roles', $customized_roles, false );
117
118 $redirect_role = (!empty($_POST['role'])) ? sanitize_key($_POST['role']) : '';
119
120 $url = admin_url('admin.php?page=pp-capabilities&role=' . esc_attr($redirect_role) . '&added=1');
121 wp_redirect($url);
122 exit;
123 } else {
124 add_action('all_admin_notices', function() {
125 ak_admin_notify(__('Incorrect capability name.', 'capability-manager-enhanced'));
126 });
127 }
128
129 } elseif ( ! empty($_POST['update_filtered_types']) || ! empty($_POST['update_filtered_taxonomies']) || ! empty($_POST['update_detailed_taxonomies']) ) {
130 ak_admin_notify(__('Type / Taxonomy settings saved.', 'capability-manager-enhanced'));
131 } else {
132 if (!apply_filters('publishpress-caps_submission_ok', false)) {
133 ak_admin_error(__('Bad form received.', 'capability-manager-enhanced'));
134 }
135 }
136
137 if ( ! empty($newrole) && defined('PRESSPERMIT_ACTIVE') ) {
138 if ( ( ! empty($_POST['CreateRole']) && ! empty( $_REQUEST['new_role_pp_only'] ) ) || ( ! empty($_POST['CopyRole']) && ! empty( $_REQUEST['copy_role_pp_only'] ) ) ) {
139 $pp_only = (array) pp_capabilities_get_permissions_option( 'supplemental_role_defs' );
140 $pp_only[]= $newrole;
141
142 pp_capabilities_update_permissions_option('supplemental_role_defs', $pp_only);
143
144 _cme_pp_default_pattern_role( $newrole );
145 pp_refresh_options();
146 }
147 }
148 }
149
150
151 /**
152 * Creates a new role/capability name from user input name.
153 * Name rules are:
154 * - 2-40 charachers lenght.
155 * - Only letters, digits, spaces and underscores.
156 * - Must to start with a letter.
157 *
158 * @param string $name Name from user input.
159 * @return array|false An array with the name and display_name, or false if not valid $name.
160 */
161 public function createNewName( $name, $args=[] ) {
162 // Allow max 40 characters, letters, digits and spaces
163 $name = trim(substr($name, 0, 40));
164 $pattern = (!empty($args['allow_dashes'])) ? '/^[a-zA-Z][a-zA-Z0-9 _\-]+$/' : '/^[a-zA-Z][a-zA-Z0-9 _]+$/';
165
166 if ( preg_match($pattern, $name) ) {
167 $roles = ak_get_roles();
168
169 $name = str_replace(' ', '_', $name);
170 if ( in_array($name, $roles) || array_key_exists($name, $this->cm->capabilities) ) {
171 return ['error' => 'role_exists', 'name' => $name]; // Already a role or capability with this name.
172 }
173
174 $display = explode('_', $name);
175 $name = strtolower($name);
176
177 // Apply ucfirst proper caps unless capitalization already provided
178 foreach($display as $i => $word) {
179 if ($word === strtolower($word)) {
180 $display[$i] = ucfirst($word);
181 }
182 }
183
184 $display = implode(' ', $display);
185
186 return compact('name', 'display');
187 } else {
188 return ['error' => 'invalid_name', 'name' => $name];
189 }
190 }
191
192 /**
193 * Creates a new role.
194 *
195 * @param string $name Role name to create.
196 * @param array $caps Role capabilities.
197 * @return string|false Returns the name of the new role created or false if failed.
198 */
199 public function createRole( $name, $caps = [], $args = [] ) {
200 if ( ! is_array($caps) )
201 $caps = array();
202
203 $role = $this->createNewName($name);
204 if (!empty($role['error'])) {
205 return false;
206 }
207
208 $new_role = add_role($role['name'], $role['display'], $caps);
209 if ( is_object($new_role) ) {
210 return $role['name'];
211 } else {
212 return false;
213 }
214 }
215
216 /**
217 * Saves capability changes to roles.
218 *
219 * @param string $role_name Role name to change its capabilities
220 * @param array $caps New capabilities for the role.
221 * @return void
222 */
223 private function saveRoleCapabilities( $role_name, $caps, $level ) {
224 $this->cm->generateNames();
225 $role = get_role($role_name);
226
227 // workaround to ensure db storage of customizations to bbp dynamic roles
228 $role->name = $role_name;
229
230 $stored_role_caps = ( ! empty($role->capabilities) && is_array($role->capabilities) ) ? array_intersect( $role->capabilities, array(true, 1) ) : array();
231 $stored_negative_role_caps = ( ! empty($role->capabilities) && is_array($role->capabilities) ) ? array_intersect( $role->capabilities, array(false) ) : array();
232
233 $old_caps = array_intersect_key( $stored_role_caps, $this->cm->capabilities);
234 $new_caps = ( is_array($caps) ) ? array_map('boolval', $caps) : array();
235 $new_caps = array_merge($new_caps, ak_level2caps($level));
236
237 // Find caps to add and remove
238 $add_caps = array_diff_key($new_caps, $old_caps);
239 $del_caps = array_diff_key(array_merge($old_caps, $stored_negative_role_caps), $new_caps);
240
241 $changed_caps = array();
242 foreach( array_intersect_key( $new_caps, $old_caps ) as $cap_name => $cap_val ) {
243 if ( $new_caps[$cap_name] != $old_caps[$cap_name] )
244 $changed_caps[$cap_name] = $cap_val;
245 }
246
247 $add_caps = array_merge( $add_caps, $changed_caps );
248
249 if ( ! $is_administrator = current_user_can('administrator') ) {
250 unset($add_caps['manage_capabilities']);
251 unset($del_caps['manage_capabilities']);
252 }
253
254 if ( 'administrator' == $role_name && isset($del_caps['manage_capabilities']) ) {
255 unset($del_caps['manage_capabilities']);
256 ak_admin_error(__('You cannot remove Manage Capabilities from Administrators', 'capability-manager-enhanced'));
257 }
258
259 // additional safeguard against removal of read capability
260 if ( isset( $del_caps['read'] ) && _cme_is_read_removal_blocked( $role_name ) ) {
261 unset( $del_caps['read'] );
262 }
263
264 // Add new capabilities to role
265 foreach ( $add_caps as $cap => $grant ) {
266 if ( $is_administrator || current_user_can($cap) )
267 $role->add_cap( $cap, $grant );
268 }
269
270 // Remove capabilities from role
271 foreach ( $del_caps as $cap => $grant) {
272 if ( $is_administrator || current_user_can($cap) )
273 $role->remove_cap($cap);
274 }
275
276 $this->cm->log_db_roles();
277
278 if (is_multisite() && is_super_admin() && is_main_site()) {
279 if ( ! $autocreate_roles = get_site_option( 'cme_autocreate_roles' ) )
280 $autocreate_roles = array();
281
282 $this_role_autocreate = ! empty($_REQUEST['cme_autocreate_role']);
283
284 if ( $this_role_autocreate && ! in_array( $role_name, $autocreate_roles ) ) {
285 $autocreate_roles []= $role_name;
286 update_site_option( 'cme_autocreate_roles', $autocreate_roles );
287 }
288
289 if ( ! $this_role_autocreate && in_array( $role_name, $autocreate_roles ) ) {
290 $autocreate_roles = array_diff( $autocreate_roles, array( $role_name ) );
291 update_site_option( 'cme_autocreate_roles', $autocreate_roles );
292 }
293
294 $do_role_sync = !empty($_REQUEST['cme_net_sync_role']);
295 $do_option_sync = !empty($_REQUEST['cme_net_sync_options']);
296
297 if ($do_role_sync || $do_option_sync) {
298 $token = $this->processNetworkSyncBatch(
299 $role_name,
300 $caps,
301 $level,
302 $do_role_sync,
303 $do_option_sync
304 );
305
306 if (!empty($token)) {
307 $this->cm->network_sync_token = $token;
308 }
309
310 }
311 } // endif multisite installation with super admin editing a main site role
312
313 pp_capabilities_autobackup();
314 }
315
316 private function saveApplicationPasswordCapabilities($subject, $caps)
317 {
318 $this->cm->generateNames();
319
320 if (method_exists($this->cm, 'initPluginCapabilities')) {
321 $this->cm->initPluginCapabilities();
322 }
323
324 if (defined('CME_FILE')) {
325 $extractor_capabilities_file = dirname(CME_FILE) . '/includes/extractor-capabilities.php';
326
327 if (is_readable($extractor_capabilities_file)) {
328 require_once $extractor_capabilities_file;
329 }
330 }
331
332 $managed_capabilities = function_exists('pp_capabilities_get_application_password_managed_capabilities')
333 ? pp_capabilities_get_application_password_managed_capabilities(array_keys($this->cm->capabilities))
334 : array_keys($this->cm->capabilities);
335
336 if (!pp_capabilities_save_application_password_capabilities($subject, $caps, $managed_capabilities)) {
337 ak_admin_error(__('The selected application password is not editable.', 'capability-manager-enhanced'));
338 return;
339 }
340
341 $this->cm->message = __('Application password capabilities saved.', 'capability-manager-enhanced');
342 }
343
344 public function continueNetworkSync($token)
345 {
346 return $this->runNetworkSyncBatch($token);
347 }
348
349 public function runNetworkSyncBatch($token)
350 {
351 $token = sanitize_key($token);
352 $state = get_site_transient('cme_network_sync_' . $token);
353
354 if (empty($state) || !is_array($state)) {
355 return false;
356 }
357
358 $this->cm->generateSysNames();
359 $this->processNetworkSyncBatchFromState($state);
360
361 return true;
362 }
363
364 private function processNetworkSyncBatch($role_name, $caps, $level, $do_role_sync, $do_option_sync)
365 {
366 $state = [
367 'role_name' => sanitize_key($role_name),
368 'caps' => (is_array($caps)) ? array_map('boolval', $caps) : array(),
369 'level' => (int) $level,
370 'do_role_sync' => (bool) $do_role_sync,
371 'do_option_sync' => (bool) $do_option_sync,
372 'offset' => 0,
373 'token' => function_exists('wp_generate_uuid4') ? wp_generate_uuid4() : strtolower(wp_generate_password(32, false, false)),
374 ];
375
376 set_site_transient('cme_network_sync_' . $state['token'], $state, DAY_IN_SECONDS);
377
378 if (!wp_next_scheduled('cme_network_sync_batch', [$state['token']])) {
379 wp_schedule_single_event(time() + 1, 'cme_network_sync_batch', [$state['token']]);
380 }
381
382 return $state['token'];
383 }
384
385 private function processNetworkSyncBatchFromState($state)
386 {
387 global $wpdb, $wp_roles, $blog_id;
388
389 $role_name = !empty($state['role_name']) ? sanitize_key($state['role_name']) : '';
390 $caps = (!empty($state['caps']) && is_array($state['caps'])) ? array_map('boolval', $state['caps']) : array();
391 $level = !empty($state['level']) ? (int) $state['level'] : 0;
392 $do_role_sync = !empty($state['do_role_sync']);
393 $do_option_sync = !empty($state['do_option_sync']);
394 $offset = !empty($state['offset']) ? absint($state['offset']) : 0;
395 $token = !empty($state['token']) ? sanitize_key($state['token']) : '';
396
397 if (!$role_name) {
398 return;
399 }
400
401 $batch_size = (int) apply_filters('cme_network_sync_batch_size', 50, $role_name, $do_role_sync, $do_option_sync);
402 if ($batch_size < 1) {
403 $batch_size = 50;
404 }
405
406 $blog_ids = get_sites([
407 'fields' => 'ids',
408 'number' => $batch_size,
409 'offset' => $offset,
410 'orderby' => 'ID',
411 'order' => 'ASC',
412 ]);
413
414 $orig_blog_id = $blog_id;
415
416 if ($do_role_sync) {
417 $role_caption = !empty($wp_roles->role_names[$role_name]) ? $wp_roles->role_names[$role_name] : $role_name;
418 $new_caps = array_merge($caps, ak_level2caps($level));
419 $admin_role = $wp_roles->get_role('administrator');
420 $main_admin_caps = array_merge($admin_role->capabilities, ak_level2caps(10));
421 }
422
423 $sync_options = !empty($state['sync_options']) ? $state['sync_options'] : [];
424
425 if ($do_option_sync && empty($sync_options)) {
426 $pp_prefix = (defined('PPC_VERSION') && !defined('PRESSPERMIT_VERSION')) ? 'pp' : 'presspermit';
427
428 foreach (['define_create_posts_cap', 'enabled_post_types', 'enabled_taxonomies'] as $option_name) {
429 $sync_options["{$pp_prefix}_$option_name"] = get_option("{$pp_prefix}_$option_name");
430 }
431
432 $sync_options['cme_detailed_taxonomies'] = get_option('cme_detailed_taxonomies');
433 $sync_options['cme_enabled_post_types'] = get_option('cme_enabled_post_types');
434 $sync_options['presspermit_supplemental_role_defs'] = get_option('presspermit_supplemental_role_defs');
435 }
436
437 foreach ($blog_ids as $id) {
438 if (is_main_site($id)) {
439 continue;
440 }
441
442 switch_to_blog($id);
443
444 if ($do_role_sync) {
445 ( method_exists($wp_roles, 'for_site') ) ? $wp_roles->for_site() : $wp_roles->reinit();
446
447 if ($blog_role = $wp_roles->get_role($role_name)) {
448 $stored_role_caps = (!empty($blog_role->capabilities) && is_array($blog_role->capabilities)) ? array_intersect($blog_role->capabilities, array(true, 1)) : array();
449 $old_caps = array_intersect_key($stored_role_caps, $this->cm->capabilities);
450
451 $add_caps = array_diff_key($new_caps, $old_caps);
452 $del_caps = array_intersect_key(array_diff_key($old_caps, $new_caps), $main_admin_caps);
453
454 foreach ($add_caps as $cap => $grant) {
455 $wp_roles->roles[$role_name]['capabilities'][$cap] = $grant;
456 }
457
458 foreach ($del_caps as $cap => $grant) {
459 unset($wp_roles->roles[$role_name]['capabilities'][$cap]);
460 }
461
462 if ($wp_roles->use_db) {
463 update_option($wp_roles->role_key, $wp_roles->roles);
464 }
465 } else {
466 $wp_roles->add_role($role_name, $role_caption, $new_caps);
467 }
468 }
469
470 foreach ($sync_options as $option_name => $option_val) {
471 update_option($option_name, $option_val);
472 }
473
474 restore_current_blog();
475 }
476
477 ( method_exists($wp_roles, 'for_site') ) ? $wp_roles->for_site() : $wp_roles->reinit();
478
479 if ($token && count($blog_ids) === $batch_size) {
480 $state['role_name'] = $role_name;
481 $state['caps'] = $caps;
482 $state['level'] = $level;
483 $state['do_role_sync'] = $do_role_sync;
484 $state['do_option_sync'] = $do_option_sync;
485 $state['sync_options'] = $sync_options;
486 $state['offset'] = $offset + $batch_size;
487 $state['token'] = $token;
488
489 set_site_transient('cme_network_sync_' . $token, $state, DAY_IN_SECONDS);
490
491 wp_schedule_single_event(time() + 1, 'cme_network_sync_batch', [$token]);
492 return;
493 }
494
495 if ($token) {
496 delete_site_transient('cme_network_sync_' . $token);
497 set_site_transient('cme_network_sync_done_' . $token, [
498 'role_name' => $role_name,
499 ], HOUR_IN_SECONDS);
500 }
501 }
502 }
503
504 if ( ! function_exists('boolval') ) {
505 function boolval( $val ) {
506 return (bool) $val;
507 }
508 }
509