Below is a differential between the unpatched vulnerable code and the patched update, for reference.
--- a/highland-software-custom-role-manager/highland-software-custom-role-manager.php
+++ b/highland-software-custom-role-manager/highland-software-custom-role-manager.php
@@ -3,7 +3,7 @@
* Plugin Name: Highland Software Custom Role Manager
* Plugin URI: https://highland-software.com/highland-software-custom-roles-manager
* Description: Extend WordPress role management by allowing administrators to create custom roles and assign multiple roles to users. Includes a visual builder interface with drag-and-drop ordering and capability controls.
- * Version: 1.0.0
+ * Version: 1.0.1
* Author: James Rodgers
* Author URI: https://highland-software.com
* Text Domain: highland-software-custom-role-manager
@@ -70,6 +70,7 @@
* Security note:
* Using require_once ensures files are only included once and prevents redeclaration errors.
*/
+require_once HSCRM_PATH . 'includes/helpers.php';
require_once HSCRM_PATH . 'includes/init.php';
require_once HSCRM_PATH . 'includes/assets.php';
require_once HSCRM_PATH . 'includes/ajax.php';
--- a/highland-software-custom-role-manager/includes/ajax.php
+++ b/highland-software-custom-role-manager/includes/ajax.php
@@ -26,8 +26,20 @@
}
/* =========================
- ADD ROW (FULL UI RESTORED)
+ HELPER: RATE LIMIT
========================= */
+function hscrm_rate_limit($action) {
+ $key = 'hscrm_rate_' . get_current_user_id() . '_' . $action;
+
+ $last = (int) get_transient($key);
+
+ if ($last && (time() - $last) < 1) {
+ wp_send_json_error(['message' => 'Too many requests'], 429);
+ wp_die();
+ }
+
+ set_transient($key, time(), 2);
+}
/**
* Returns HTML for a new builder row
@@ -41,11 +53,23 @@
*/
add_action('wp_ajax_hscrm_add_row', function(){
- check_ajax_referer('hscrm_ajax_nonce','nonce');
+ check_ajax_referer('hscrm_ajax_nonce', 'nonce');
+
+ if (!hscrm_user_can_manage_roles()) {
+ wp_send_json_error(['message' => 'Unauthorized'], 403);
+ wp_die();
+ }
+
+ // hscrm_rate_limit('add_row');
- $idx = intval($_POST['idx'] ?? 0);
+ $idx = isset($_POST['idx']) ? intval($_POST['idx']) : 0;
- ob_start(); ?>
+ if ($idx < 0) {
+ wp_send_json_error(['message' => 'Invalid index'], 400);
+ wp_die();
+ }
+
+ ob_start(); ?>
<div class="hscrm-card draggable-item p-3 mb-3"
id="row_<?php echo esc_attr($idx); ?>"
@@ -101,12 +125,10 @@
pattern="[a-z0-9_]+"
placeholder="<?php esc_attr_e('Role Slug','highland-software-custom-role-manager'); ?>"
title="<?php esc_attr_e('Lowercase letters, numbers, underscores only','highland-software-custom-role-manager'); ?>">
- <p class="hscrm-slug-risk-warning d-none" style="margin-top:4px; color:#b32d2e;">
- ⚠ <?php esc_html_e('Changing this slug after users are assigned will break their role assignment.','highland-software-custom-role-manager'); ?>
- </p>
</div>
</div>
+
<!-- Capability Presets -->
<div class="hscrm-cap-presets mb-2 d-none">
@@ -128,42 +150,33 @@
</div>
<!-- Capabilities Grid -->
- <?php
+ <?php
echo '<div id="caps_'.esc_attr($idx).'" class="hscrm-cap-grid" style="display:none;">';
- // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
- echo hscrm_get_capabilities_html();
+ echo hscrm_get_capabilities_html();
echo '</div>';
?>
</div>
<?php
- wp_send_json_success(['idx'=>$idx,'message'=>ob_get_clean()]);
+ wp_send_json_success(['idx'=>$idx,'html'=>ob_get_clean()]);
+ wp_die();
});
/* =========================
LOAD ROLES
========================= */
-
-/**
- * Returns saved role builder data
- *
- * SECURITY:
- * - Nonce verified
- * - Capability restricted
- */
-add_action('wp_ajax_hscrm_load_roles', 'hscrm_load_roles');
-
-function hscrm_load_roles() {
+add_action('wp_ajax_hscrm_load_roles', function(){
check_ajax_referer('hscrm_ajax_nonce', 'nonce');
- if (!current_user_can('manage_options')) {
- wp_send_json_error([
- 'message' => __('Permission denied', 'highland-software-custom-role-manager')
- ]);
+ if (!hscrm_user_can_manage_roles()) {
+ wp_send_json_error(['message' => 'Unauthorized'], 403);
+ wp_die();
}
+ //hscrm_rate_limit('load_roles');
+
$data = get_option('hscrm_roles', []);
if (!is_array($data)) {
@@ -171,314 +184,147 @@
}
wp_send_json_success($data);
-}
+ wp_die();
+});
/* =========================
SAVE ROLES
========================= */
+add_action('wp_ajax_hscrm_save_roles', function(){
-/**
- * Saves builder configuration and syncs roles
- *
- * SECURITY:
- * - Nonce verified
- * - Capability restricted
- * - JSON sanitized via wp_unslash + json_decode
- *
- * EDGE CASES:
- * - Empty payload
- * - Invalid JSON
- */
-add_action('wp_ajax_hscrm_save_roles', 'hscrm_save_roles');
-
-function hscrm_save_roles() {
-
- /**
- * Security: nonce + capability check
- */
check_ajax_referer('hscrm_ajax_nonce', 'nonce');
- if (!current_user_can('manage_options')) {
- wp_send_json_error([
- 'message' => __('Unauthorized', 'highland-software-custom-role-manager')
- ]);
+ if (!hscrm_user_can_manage_roles()) {
+ wp_send_json_error(['message' => 'Unauthorized'], 403);
+ wp_die();
}
-
- $core_roles = ['administrator','editor','author','contributor','subscriber'];
-
- /**
- * Get submitted rows safely
- */
- $raw_rows = [];
- if (isset($_POST['rows'])) {
+ // hscrm_rate_limit('save_roles');
- $raw_rows = wp_unslash($_POST['rows']);
+ $raw_rows = isset($_POST['rows']) ? wp_unslash($_POST['rows']) : [];
- // Handle JSON string case
- if (is_string($raw_rows)) {
- $decoded = json_decode($raw_rows, true);
-
- if (json_last_error() === JSON_ERROR_NONE) {
- $raw_rows = $decoded;
- }
+ if (is_string($raw_rows)) {
+ $decoded = json_decode($raw_rows, true);
+ if (json_last_error() === JSON_ERROR_NONE) {
+ $raw_rows = $decoded;
}
-
- // Final validation
- if (!is_array($raw_rows)) {
- wp_send_json_error([
- 'message' => __('Invalid data format', 'highland-software-custom-role-manager')
- ]);
- }
-
- // Safe recursive sanitize
- array_walk_recursive($raw_rows, function (&$value) {
- if (is_string($value)) {
- $value = wp_kses_post($value);
- }
- });
}
+ // 🔒 Ensure array (allow empty)
+ if (!is_array($raw_rows)) {
+ wp_send_json_error(['message' => 'Invalid data format'], 400);
+ wp_die();
+ }
-
- /**
- * Sanitize rows safely
- */
- $rows = array_map(function ($row) use ($core_roles) {
-
- // Ensure row is array
- if (!is_array($row)) {
- return null;
- }
-
- // Extract and sanitize type early
- $type = sanitize_text_field($row['type'] ?? '');
-
- // Safely handle capabilities
- $caps = [];
- if (isset($row['capabilities']) && is_array($row['capabilities'])) {
- $caps = array_map('sanitize_key', $row['capabilities']);
- }
-
- // =====================
- // ROLE
- // =====================
- if ($type === 'role') {
-
- $slug = sanitize_key($row['roleSlug'] ?? '');
-
- // Skip invalid slug
- if (!$slug) {
- return null;
- }
-
- // BLOCK core roles
- if (in_array($slug, $core_roles, true)) {
- return null;
- }
-
- return [
- 'type' => 'role',
- 'roleName' => sanitize_text_field($row['roleName'] ?? ''),
- 'roleSlug' => $slug,
- 'capabilities' => $caps
- ];
- }
-
- // =====================
- // GROUPING
- // =====================
- if ($type === 'grouping') {
-
- $group = sanitize_text_field($row['groupName'] ?? '');
-
- if (!$group) {
- return null;
- }
-
- return [
- 'type' => 'grouping',
- 'groupName' => $group
- ];
+ // 🔒 Sanitize deeply
+ array_walk_recursive($raw_rows, function (&$value) {
+ if (is_string($value)) {
+ $value = sanitize_text_field($value);
}
+ });
- // =====================
- // SEPARATOR
- // =====================
- if ($type === 'separator') {
- return ['type' => 'separator'];
- }
+ $core_roles = ['administrator','editor','author','contributor','subscriber'];
- return null;
+ // 🔒 Normalize rows (empty-safe)
+ $rows = [];
- }, $raw_rows);
- $rows = array_values(array_filter($rows));
- /**
- * Validation setup
- */
- $errors = [];
- $seen_slugs = [];
- $seen_names = [];
+ if (!empty($raw_rows)) {
+ $rows = array_values(array_filter(array_map(function ($row) use ($core_roles) {
- $default_roles = ['administrator','editor','author','contributor','subscriber'];
+ if (!is_array($row)) return null;
- /**
- * Validate each row
- */
- foreach ($rows as $index => $row) {
-
- $type = $row['type'] ?? '';
-
- // Only validate role rows
- if ($type !== 'role') {
- continue;
- }
+ $type = sanitize_text_field($row['type'] ?? '');
- $name = sanitize_text_field($row['roleName'] ?? '');
- $slug = sanitize_key($row['roleSlug'] ?? '');
+ if ($type === 'role') {
- /**
- * 1. Empty Role Name
- */
- if ($name === '') {
- $errors[] = [
- 'index' => $index,
- 'field' => 'roleName',
- 'message' => __('Role name is required', 'highland-software-custom-role-manager')
- ];
- }
+ $slug = sanitize_key($row['roleSlug'] ?? '');
- /**
- * 2. Invalid slug
- * Must be lowercase letters, numbers, underscores
- */
- if ($slug === '' || !preg_match('/^[a-z0-9_]+$/', $slug)) {
- $errors[] = [
- 'index' => $index,
- 'field' => 'roleSlug',
- 'message' => __('Invalid role slug', 'highland-software-custom-role-manager') /* translators: Error shown when role slug format is invalid */
- ];
- }
+ if (!$slug || in_array($slug, $core_roles, true)) {
+ return null;
+ }
- /**
- * 3. Duplicate slug (within builder)
- */
- if ($slug !== '') {
- if (isset($seen_slugs[$slug])) {
- $errors[] = [
- 'index' => $index,
- 'field' => 'roleSlug',
- 'message' => __('Duplicate role slug', 'highland-software-custom-role-manager')
+ return [
+ 'type' => 'role',
+ 'roleName' => sanitize_text_field($row['roleName'] ?? ''),
+ 'roleSlug' => $slug,
+ 'capabilities' => isset($row['capabilities']) && is_array($row['capabilities'])
+ ? array_map('sanitize_key', $row['capabilities'])
+ : []
];
}
- $seen_slugs[$slug] = true;
- }
- /**
- * 4. Duplicate Role Name (case-insensitive)
- */
- if ($name !== '') {
- $name_key = strtolower($name);
-
- if (isset($seen_names[$name_key])) {
- $errors[] = [
- 'index' => $index,
- 'field' => 'roleName',
- 'message' => __('Duplicate role name', 'highland-software-custom-role-manager')
- ];
+ if ($type === 'grouping') {
+ $group = sanitize_text_field($row['groupName'] ?? '');
+ return $group ? ['type'=>'grouping','groupName'=>$group] : null;
}
- $seen_names[$name_key] = true;
- }
- /**
- * 5. Prevent modifying default roles
- */
- if ($slug !== '' && in_array($slug, $default_roles, true)) {
- $errors[] = [
- 'index' => $index,
- 'field' => 'roleSlug',
- 'message' => __('Default role cannot be modified', 'highland-software-custom-role-manager')
- ];
- }
+ if ($type === 'separator') {
+ return ['type'=>'separator'];
+ }
+
+ return null;
+
+ }, $raw_rows)));
}
- /**
- * If validation fails, return errors
- */
- if (!empty($errors)) {
- wp_send_json_error([
- 'errors' => $errors
- ]);
+ // 🔒 Ensure final structure is always array
+ if (!is_array($rows)) {
+ $rows = [];
}
- /**
- * Save data
- */
update_option('hscrm_roles', $rows);
- /**
- * Sync roles with WordPress
- */
+ // 🔒 Always sync (even empty → removes all custom roles)
hscrm_sync_roles($rows);
- /**
- * Success response
- */
- wp_send_json_success([
- 'message' => __('Roles saved successfully', 'highland-software-custom-role-manager')
- ]);
-}
+ wp_send_json_success(['message' => 'Roles saved successfully']);
+ wp_die();
+});
/* =========================
- CHECK Role Slug
+ CHECK ROLE SLUG
========================= */
-
-/**
- * Validates Role Slug against existing roles
- */
add_action('wp_ajax_hscrm_check_role_slug', function(){
- check_ajax_referer('hscrm_ajax_nonce','nonce');
+ check_ajax_referer('hscrm_ajax_nonce','nonce');
- $default_roles = ['administrator','editor','author','contributor','subscriber'];
-
- $slug = sanitize_key($_POST['slug'] ?? '');
-
- if ($slug === '') {
- wp_send_json_success([
- 'is_default' => false,
- 'exists' => false,
- ]);
+ if (!hscrm_user_can_manage_roles()) {
+ wp_send_json_error(['message' => 'Unauthorized'], 403);
+ wp_die();
}
- $is_default = in_array($slug, $default_roles, true);
- $exists = get_role($slug) !== null;
+ $slug = isset($_POST['slug']) ? sanitize_key(wp_unslash($_POST['slug'])) : '';
+
+ $default_roles = ['administrator','editor','author','contributor','subscriber'];
wp_send_json_success([
- 'is_default' => $is_default,
- 'exists' => $exists,
+ 'is_default' => in_array($slug, $default_roles, true),
+ 'exists' => $slug ? (get_role($slug) !== null) : false,
]);
+
+ wp_die();
});
/* =========================
GET CAPABILITIES HTML
========================= */
-
-/**
- * Returns capability UI HTML
- */
add_action('wp_ajax_hscrm_get_capabilities', function(){
- check_ajax_referer('hscrm_ajax_nonce','nonce');
+ check_ajax_referer('hscrm_ajax_nonce','nonce');
+
+ if (!hscrm_user_can_manage_roles()) {
+ wp_send_json_error(['message' => 'Unauthorized'], 403);
+ wp_die();
+ }
+
+ // hscrm_rate_limit('get_caps');
+
+ wp_send_json_success([
+ 'html' => hscrm_get_capabilities_html()
+ ]);
- if (!current_user_can('manage_options')) {
- wp_send_json_error(['message'=>__('Unauthorized', 'highland-software-custom-role-manager')]);
- }
-
- wp_send_json_success([
- 'html' => hscrm_get_capabilities_html()
- ]);
+ wp_die();
});
No newline at end of file
--- a/highland-software-custom-role-manager/includes/assets.php
+++ b/highland-software-custom-role-manager/includes/assets.php
@@ -33,6 +33,11 @@
* - User edit/profile/create pages
* - Plugin admin pages (identified by 'hscrm' in hook)
*/
+
+ if (!hscrm_user_can_manage_roles()) {
+ return;
+ }
+
$load_assets = false;
if (in_array($hook, ['user-edit.php', 'profile.php', 'user-new.php'], true)) {
--- a/highland-software-custom-role-manager/includes/helpers.php
+++ b/highland-software-custom-role-manager/includes/helpers.php
@@ -0,0 +1,9 @@
+<?php
+
+if (!defined('ABSPATH')) {
+ exit;
+}
+
+function hscrm_user_can_manage_roles() {
+ return current_user_can('promote_users') && current_user_can('list_users');
+}
No newline at end of file
--- a/highland-software-custom-role-manager/includes/roles.php
+++ b/highland-software-custom-role-manager/includes/roles.php
@@ -128,7 +128,13 @@
* - Capabilities come from UI, must be trusted or validated upstream
*/
foreach ($caps as $cap) {
- $cap_array[sanitize_key($cap)] = true;
+ $cap = sanitize_key($cap);
+
+ if ($cap === 'manage_options') {
+ continue;
+ }
+
+ $cap_array[$cap] = true;
}
add_role($slug, $name, $cap_array);
--- a/highland-software-custom-role-manager/includes/user-ui.php
+++ b/highland-software-custom-role-manager/includes/user-ui.php
@@ -95,20 +95,20 @@
$is_checked = in_array($role_slug, $user_roles, true);
- echo '<label style="display:block; margin-bottom:6px;">';
+ echo '<label style="display:block; margin-bottom:6px;">';
- echo '<input type="checkbox"
- name="hscrm_roles[]"
- value="' . esc_attr($role_slug) . '" ';
+ echo '<input type="checkbox"
+ name="hscrm_roles[]"
+ value="' . esc_attr($role_slug) . '" ';
- checked($is_checked, true);
- disabled(!$can_promote);
+ checked($is_checked, true);
+ disabled(!$can_promote);
- echo '>';
+ echo '>';
- echo ' ' . esc_html(translate_user_role($role_data['name']));
+ echo ' ' . esc_html(translate_user_role($role_data['name']));
- echo '</label>';
+ echo '</label>';
}
/**
@@ -131,7 +131,6 @@
foreach ($saved as $item) {
- // GROUPING
if (($item['type'] ?? '') === 'grouping' && !empty($item['groupName'])) {
echo '<div style="margin-top:10px; font-weight:bold;">'
. esc_html($item['groupName']) .
@@ -139,13 +138,11 @@
continue;
}
- // SEPARATOR
if (($item['type'] ?? '') === 'separator') {
echo '<div style="margin-top:10px;"><hr></div>';
continue;
}
- // ROLE
if (($item['type'] ?? '') === 'role') {
$slug = sanitize_key($item['roleSlug'] ?? '');
$label = sanitize_text_field($item['roleName'] ?? '');
@@ -193,29 +190,34 @@
function hscrm_save_user_roles($user_id) {
- /**
- * SECURITY: Capability check
- */
+ $user_id = intval($user_id);
+ if ($user_id <= 0) {
+ return;
+ }
+
+ $user = get_userdata($user_id);
+ if (!$user) {
+ return;
+ }
+
+ if (!current_user_can('promote_users')) {
+ return;
+ }
+
if (!current_user_can('edit_user', $user_id)) {
return;
}
- /**
- * SECURITY: Nonce verification
- */
if (
!isset($_POST['hscrm_roles_nonce']) ||
!wp_verify_nonce(
sanitize_text_field(wp_unslash($_POST['hscrm_roles_nonce'])),
'hscrm_save_user_roles'
- )
+ )
) {
return;
}
- /**
- * Sanitize roles
- */
$raw_roles = [];
if (isset($_POST['hscrm_roles']) && is_array($_POST['hscrm_roles'])) {
@@ -226,77 +228,67 @@
}
if (!is_array($raw_roles)) {
- return; // do not use wp_send_json_error in non-AJAX context
+ return;
}
- $roles = array_map(function ($role) {
- return sanitize_key($role);
- }, $raw_roles);
+ $roles = array_values(array_unique(array_filter($raw_roles)));
- /**
- * Setup
- */
- $user = new WP_User($user_id);
+ $editable_roles = get_editable_roles();
+
+ $roles = array_values(array_filter($roles, function ($role) use ($editable_roles) {
+ return isset($editable_roles[$role]);
+ }));
$default_role = get_option('default_role', 'subscriber');
$core_roles = ['administrator','editor','author','contributor','subscriber'];
- /**
- * Prevent removing ALL roles
- */
if (empty($roles)) {
-
- // If user was administrator, keep it
- if (in_array('administrator', $user->roles, true)) {
+ if (in_array('administrator', (array) $user->roles, true)) {
$roles = ['administrator'];
} else {
$roles = [$default_role];
}
}
- /**
- * Ensure at least one core role remains
- */
$has_core = array_intersect($roles, $core_roles);
if (empty($has_core)) {
$roles[] = $default_role;
}
- /**
- * Ensure at least one valid role exists
- */
- $roles = array_values(array_unique(array_filter($roles)));
+ $roles = array_values(array_unique(array_filter($roles, function ($role) {
+ return is_string($role) && get_role($role) !== null;
+ })));
- /**
- * Save to user meta (custom roles system)
- */
- update_user_meta($user_id, 'hscrm_custom_roles', $roles);
+ if (empty($roles)) {
+ return;
+ }
- /**
- * Assign primary role (WordPress compatibility)
- * Only assign the FIRST role as primary
- */
- $primary_role = $roles[0] ?? $default_role;
+ $primary_role = $roles[0];
- /**
- * Prevent assigning invalid or empty role
- */
if (!get_role($primary_role)) {
$primary_role = $default_role;
}
- /**
- * Apply role safely
- */
+ $final_roles = array_values(array_unique(array_filter($roles)));
+
+ if (!in_array($primary_role, $final_roles, true)) {
+ array_unshift($final_roles, $primary_role);
+ }
+
+ error_log(sprintf(
+ 'HSCRM: User %d changed roles for user %d to: %s',
+ get_current_user_id(),
+ $user_id,
+ implode(',', $final_roles)
+ ));
+
+ update_user_meta($user_id, 'hscrm_custom_roles', $final_roles);
+
$user->set_role($primary_role);
- /**
- * OPTIONAL HARDENING:
- * Re-add additional roles (if you want true multi-role support at WP level)
- */
- foreach ($roles as $role) {
+ foreach ($final_roles as $role) {
if ($role !== $primary_role && get_role($role)) {
$user->add_role($role);
}
--- a/highland-software-custom-role-manager/uninstall.php
+++ b/highland-software-custom-role-manager/uninstall.php
@@ -16,7 +16,9 @@
* - Plugin environment is NOT fully loaded here
* - Only use WordPress core functions that are safe in uninstall context
*/
-
+if (!defined('ABSPATH')) {
+ exit;
+}
/**
* Prevent direct access
*
@@ -54,66 +56,92 @@
*/
$hscrm_saved = get_option('hscrm_roles', []);
- if (is_array($hscrm_saved)) {
+ if (!is_array($hscrm_saved)) {
+ $hscrm_saved = [];
+ }
- /**
- * Collect custom role slugs first
- *
- * This avoids repeated user loops for each role
- */
- $hscrm_custom_roles = [];
+ /**
+ * Collect custom role slugs first
+ *
+ * This avoids repeated user loops for each role
+ */
+ $hscrm_custom_roles = [];
- foreach ($hscrm_saved as $hscrm_row) {
+ foreach ($hscrm_saved as $hscrm_row) {
- // Skip non-role entries (e.g., groupings)
- if (($hscrm_row['type'] ?? '') !== 'role') {
- continue;
- }
+ // Skip invalid rows
+ if (!is_array($hscrm_row)) {
+ continue;
+ }
- $hscrm_slug = sanitize_key($hscrm_row['roleSlug'] ?? '');
+ // Skip non-role entries (e.g., groupings)
+ if (($hscrm_row['type'] ?? '') !== 'role') {
+ continue;
+ }
- // Skip invalid or default roles
- if (!$hscrm_slug || in_array($hscrm_slug, $default_roles, true)) {
- continue;
- }
+ $hscrm_slug = sanitize_key($hscrm_row['roleSlug'] ?? '');
- $hscrm_custom_roles[] = $hscrm_slug;
+ // Skip invalid or default roles
+ if (!$hscrm_slug || in_array($hscrm_slug, $hscrm_default_roles, true)) {
+ continue;
}
- /**
- * Remove custom roles from all users
- *
- * Edge case:
- * - Users may still have roles assigned that are about to be removed
- * - We remove them first to prevent orphaned role assignments
- */
- if (!empty($hscrm_custom_roles)) {
+ // Ensure role actually exists before processing
+ if (!get_role($hscrm_slug)) {
+ continue;
+ }
+
+ $hscrm_custom_roles[] = $hscrm_slug;
+ }
- $hscrm_users = get_users();
+ // Normalize role list
+ $hscrm_custom_roles = array_values(array_unique($hscrm_custom_roles));
+
+ /**
+ * Remove custom roles from all users
+ *
+ * Edge case:
+ * - Users may still have roles assigned that are about to be removed
+ * - We remove them first to prevent orphaned role assignments
+ */
+ if (!empty($hscrm_custom_roles)) {
- foreach ($hscrm_users as $hscrm_user) {
+ // Use efficient user query (IDs only)
+ $hscrm_user_query = new WP_User_Query([
+ 'fields' => 'ID',
+ 'number' => -1
+ ]);
- $hscrm_user_obj = new WP_User($hscrm_user->ID);
- $hscrm_user_roles = $hscrm_user_obj->roles;
+ $hscrm_user_ids = $hscrm_user_query->get_results();
- foreach ($hscrm_user_roles as $hscrm_role) {
+ foreach ($hscrm_user_ids as $hscrm_user_id) {
- if (in_array($hscrm_role, $hscrm_custom_roles, true)) {
- $hscrm_user_obj->remove_role($hscrm_role);
- }
+ $hscrm_user_obj = new WP_User($hscrm_user_id);
+
+ foreach ((array) $hscrm_user_obj->roles as $hscrm_role) {
+
+ if (in_array($hscrm_role, $hscrm_custom_roles, true)) {
+ $hscrm_user_obj->remove_role($hscrm_role);
}
}
/**
- * Remove roles from WordPress
- *
- * Important:
- * - Only remove roles AFTER user cleanup
+ * Ensure user still has at least one role
*/
- foreach ($hscrm_custom_roles as $hscrm_role_slug) {
- remove_role($hscrm_role_slug);
+ if (empty($hscrm_user_obj->roles)) {
+ $hscrm_user_obj->set_role(get_option('default_role', 'subscriber'));
}
}
+
+ /**
+ * Remove roles from WordPress
+ *
+ * Important:
+ * - Only remove roles AFTER user cleanup
+ */
+ foreach ($hscrm_custom_roles as $hscrm_role_slug) {
+ remove_role($hscrm_role_slug);
+ }
}
}