MODX Quick Tip: Login Snippet Logout Link

May 24, 2012

The Problem

Need to install a member's only area in your MODX Revo website? Never fear, the Login snippet makes it easy. Really quite easy. Just install via Package Management and follow the instructions here

Like everything MODX, it can be as simple or robust as you want, based on your needs. But one, simple function has eluded me in the past, and I just had to do it again, and it's sorely lacking in the documentation. That is:

"Show a Login link when a visitor is not logged in, but show a Logout link once they are logged in."

The usefulness of this seems obvious to me but the documentation doesn't make it obvious how to do it. I will fix that shortly...but in the meantime, here is one version (see update below for the other)

[[!*id:is=`10`:then=`
    [[!+modx.user.id:is=`0`:then=`
        <a class="login" href="[[~10]]" title="Login">Login</a>`:else=`
        <a class="logout" href="[[~10? &service=logout]]" title="Logout">Logout</a>
    `]]
`]]  

Break it down:

  • [[!*id:is - This is an optional output filter that only displays the login/logout link if a certain condition is met, like the ID of the page is that of the login page. Useful if you don't want the link to appear on the entire site, for example. You must call this uncached because the nested placeholder call must be uncached...
  • [[!+modx.user.id:is - This is the magic placeholder that is set on every page load. (In Evo, you'd accomplish the same thing with the snippets WebLogin and LoginState. In Revo, it's baked in.) If the user is not logged in, it will return "0". So we have an output filter that shows the login link if this is the case...
  • href="[[~10]]" - This tells MODX to output the link to the login page (in this example, Doc ID 10, but you'd replace it with the correct one for your case.)
  • :else - If the placeholder returns something other than "0", the user is logged in, and the logout link is displayed.
  • href="[[~10? &service=`logout`]] - You must add the service=logout url parameter to the logout link so that the link actually logs the user out, in addition to navigating to the page...

Easy, right? Just remember: the MODX user id placeholder must be uncached, and so must any other MODX tag in which it is nested. "0" (without the quotes) is the value returned if the user is not logged in. (Think user ID "0", meaning they don't have an ID.)

*UPDATE: If you want to check if the user has access to a specific context, the better way to do this would be to write your own snippet that returns some value based on a conditional, like this:

$ctx = $modx->getOption('context', $scriptProperties, $modx->context->get('key'));
$loggedInHtml = $modx->getOption('loggedInHtml', $scriptProperties, '');
$anonymousHtml = $modx->getOption('anonymousHtml', $scriptProperties, '');
if ($modx->user->hasSessionContext($ctx)) {
    return $loggedInHtml;
} else {
    return $anonymousHtml;
}

Break it down:

  1. Get the specified Context key, defaulting to the current Context.
  2. Check if the user is logged into the Context.
  3. Return the html string provided if logged in.
  4. Otherwise return the html string for anonymous users.

If the above snippet were called "userHasSession", you'd call it like this:

[[!userHasSession?
    &loggedInHtml=`<a class="logout" href="[[~10? &service=`logout`]]" title="Logout">Logout</a>`
    &anonymousHtml=`<a class="login" href="[[~10]]" title="Login">Login</a>`
]]

That's it! Have fun :)