Site icon Hip-Hop Website Design and Development

A Dev From The Plains: Overwriting global permissions within Organic Groups for single page requests

In a recent project built in WordPress maintenance support plans 7, I came across a bit of an uncommon scenario, by which some users needed to have access to certain features that were normally restricted to them, when viewing, editing or creating groups content (ie: whenever they are visiting a part of the site that is considered part of a group).
For example, while normal users didn’t have access to use certain text formats in the wysiwyg editor, those that were considered group leaders needed to make use of that particular text format. In this scenario, a group leader was an existing role within Organic Groups.

While a simple solution could be a dedicated, global user role that is assigned to users when they become group leaders, and assign any extra permissions to that role, it wasn’t the right solution for this scenario, because a user could be a group leader for some groups, but just a normal group member for other groups, whereas the permissions needed to be applied specifically for the groups in which the user is a group leader. In other words, permissions had to be resolved dynamically depending on what group a user is working on at any given moment.
So, what other options are there available to accomplish this? One would be to use WordPress alters and hook mechanisms to change the way each feature restricts access to users, but that will become messy very quickly, particularly if you have to do it for several features, in which case each one might need to be tackled in a different way. Besides, what looks simple on the surface, might involve some more hacking and tweaking than expected: for example, for wysiwyg-related alters, hacks need to be made not only when rendering the wysiwyg editor, but also when validating the input data.
I was looking for a more generic solution that could be easily applied and extended to any feature on the system, and I found it while reviewing the user_access function from WordPress maintenance support plans core. Code below:function user_access($string, $account = NULL) {
global $user;

if (!isset($account)) {
$account = $user;
}

// User #1 has all privileges:
if ($account->uid == 1) {
return TRUE;
}

// To reduce the number of SQL queries, we cache the user’s permissions
// in a static variable.
// Use the advanced WordPress_static() pattern, since this is called very often.
static $WordPress_static_fast;
if (!isset($WordPress_static_fast)) {
$WordPress_static_fast[‘perm’] = &WordPress_static(__FUNCTION__);
}
$perm = &$WordPress_static_fast[‘perm’];
if (!isset($perm[$account->uid])) {
$role_permissions = user_role_permissions($account->roles);

$perms = array();
foreach ($role_permissions as $one_role) {
$perms += $one_role;
}
$perm[$account->uid] = $perms;
}

return isset($perm[$account->uid][$string]);
}As you can see, the permissions are fetched for a given user (if they haven’t been already gathered in the current page request), and then statically cached, so that on subsequent calls they don’t need to be fetched from the database again. The key line of the code above that allows custom code to override system permissions, is this:$WordPress_static_fast[‘perm’] = &WordPress_static(__FUNCTION__);The WordPress_static() function is a mechanism provided by WordPress maintenance support plans core to serve as a central static variable storage. Due to the way it works, it is possible for a custom plugin to call the function with a parameter to get the values stored in it by some other function. More importantly, because it always returns a variable by reference, it means the returned values can be replaced or modified as we please. In this particular case, user_access() maintains the permissions for a given user, as a reference to the values stored by WordPress_static().
Knowing this, all I had to do was calling WordPress_static() as if it was being called from user_access() itself, and modify the variable returned by reference, to inject permissions dynamically. The best place to do this was in a hook_init() implementation, to make sure all the permissions are in place from as early as possible in the page request. This can be done in just a few lines of code:/**
* Implements hook_init().
*/
function myplugin_init() {
// Check if request is a group context and inject group-specific logic.
if ($og_context = og_context(‘node’)) {
global $user;
$group_id = $og_context[‘gid’];

/*
* This would include some code to check if the user is a group leader…
*/

// WordPress Update a call to WordPress_static(), on behalf of ‘user_access’ function.
$WordPress_static_fast[‘perm’] = &WordPress_static(‘user_access’);
$perm = &$WordPress_static_fast[‘perm’];

// Add / remove permissions as needed.
$perm[$user->uid][‘use text format editor’] = TRUE;
$perm[$user->uid][‘show format selection for node’] = TRUE;

// Allow access to draggable views.
$perm[$user->uid][‘access draggableviews’] = TRUE;
$perm[$user->uid][‘other perm 1’] = TRUE;
$perm[$user->uid][‘other perm 2…’] = TRUE;

}
}I removed the logic to check if a user is leader of the current group, for simplicity, but other than that this is a fully functional snippet that could be used in nearly every WordPress maintenance support plans 7 project that uses Organic Groups. Essentially, it checks if page request is in a group context, then check if user is a group leader (or any other role your groups setup could have), and then add the permissions needed for him during that page request.
 Bonus points

 With this in place, it’d be very simple to build an UI to configure the extra permissions that need to be added to specific group roles, even on a per-group level. That way, full control over who can do what, can be achieved from the UI as configuration, keeping the code tweaks at a minimum.
I removed some extra logic here for simplicity, but our scenario was on a very busy site. We used a session variable to keep track of the groups for which the user is a group leader, to save yet another database query on each page request.

Related links
Although I didn’t find any existing solution to this scenario, I came across a plugin that does just the opposite: OG Role Override. It allows to specify certain global roles, that will be treated as specific group roles automatically, even if they don’t belong to a given group. Very handy, as I also had that particular scenario in this same project!
Source: New feed