When making changes to a user’s status or capabilities, as we discussed in the previous article, sometimes you’d like the changes to take effect right away. Suppose, for example, that a user selects an option that adds them to a particular user group. It’s frustrating to find that the users have to log out, then log back in before MODX will treat them as members of the group.
Adding a user to a user group can have many ripple effects. It may qualify the user for one or more new permission ACL entries, which would mean more permissions for the user (potentially, both context and object permissions). It might give the user access to resources in protected resource groups,elements in protected categories, or new Media Sources. There may also be snippets that check the user’s status with
In this article, we’ll look ways to force MODX to update the user’s status immediately. Susan Sottwell played an important role in testing the code below.
You may have experienced problems with changes on your site not taking effect due to the cache. That’s not what we’re talking about here, though. Clearing the site cache often won’t help with updating a users’ status. That’s because much of the user’s information is held in the
$_SESSION array. You could fix things by unsetting the
$_SESSION array, but that would be a little like killing a mosquito with a sledge hammer. Deleting the
_$SESSION effectively logs the user out and forces them to log back in, which is what we’re trying to avoid.
The short answer is to refresh the user’s data with
$user->loadAttributes(), though in some cases it requires an extra step. Here’s our code from the previous article with some extra lines that will make the change take effect immediately.
$groupname = ‘Group1’;
/* New Code */
$userId = $modx->user->get(‘id’);
$context = ‘web’;
$principalTargets = $modx->getOption(‘principal_targets’, null, ‘modAccessContext,
$targets = explode(‘,’, $principalTargets);
$modx->user->loadAttributes($targets, $context, true);
How it Works
The code could be made more efficient, but this version is a little easier to understand. Lets look first at the
loadAttributes() call. It takes three arguments.
The first argument is an array of permission-related classes that should be refreshed for the user (
$principalTargets). Our code uses
$modx->getOption() to retrieve the
principal_targets System Setting. If it’s not set, we include a set of defaults that will take care of most situations:
sources.modAccessMediaSource. These four (which make up the default value of the
principal_targets System Setting) will cover refreshing the user’s access to the context, resource groups, categories, and Media Sources.
getOption() line runs, the targets will be a string containing a comma-separated list. We need it to be an array (that’s what
loadAttributes is expecting), so we convert it to one with
explode(), which also removes the commas. To finish off the first argument, we use
array_walk() to call the
trim() function on each member of the array. The
trim() function removes any leading or trailing spaces, newlines, or tabs.
It’s not actually necessary to check the System Setting with
getOption(). If you know which targets you need, you can speed things up slightly by just doing something like this:
$targets = array(‘modAccessResourceGroup’, ‘modAccessCategory’);
The second argument to
loadAttributes() is the context you want to be refreshed. This is usually ‘web’, but it could be another front-end context. This argument only takes a single context, but usually, you only need it to take effect in one context. If necessary, you could call
loadAttributes() multiple times, once for each context.
If you have a multi-context site and the code could run in more than one front-end context, you can reload the user attributes for the current context by changing the
$context = line to this:
$context = $modx->context->get(‘key’);
The third argument, if set to
true, tells MODX that you want things reloaded from scratch rather than from the cache.
Once we have the three arguments set up, we call
loadAttributes() with them to refresh the user's data.
What’s That Thing with the $_SESSION
There’s a minor bug in MODX (possibly fixed by the time you read this) that keeps the data from being completely refreshed. If you call
user->joinGroup(), for example, that method clears a user $_SESSION variable called
modx.user.##.userGroupNames (where ## is the user’s ID). At this writing, if you check the user’s group membership with
$user->getUserGroups() right after calling
joinGroup(), the user won’t be a member yet because
getUserGroups() checks this variable:
$_SESSION["modx.user.##.userGroups"], which isn’t cleared by
To handle this problem, we’ve added this line to the code to clear the other
I filed a pull request to fix this bug, so there’s a good chance that it will have been fixed by the time you read this, in which case that line is no longer necessary, though it won’t hurt anything to have it there.
Once we’ve cleared the user’s data with the code above, as soon as a method like
hasPermission() is called, the data will be reloaded fresh from the database and the user will have the access they deserve.