The Role Editor implements multiple layers of security to protect WordPress installations from unauthorized access, injection attacks, and data manipulation. All security measures follow WordPress coding standards and best practices.
Capability Check:
manage_options capabilitysetup_admin_page() methodrender_page() methodImplementation:
if (!current_user_can("manage_options")) {
return; // or wp_die()
}
Access Control:
Permission Callback:
permissions_check() methodmanage_options capabilityNonce Verification:
X-WP-Nonce header_wpnonce parameterwp_rest actionImplementation:
public function permissions_check($request)
{
if (!current_user_can("manage_options")) {
return new \WP_Error("rest_forbidden", ...);
}
$nonce = $request->get_header('X-WP-Nonce') ?: $request->get_param('_wpnonce');
if (!$nonce || !wp_verify_nonce($nonce, 'wp_rest')) {
return new \WP_Error('rest_forbidden', ...);
}
return true;
}
Format Validation:
/^[a-zA-Z0-9_-]+$/Length Validation:
Implementation:
if (!preg_match('/^[a-zA-Z0-9_-]+$/', $role_slug)) {
return new \WP_Error('rest_invalid_role', ...);
}
Format Validation:
/^[a-z0-9_]+$/Existence Validation:
Type Validation:
Implementation:
foreach ($capabilities as $cap) {
if (!is_string($cap)) {
continue;
}
$cap = sanitize_text_field($cap);
if (preg_match('/^[a-z0-9_]+$/', $cap) && in_array($cap, $all_capabilities)) {
$validated_capabilities[] = $cap;
}
}
Sanitization:
wp_strip_all_tags() removes HTMLtrim() removes whitespacesanitize_text_field() sanitizesLength Validation:
Implementation:
$new_name = isset($body['name']) ? sanitize_text_field($body['name']) : '';
$new_name = wp_strip_all_tags($new_name);
$new_name = trim($new_name);
if (empty($new_name) || strlen($new_name) > 100) {
return new \WP_Error('rest_invalid_name', ...);
}
Script Tag Attributes:
esc_url() for URLsesc_attr() for attributesabsint() for integersImplementation:
wp_print_script_tag([
"plugin-base" => esc_url($url),
"rest-base" => esc_url(rest_url()),
"user-id" => absint($current_user->ID),
"user-name" => esc_attr($current_user->display_name),
"user-email" => esc_attr($current_user->user_email),
]);
REST API Responses:
Implementation:
return new \WP_REST_Response([
'slug' => sanitize_text_field($role_slug),
'capabilities' => array_map('sanitize_text_field', $capabilities),
'userCount' => absint($users_with_role),
], 200);
Protected Roles:
Deletion Prevention:
Implementation:
$default_roles = ['administrator', 'editor', 'author', 'contributor', 'subscriber'];
if (in_array($role_slug, $default_roles)) {
return new \WP_Error('rest_cannot_delete_default', ...);
}
Deletion Check:
Implementation:
$user_count = count_users();
$users_with_role = isset($user_count['avail_roles'][$role_slug])
? absint($user_count['avail_roles'][$role_slug])
: 0;
if ($users_with_role > 0) {
return new \WP_Error('rest_role_has_users', ...);
}
Existence Checks:
Implementation:
if (!isset($wp_roles->roles[$role_slug])) {
return new \WP_Error('rest_invalid_role', ...);
}
Route Parameter Validation:
Input Validation:
Implementation:
const isValidRoleSlug = (slug) => {
if (!slug || typeof slug !== 'string') return false;
return /^[a-z0-9_-]+$/.test(slug);
};
Nonce Transmission:
X-WP-Nonce headerImplementation:
payload.headers = {
'Content-Type': 'application/json',
'X-WP-Nonce': restNonce,
};
Multiple Layers:
Capability Requirements:
manage_options requiredError Handling:
Whitelist Approach:
Context-Aware Escaping:
esc_attr()esc_url()absint()sanitize_text_field()manage_optionsmanage_optionsAuthentication Tests:
Validation Tests:
Protection Tests:
1.2.12: