How to allow subsite administrators to edit users in a WordPress Multisite Network

on in WordPress
Last modified on

WordPress Multisite

WordPress Multisite is a powerful feature that allows me to manage multiple WordPress websites (or subsites) from a single installation. However, one of the frustrating limitations is that subsite administrators cannot edit users. This restriction is primarily designed to maintain security and control over network-wide user management. In a WordPress 3.x+ Network, only Super Admins are granted the privilege to edit users. In my case, I need subsite administrators to edit potentially hundreds of subsite users.

Diagnosing the Problem

The first instinct was to assign the edit_users capability to the admin role. After all, if a user has the edit_users capability, it seems logical that they should be able to edit other users’ profiles. However, it’s not that straightforward.

Upon closer inspection, I discovered that, even though administrators don’t have the ability to edit users, they do, in fact, possess the edit_users capability. Like I said, frustrating.

The Heart of the Matter

To understand why administrators can’t edit users in a WordPress Multisite network, I looked and found the map_meta_cap capability, which can be found in the capabilities.php file.

case 'edit_users':
    // If multisite, these caps are allowed only for super admins.
    if ( is_multisite() && !is_super_admin( $user_id ) )
        $caps[] = 'do_not_allow';
    else
        $caps[] = 'edit_users'; // Explicit due to primitive fall through
    break;

This code snippet reveals the master override that prevents any role other than Super Admin from editing other users.

Using the map_meta_cap Filter

Fortunately, WordPress offers a solution through the use of filters. The $caps array, which contains the capabilities for a user, is passed through a filter before being returned:

return apply_filters('map_meta_cap', $caps, $cap, $user_id, $args);

To overcome the limitation, I used the map_meta_cap filter to transform the do_not_allow capability in the $caps array into either edit_users, delete_users, or create_users. This filter modifies the capabilities assigned to users, effectively granting administrators the ability to edit users in a Multisite network.

/**
 * Allows subsite administrators to edit users in a WordPress Multisite network.
 *
 * In a WordPress 3.x Network, the Super Admin role is the only role allowed to edit users.
 *
 * @param array   $caps    The user's capabilities.
 * @param string  $cap     The capability being checked.
 * @param int     $user_id The user ID.
 * @param mixed   $args    Additional arguments.
 *
 * @return array Modified user capabilities.
 */
function wppd_admin_users_caps( $caps, $cap, $user_id, $args ) {
    foreach ( $caps as $key => $capability ) {
        if ( $capability != 'do_not_allow' ) {
            continue;
        }

        switch ( $cap ) {
            case 'edit_user':
            case 'edit_users':
                $caps[$key] = 'edit_users';
                break;
            case 'delete_user':
            case 'delete_users':
                $caps[$key] = 'delete_users';
                break;
            case 'create_users':
                $caps[$key] = $cap;
                break;
        }
    }

    return $caps;
}

// Apply the wppd_admin_users_caps function to the 'map_meta_cap' filter.
add_filter( 'map_meta_cap', 'wppd_admin_users_caps', 1, 4 );

// Remove all filters for 'enable_edit_any_user_configuration'.
remove_all_filters( 'enable_edit_any_user_configuration' );

// Add a filter to enable editing any user configuration.
add_filter( 'enable_edit_any_user_configuration', '__return_true' );

/**
 * Checks that both the editing user and the user being edited are
 * members of the same blog and prevents editing super admin users.
 */
function wppd_edit_permission_check() {
    global $current_user, $profileuser;

    $screen = get_current_screen();

    get_currentuserinfo();

    if ( ! is_super_admin( $current_user->ID ) && in_array( $screen->base, [ 'user-edit', 'user-edit-network' ] ) ) {
        // Editing a user profile.
        if ( is_super_admin( $profileuser->ID ) ) {
            // Trying to edit a super admin while not being a super admin.
            wp_die( __( 'You do not have permission to edit this user.' ) );
        } elseif ( ! ( is_user_member_of_blog( $profileuser->ID, get_current_blog_id() ) && is_user_member_of_blog( $current_user->ID, get_current_blog_id() ) ) ) {
            // Editing user and edited user aren't members of the same blog.
            wp_die( __( 'You do not have permission to edit this user.' ) );
        }
    }
}

// Apply the wppd_edit_permission_check function to the 'admin_head' filter.
add_filter( 'admin_head', 'wppd_edit_permission_check', 1, 4 );

Conclusion

This restores the edit_users, delete_users and create_users capabilities to their former glory.

If a user has the admin role, or has been manually assigned any of these capabilities, they will then be able to edit users.

Put the code above in a must-use plugin in the /wp-content/mu-plugins/ directory.

Photo by Fikret tozak on Unsplash

Related posts