1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
<?php
// ***************************************************************
// Remove any role that has a capability that the current user doesn't have.
// 
// uses the 'editable_roles' filter which might not exist yet. Probably
// won't be around until 2.6 is released, maybe 2.5.1...
//

function filter_editable_roles($roles) {
	foreach ($roles as $role => $details) :
		foreach ($details['capabilities'] as $capability => $value) :
			if (!current_user_can($capability)) :
				unset ($roles[$role]);
				break;
			endif; 
		endforeach; //capabilities
	endforeach; //foreach $wp_roles;
	return $roles;
}
add_filter('editable_roles', 'filter_editable_roles');



// ***************************************************************
// Check if the logged in user should be allowed to edit another
// user. 
//
// For hooking into 'user_has_cap' filter. Use when doing a 
// check for current_user_can('edit_user', $user_id);
// Works by comparing the logged-in user to the $user_object,
// if $user_object has any capability that the logged-in user DOESN'T
// then the edit is denied. 
//
// NOTE: this won't help stopping users from being PROMOTED to an 
// innapropriate role. For that the promotion logic needs to get
// the filtered roles with get_editable_roles
//
// $allcaps - a copy of $wp_roles->role_names , it should return with
//          innapropriate roles removed.
			
function check_user_editable($allcaps, $caps, $args) {
	// only run if we're checking the 'edit_users' cap
	// also, only if there is a second argument in $args (the second, edited, user)
	if ($caps[0] == 'edit_users' && $args[2]) :
		
		// Get full information about the user that they want to edit.
		global $user_object, $wp_roles;
		
		// The $user_object variable is often not available when checks like this are made. 
	
		// line 109 of /wp-admin/user-edit.php 
		
	
		// Not doing that yet though, for now we'll just
		// return the list as before if the $user_object doesn't have the 
		// same ID as the argument that was passed into the filter
		
		if (!$user_object) $user_object = new wp_user($args[2]);


		if ($user_object->ID != $args[2]) return $allcaps;
		
		$edited_user_caps = $user_object->allcaps;
		$edited_user_roles = $user_object->roles;
		$checked_roles = array();

		// go through edited user's roles, and check for missing caps. 
		foreach ($edited_user_roles as $role => $name) :
			$rolecaps = $wp_roles->roles[$name]['capabilities'];
			foreach($rolecaps as $capability => $value) :
				if (!current_user_can($capability)) :
					unset ($allcaps['edit_users']);
					return $allcaps;
				endif; 
			endforeach; // rolecaps
			// add the role to a list of checked roles if there are no problems
			$checked_roles[] = $name;
		endforeach; // foreach edited_user_roles
		
		// This only runs if there were no conflicts while checking roles
		// go through the edited users caps and check if current user has them all
		foreach ($edited_user_caps as $capability => $value) :
			if (in_array($capability, $checked_roles)) :
				continue;
			elseif (!current_user_can($capability)) :
				unset ($allcaps['edit_users']);
				return $allcaps;
			endif; 
		endforeach; //capabilities	
	endif;// if edit_users
	 
	return $allcaps;
}

add_filter('user_has_cap', 'check_user_editable', 10, 3)
?>