Adding Users to User Groups in Code

Several different methods for adding users to user groups in code.

By Bob Ray  |  November 21, 2023  |  5 min read
Adding Users to User Groups in Code

As I’m sure you know, there’s almost never just one way to do something in MODX. In this article, we’ll see several different ways to add a user to a user group and look at some of the finer points of each method.

The Simple Way

This is not the fastest way to add a user to a user group, but it couldn’t be much simpler. Assuming that you have the user object, you just do this:

$user->joinGroup('Group1');

If you know the ID of the group, this would be slightly faster:

$user->joinGroup(12);

Using joinGroup() also allows you to set the user’s role with either the name or the ID of the role:

$user->joinGroup('Group1', 'Editor');
$user->joinGroup('Group1', 23);

You can mix and match the types of the arguments at will. All these are valid:

$user->joinGroup('Group1', 'Editor');
$user->joinGroup('Group1', 23);
$user->joinGroup(12, 'Editor');
$user->joinGroup(12, 23);

A Word of Warning

Because you can mix and match the argument types, MODX has to detect what you’ve sent it. It does this by using the is_string() function. If you send it a string for either the group name or the role, it will always assume that it’s a name, not an ID. That means that if your group has an ID of 12, this isn’t going to work:

$user->joinGroup('12');

With that code, MODX will try to put the user in a group named 12 rather than in the group with that ID. This problem is especially likely to bite you if you use a Snippet property, Plugin property, or a TV, to set the ID of a group or role. Those will all be Strings. To avoid this when using IDs with joinGroup() it’s a good practice to get in the habit of doing this:

$user->joinGroup( (int) $groupId, (int) $roleId);

By “casting” the variables to (int), you can make sure that MODX always receives a number rather than a string, regardless of the type of the original variable. Similarly, if your user groups have numeric names (e.g., '143'), be sure you send a string to joinGroup(). If you are a belt and suspenders kind of person, you can do this:

$user->joinGroup( (string) $groupName, (string) $roleName);

Error Prevention Checks

If you try to add a user to a group they already belong to with joinGroup(), MODX will throw an error. There are two solutions to this. One is to check with isMember():

if (! $user->isMember('groupName')) {
    $user->joinGroup( (int) $groupId, (int) $roleId);
}

Note that isMember() only accepts a group name, not a group ID, so be careful what you send it. If you send an ID, it will always return false (unless it has been re-written by the time you read this). Note also that it is $user->isMember(), not $modx->isMember().

Using isMember() is redundant because joinGroup() also checks to see if the user is already a member before adding them to the group. If the user is already a member, joinGroup() won't try to add them, but it will put an error in the MODX error log. Another solution is to simply suppress that error message with @ when calling joinGroup():

@$user->joinGroup( (int) $groupId, (int) $roleId);

A Slightly Faster Way

This method is only a tiny bit faster than using joinGroup(), so it’s seldom worth the trouble unless you need to add a ton of users to a group or groups.

As we mentioned above, the user’s group membership is stored in the modUserGroupMember object. This code essentially duplicates the joinGroup code so it only saves the few milliseconds it takes to make the function call to joinGroup() plus the check to see whether the user is already a member. It should only be used if you’re sure the user is not already a member. In this method, we create the modUserGroupMember object ourselves, set its two fields, and save it:

$userId = $modx->user->get('id');
$groupId = 12;
$roleId = 23;

$member = $this->xpdo->newObject('modUserGroupMember');
$member->set('member',$userId);
$member->set('user_group',$groupId);
/* optional */
$member->set('role',$roleId);

$member->save();

Using this method, the values for each field must be IDs, not names, and calling save() is required. We could add a check with $modx->getObject('modUserGroupMember) to see if the user is already a member, but if you need that, you might as well just use joinGroup().

The Slow Way

This way is slower, but there are some situations where it makes sense. It basically adds the user to a user group, or vice versa, using addMany(). Because a user can be in more than one group and a group can have more than one user, you can never use addOne() here, even if you’re only adding one user to one group. The addMany() method takes an array and requires the argument to be an array of objects:

/* Make it run in either MODX 2 or MODX 3 */
$prefix = $modx->getVersionData()['version'] >= 3
  ? 'MODX\Revolution\\'
  : '';

$groupId = 12;

$userGroup = $modx-getObject($prefix . 'modUserGroup', $groupId);
$userGroup->addMany(array($userObject));
$userGroup->save();

// or

$user->addMany(array($userGroup));
$user->save();

Why would you want to use this method? This way of adding users to user groups makes sense if either the user group or the user is newly created. In that case, you don’t know its ID, and you’re going to have to save it anyway, so adding the other object to it before the save, won’t add a lot of time, and it keeps you from having to save the object first in order to get its ID.

As the method name (addMany) suggests, you can also add the user to multiple groups for either method above by creating an array like this:

$groups = array(12,14,23)
$user->addMany->$groups;
$user->save();

Bob Ray is the author of the MODX: The Official Guide and dozens of MODX Extras including QuickEmail, NewsPublisher, SiteCheck, GoRevo, Personalize, EZfaq, MyComponent and many more. His website is Bob’s Guides. It not only includes a plethora of MODX tutorials but there are some really great bread recipes there, as well.