Skip to content

Instantly share code, notes, and snippets.

@kostiantyn-petlia
Last active February 21, 2019 16:48
Show Gist options
  • Save kostiantyn-petlia/a5d7b5c37553a07c3ee196b435c75564 to your computer and use it in GitHub Desktop.
Save kostiantyn-petlia/a5d7b5c37553a07c3ee196b435c75564 to your computer and use it in GitHub Desktop.
<?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