Last active
February 21, 2019 16:48
-
-
Save kostiantyn-petlia/a5d7b5c37553a07c3ee196b435c75564 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Define & change the website WP_Roles | |
* Help: https://codex.wordpress.org/Roles_and_Capabilities | |
*/ | |
class UserRoles { | |
/** Array of allowed roles (keys) with data array with 'label' text & 'caps' array. | |
* Set standard name and empty array for default WP role. | |
* | |
* Link: https://codex.wordpress.org/Roles_and_Capabilities | |
* | |
* Note: All roles will be reset to WP default roles before changing. | |
* Note: Roles will write to the DB, so, need to run just once. | |
* It fires after the theme is switched to our theme. | |
* Use UserRoles(true) for change role right now on the 'init' hook. | |
* | |
* The standard WP roles: [ administrator, editor, author, contributor, subscriber ] | |
* | |
* For example [ | |
* 'administrator' => [], | |
* 'editor' => [], | |
* 'hero' => [ | |
* 'label => 'Hero', | |
* 'caps' => [ | |
* 'some_caps_name1' => true, | |
* 'some_caps_name2' => false | |
* ] | |
* ] | |
* ] | |
*/ | |
const ROLES_AND_CAPS = [ | |
'administrator' => [ | |
'label' => 'Administrator', | |
'caps' => [ | |
// CPT 'play' caps | |
'edit_play' => true, | |
'read_play' => true, | |
'delete_play' => true, | |
'edit_plays' => true, | |
'edit_others_plays' => true, | |
'publish_plays' => true, | |
'read_private_plays' => true, | |
'delete_plays' => true, | |
'delete_private_plays' => true, | |
'delete_published_plays' => true, | |
'delete_others_plays' => true, | |
'edit_private_plays' => true, | |
'edit_published_plays' => true, | |
] | |
], | |
'editor' => [ | |
'label' => 'Editor', | |
'caps' => [ | |
// CPT 'play' caps | |
'edit_play' => true, | |
'read_play' => true, | |
'delete_play' => true, | |
'edit_plays' => true, | |
'edit_others_plays' => true, | |
'publish_plays' => true, | |
'read_private_plays' => true, | |
'delete_plays' => true, | |
'delete_private_plays' => true, | |
'delete_published_plays' => true, | |
'delete_others_plays' => true, | |
'edit_private_plays' => true, | |
'edit_published_plays' => true, | |
// WP_Users caps (it's access to Users for Editor) | |
'list_users' => true, | |
'edit_users' => true, | |
// Access to Menus | |
'edit_theme_options' => true, | |
'switch_themes' => false, | |
'edit_themes' => false | |
] | |
], | |
'dramatist' => [ | |
'label' => 'Dramatist', | |
'caps' => [ | |
'read' => true, | |
// CPT 'play' caps | |
'edit_plays' => true, | |
'edit_published_plays' => true, | |
'publish_plays' => false, | |
'delete_published__plays' => false, | |
'delete_plays' => false, | |
'upload_files' => true | |
] | |
], | |
'free' => [ | |
'label' => 'Free Account', | |
'caps' => [ | |
'read' => true | |
] | |
] | |
]; | |
// Only Admin can set this roles to the user | |
const PROTECTED_ROLES = [ 'administrator', 'editor' ]; | |
// Roles what will be show in the Author-of-the-post dropdown | |
const DROPDOWN_AUTHOR_ROLES = [ 'administrator', 'editor', 'dramatist' ]; | |
/** | |
* Add our filters & actions | |
*/ | |
function __construct( $right_now = false ) { | |
// Note: Roles will write to the DB, so, need to run just once | |
// It fires after the theme is switched to our theme | |
if ( $right_now ) { | |
add_action( 'init', [ $this, 'customizeRoles' ], 9 ); | |
} else { | |
add_action( 'after_switch_theme', [ $this, 'customizeRoles' ], 10 ); | |
} | |
// Protect some roles | |
add_filter( 'editable_roles', [ $this, 'protectSpecifiedRoles' ] ); | |
add_filter( 'map_meta_cap', [ $this, 'protectAdmin' ], 10, 4 ); | |
// Add custom roles to the Author-of-the-post dropdown | |
add_filter( 'wp_dropdown_users_args', [ $this, 'setDropdownUsersArgs' ], 10, 2 ); | |
} | |
/** | |
* Reset all roles to default WP Roles | |
*/ | |
public function resetRolesToDefault() { | |
if ( ! function_exists( 'populate_roles' ) ) { | |
require_once( ABSPATH . 'wp-admin/includes/schema.php' ); | |
} | |
\populate_roles(); | |
} | |
/** | |
* Roles what will be show in the Author-of-the-post dropdown | |
* Help: https://wordpress.stackexchange.com/questions/269153/how-to-force-listing-contributors-in-authors-dropdown-menu#answer-269209 | |
*/ | |
public function setDropdownUsersArgs( $query_args, $r ) { | |
if ( isset( $r['name'] ) && $r['name'] === 'post_author_override' ) { | |
// Unset the 'who' as this defaults to the 'author' role | |
if ( isset( $query_args['who'] ) ) { | |
unset( $query_args['who'] ); | |
} | |
$query_args['role__in'] = self::DROPDOWN_AUTHOR_ROLES; | |
} | |
return $query_args; | |
} | |
/** | |
* Check & add custom WP user roles | |
* Note: it will write to the DB, so, need to run just once | |
*/ | |
public function customizeRoles() { | |
// Reset all WP roles to default | |
$this->resetRolesToDefault(); | |
global $wp_roles; | |
if ( ! isset( $wp_roles ) ) { | |
$wp_roles = new \WP_Roles(); | |
} | |
// Some strange errors | |
if ( ! ( $wp_roles instanceof \WP_Roles ) ) return; | |
$wp_roles_names = $wp_roles->get_names(); // ['administrator' => 'Administrator', etc ] | |
// Delete disallowed roles, change caps for allowed roles | |
if ( is_array( $wp_roles_names ) && is_array( self::ROLES_AND_CAPS ) ) { | |
// 1) REMOVE any disallowed roles | |
foreach ( $wp_roles_names as $role_name => $role_label ) { | |
if ( false === array_key_exists( $role_name, self::ROLES_AND_CAPS ) ) { | |
remove_role( $role_name ); | |
} | |
} | |
// 2) ADD NEW custom roles (for example 'dramatist' & 'free') | |
foreach ( self::ROLES_AND_CAPS as $role_name => $role_data ) { | |
if ( false === array_key_exists( $role_name, $wp_roles_names ) ) { | |
$role_label = ( ! empty( $role_data['label'] ) ) ? $role_data['label'] : ucfirst( $role_name ); | |
add_role( $role_name, $role_label ); | |
} | |
} | |
//3) CHANGE specified capabilities for roles if they were defined | |
foreach ( self::ROLES_AND_CAPS as $role_name => $role_data ) { | |
if ( ! empty( $role_data['caps'] ) && is_array( $role_data['caps'] ) && ( $role = get_role( $role_name ) ) && ( $role instanceof \WP_Role ) ) { | |
foreach ( $role_data['caps'] as $cap_name => $cap_value ) { | |
$role->add_cap( $cap_name, $cap_value ); | |
} | |
} | |
} | |
} | |
} | |
/** | |
* Remove 'Administrator' from the list of roles if the current user is not an admin | |
*/ | |
public function protectSpecifiedRoles( $roles ) { | |
if ( ! empty( self::PROTECTED_ROLES ) && is_array( self::PROTECTED_ROLES ) ) { | |
foreach ( self::PROTECTED_ROLES as $role_name ) { | |
if ( isset( $roles[ $role_name ] ) && ! current_user_can( 'administrator' ) ) { | |
unset( $roles[ $role_name ] ); | |
} | |
} | |
} | |
return $roles; | |
} | |
/** | |
* If someone is trying to edit or delete and admin and that user isn't an admin, don't allow it | |
*/ | |
public function protectAdmin( $caps, $cap, $user_id, $args ) { | |
switch ( $cap ) { | |
case 'edit_user': | |
case 'remove_user': | |
case 'promote_user': | |
if ( isset( $args[0] ) && $args[0] == $user_id ) { | |
break; | |
} elseif ( ! isset( $args[0] ) ) { | |
$caps[] = 'do_not_allow'; | |
} | |
$other = new \WP_User( absint( $args[0] ) ); | |
if ( $other->has_cap( 'administrator' ) ) { | |
if ( ! current_user_can( 'administrator' ) ) { | |
$caps[] = 'do_not_allow'; | |
} | |
} | |
break; | |
case 'delete_user': | |
case 'delete_users': | |
if ( ! isset( $args[0] ) ) { | |
break; | |
} | |
$other = new \WP_User( absint( $args[0] ) ); | |
if ( $other->has_cap( 'administrator' ) ) { | |
if ( ! current_user_can( 'administrator' ) ) { | |
$caps[] = 'do_not_allow'; | |
} | |
} | |
break; | |
default: | |
break; | |
} | |
return $caps; | |
} | |
} | |
// Let's change WP Roles & Caps | |
$user_roles = new UserRoles(); // UserRoles(true) - update/save roles |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment