Using BuddyPress Group Membership for Post Access Control

Veröffentlicht in: Probleme & Lösungen | 0

I have looked around the internet for a while. I could only find questions but no real solutions. What did I want to do? Read on …

I had a web site based on WordPress (WP) where people should see certain content (posts/pages/…) only when they were logged in to the site. That means, visitors should only see public pages. Further more, some registered users should see only some of the protected content.

There is a nice plugin, the User Access Manager (UAM), which does most of the job. Its concept is to create user groups and assign users to one or more of these groups. You then restrict access to posts and pages and categories based on these user groups.

I also wanted more functionality on the site, which included a forum membership also based on the user and probably a group membership. There is a nice plugin for this too: BuddyPress and the forum bbPress. BuddyPress (BP) would also let users invite others, even new users, to a group, where UAM requires the administrator to add users manually.

Problem here: I now had too different lists of user groups. One from the UAM and one from BP.

 

Solution #1 (deprecated)

My (first) idea was too combine the two, so that a user being member in a BP group would also be member of the UAM group with the same name automatically. The solution is shown here, BUT there is a little security flaw: if the administrator adds a UAM group (for some purpose aside from BP) and there is no BP group of that name yet, then front-end BP users may create such group and elevate their access permissions to the existing UAM group. See solution #2 below

Here is what I did:

Find the source code of the UAM plugin within your WordPress installation. Within the plugin directory there is a file named UamUserGroup.class.php. (The full path from the home directory of your web site is: wp-content/plugins/user-access-manager/class/UamUserGroup.class.php)

Edit this file. Find the functtion _getFullUser.

 

protected function _getFullUser($iObjectId)
{
 $aIsRecursiveMember = array();
 
 global $wpdb;
 
 $oCurUserData = get_userdata($iObjectId);
 
 if (isset($oCurUserData->{$wpdb->prefix . "capabilities"})) {
  $aCapabilities = $oCurUserData->{$wpdb->prefix . "capabilities"};
 } else {
  $aCapabilities = array();
 }
 
 $aRoles = (is_array($aCapabilities) && count($aCapabilities) > 0) ? array_keys($aCapabilities) : array('norole');
 $aObjects = $this->getObjectsFromType('role');

 foreach ($aRoles as $sRole) {
  if (isset($aObjects[$sRole])) {
   $oRoleObject = new stdClass();
   $oRoleObject->name = $sRole;

   $aIsRecursiveMember = array('role' => array());
   $aIsRecursiveMember['role'][] = $oRoleObject;
 
   break; // (JL) can stop here, any further role would delete the previous anyway
  }
 }

 // (JL) check if user is member of a BuddyPress group with the same name like this UAM group
 if ($aIsRecursiveMember == array() && function_exists("bp_loggedin_user_id")) {
  $uamGroupName = $this->getGroupName();
  $bp_groups = groups_get_user_groups($iObjectId);
  foreach ($bp_groups["groups"] as $bp_group_id) {
   $bp_group_name = groups_get_group(array( 'group_id' => $bp_group_id )) -> name;
   if ($bp_group_name == $uamGroupName) {
    $oGroupObject = new stdClass();
    $oGroupObject->name = $bp_group_name;

    $aIsRecursiveMember = array('bp_group' => array());
    $aIsRecursiveMember['bp_group'][] = $oGroupObject;

    break;
   }
  }
 }
 
 return $aIsRecursiveMember;
}

 

The red lines are the ones I inserted into the original function. The change is based on UAM version 1.2.6.10.

 

Solution #2 (recommended)

The idea here is about introducing pseudo WP user roles indicating BP group membership of a user. UAM already has a mechanism for making users member of a UAM group if they have one or more required WP roles. When creating or editing a UAM group you see these roles as a list of check boxes. After introducing the change below, this list will be extended by the list of currently defined BP groups. The role name is built in the format „bpg_<id>_<slug>“ where the <id> is the unique group number and the slug resembles the name of the group. When administering the UAM group you need to check one (or even more) BP groups here in order to make users, who are member of those BP groups, become member of this UAM group.

Here is what I did:

Find the source code of the UAM plugin within your WordPress installation. Within the plugin directory there is a file named UamUserGroup.class.php. (The full path from the home directory of your web site is: wp-content/plugins/user-access-manager/class/UamUserGroup.class.php)

Edit this file. Find the functtion _getFullUser.

protected function _getFullUser($iObjectId)
{
 $aIsRecursiveMember = array();
 
 global $wpdb;
 
 $oCurUserData = get_userdata($iObjectId);
 $aRoles = $oCurUserData->roles;
 
 if (isset($oCurUserData->{$wpdb->prefix . "capabilities"})) {
  $aCapabilities = $oCurUserData->{$wpdb->prefix . "capabilities"};
 } else {
  $aCapabilities = array();
 }
 
 $aRoles = (is_array($aCapabilities) && count($aCapabilities) > 0) ? array_keys($aCapabilities) : array('norole');
 
 // (JL) add pseudo roles for each BuddyPress group membership
 if (function_exists("groups_get_user_groups")) {
  $bp_group_ids = groups_get_user_groups($iObjectId)["groups"];
  foreach ($bp_group_ids as $bp_group_id) {
   $bp_group = groups_get_group(array( 'group_id' => $bp_group_id ));
   $bp_role = "bpg_" . $bp_group->id . "_" . $bp_group->slug;
   array_push($aRoles, $bp_role);
  }
 }

 $aObjects = $this->getObjectsFromType('role');

 foreach ($aRoles as $sRole) {
  if (isset($aObjects[$sRole])) {
   $oRoleObject = new stdClass();
   $oRoleObject->name = $sRole;

   $aIsRecursiveMember = array('role' => array());
   $aIsRecursiveMember['role'][] = $oRoleObject;
 
   break; // (JL) can stop here, any further role would delete the previous anyway
  }
 }

 return $aIsRecursiveMember;
}

 

Within the plugin directory there is another file named adminGroup.php. (The full path from the home directory of your web site is: wp-content/plugins/user-access-manager/tpl/adminGroup.php)

Edit this file. Find the the line which reads: foreach ($wp_roles->role_names as $role => $name)

Replace this line by the following:

 $aRoles = $wp_roles->role_names;

 // JL: add a pseudo role for each BuddyPress group
 if (function_exists("groups_get_groups")) {
  foreach(groups_get_groups()["groups"] as $bp_group) {
   $bp_role = "bpg_" . $bp_group->id . "_" . $bp_group->slug;
   $aRoles[$bp_role] = $bp_group->name;
  }
 }

 foreach ($aRoles as $role => $name) {
 foreach ($wp_roles->role_names as $role => $name)

And some lines further down I did the following beauty correction. The displayed label was the technical role name. Now it shows the human readable name (and the technical name in parenthesis).

 <label for="role-<?php echo $role; ?>">
  <?php echo $role; ?>
  <?php echo $name . " (" . $role . ")"; ?>
 </label>

 

The red lines are the ones I inserted into the original function. The change is based on UAM version 1.2.6.10.

 

Solution #3 (preferred)

Editing plugins from other sources has certain disadvanges, like when the original author releases new versions. Furthermore the solution given above is valid for the User Access Manager plugin only.

That’s why I finally created my own plugin: BuddyPress Group Roles. Just download the plugin, install it on your WordPress together with BuddyPress and any access management plugin like User Access Manager and be happy …

For more information see the full discription of the plugin.