Based on a response to a similar question in http://drupal.org/node/43956, I created a block which displays a link to login if the user is not logged in or log out if the user is logged in. What I'd like is to put that in my Primary Links menu, though. I see a ton of posts asking essentially the same question, but not a lot of responses (http://drupal.org/search/node/dynamic+primary+link). What's the best way to do this?

global $user;
if ($user->uid != 0) {
  // code for the logout button
  echo "<a href=\"/drupal/logout\">Log out</a>";
}
else {
  // code for the login button
  echo "<a href=\"?q=user\">Login</a>";
}

Comments

mattyoung’s picture

I think this can probably be done with custom theme page preprocess hood:

In the theme's template.php:

<?php
function THEME_preprocess_page(&$vars) {
    global $user;
    if ($user->uid != 0) {
      // code for the account and logout button
      $vars['primary_links'][] = "<a href=\"/?q=user\">Account</a>";
      $vars['primary_links'][] = "<a href=\"/drupal/logout\">Logout</a>";
    }
    else {
      // code for the login button
      $vars['primary_links'][] =  "<a href=\"?q=user\">Login</a>";
    }
}
?>

I don't know if the PHP code is kosher as I haven't try it yet.

Let me know if this work if you try it.

barrett’s picture

Seems feasible, but it's not working for me. I'm using garland, so in drupal/themes/garland/template.php I put the code as you have it, replacing THEME with garland in the function name (ie. function garland_preprocess_page(...)). No errors, but no change in the primary links content either.

If I should have put it somewhere else, please let me know.

mattyoung’s picture

Yeah, doesn't work for me either. I have posted a question in the theme forum and let's hope someone can help.

Do you know how to see if the hood is called and what the value of $var['primary_links'] before and after? I'm completely PHP illiterate :(.

barrett’s picture

I use php's error_log function, as you can see below. You'll have to see where your error_log is set to write. Either way, in mine the function is not being called.

function THEME_preprocess_page(&$vars) {
error_log("preporcess_page hook called");
error_log(print_r($vars['primary_links'],TRUE));
    global $user;
    if ($user->uid != 0) {
      // code for the account and logout button
      $vars['primary_links'][] = "<a href=\"/?q=user\">Account</a>";
      $vars['primary_links'][] = "<a href=\"/drupal/logout\">Logout</a>";
    }
    else {
      // code for the login button
      $vars['primary_links'][] =  "<a href=\"?q=user\">Login</a>";
    }
error_log(print_r($vars['primary_links'],TRUE));
}
mattyoung’s picture

It's not being called because the new template.php need to be "registered"? I thought visiting the theme page does this and I did.

But now somehow the template.php is causing my site to go black at the point where the primary_links should render. So all I see on the page is header, logo, site name, then bam! no more right where the primary_links should be. Then if I remove the template.php file, site goes back to normal.

Please double check my code see what might cause this.

>You'll have to see where your error_log is set to write

Where to find this info? Is this the apache log? php.ini?

Thanks!

barrett’s picture

That sounds like a php error. The same code worked (or didn't, but didn't cause an error) on my site. Try viewing the source of the page when it blacks out like that, sometimes you can see error reporting there.

For where your error_log is located, you can check the error_log setting in your php.ini, echo ini_get('error_log'), or check the output of the phpinfo() function. It's commonly routed to ~/logs/error_log (on a shared host) but it's also not uncommon for it to not be set.

mattyoung’s picture

The reason the hook is not called is the "Enable" checkbox in the theme page is *not* checked. I would think having it as "default" should also mean enable but seem not the case. Anyway, once I have it checked, the hook begin to work.

Here is the template.php hook code:

function phptemplate_preprocess_page(&$vars) {
    global $user;

error_log(">>>>>> phptemplate_preprocess_page() hook called");
error_log(print_r($var['primary_links'], TRUE));

    if ($user->uid != 0) {
      // code for the account and logout links
      $vars['primary_links']['account-link'] = Array (
          'attributes' => Array('title' => 'Account link'),
          'href' => '?q=user',
          'title' => t('Account')
      );
      $vars['primary_links']['logout-link'] = Array (
          'attributes' => Array('title' => 'Logout link'),
          'href' => 'logout',
          'title' => t('Logout')
      );
    }
    else {
      // code for the login links
      $vars['primary_links']['login-link'] = Array (
          'attributes' => Array('title' => 'Login link'),
          'href' => '?q=user',
          'title' => t('Login')
      );
    }

error_log("    >>>>>> AFTER phptemplate_preprocess_page() hook");
error_log(print_r($var['primary_links'], TRUE));

}

But there is a small problem: the Account and Login link doesn't work. It's href='?q=user' but the source is this:

<a href="/%3Fq%3Duser" title="Login link" class="active">Login</a>

and this lead to page not found. I have clean URL so I just use href='user' to get by for now.

I note that change to template.php doesn't take effect immediately. I thought visiting the theme admin page would make it so but doesn't seem to. I had to do "Save Configuration" to make it.

Another thing I notice is on the "Page not found" page, the regular primary_links items are not shown. Kind of odd and it's not good, my user have no way to get back to other pages.

barrett’s picture

Sweet, Matt. Thanks for running that down.

To make this work in Drupal 5, there's another step you have to take since the preprocess hook didn't come along until drupal 6: http://www.garfieldtech.com/blog/preprocess-drupal-5

Have you noticed though that it still displays the 'Edit Primary Links' link when you're logged in?

gpk’s picture

I always find that if I select the Default radio for a theme then the Enabled checkbox automatically gets checked.

Note also that although preprocess hooks are not part of the Drupal core theme system in D5, the Zen theme does include a backport of this functionality.

gpk
----
www.alexoria.co.uk

sethstacey’s picture

I just used this code, and it worked great.

As I do not use Drupal often, however, I wanted to post one thing that may get some people lost:

In the template.php file, the code posted above gets placed inside the function already present in the file.

You can use a find (CRT+F for most apps) and paste in "function phptemplate_preprocess_page(&$vars)"

Then place that code above (minues the first and last lines of code, which relate to creating the function--it is already created in the template.php file), and leave everything else alone.

Hope this helps!
Seth

netron’s picture

this works great for primary links tabs , but it doesnt if you render your primary links in a primary links block.

i guess i need to return something to blocks from the _preprocess_page function maybe.

investigating this on. am on D6

alienzed’s picture

Ever figure that out, I am preprocessing my primary links beautifully but my primary links block remains unchanged...

alienzed’s picture

Ok so I found a dirty but working solution. In all places, use the following function in the settings.php file in sites/default

the function custom_url_rewrite_outbound() will go through every single path link in the menu_link table (i think)
allowing you to change them on the fly. The context seems pretty full too, I could get the current url and print to the page for debugging...

http://api.drupal.org/api/function/custom_url_rewrite_outbound

I can't believe there's no easier simpler method to do this though... I say that in hopes that someone will tell me what that easier method is!

scooper’s picture

I don't understand the issue. If I create 2 primary links: "Login" with path /user/login and "Logout" with path /logout, Drupal is smart enough to only display the Login link for someone not logged in, and only display the Logout link after logged in.

wthielke’s picture

I had to set the link to "user/login" for the login link. Also, if you don't want the login block to automatically appear on your front page, go to admin/build/block/list and change the settings for the user login block. For example, you could hide it completely or set it to display on another page (e.g. 'login') that most users won't see. If it's not displayed, the 'login' menu item will create the login form in the primary panel.

Sam Straub’s picture

The simplest way to do this is to just create the two primary links. One with path logout and the other with path user/login. Drupal will show/hide as appropriate.

The preprocess stuff can be helpful in certain cases like with the My Account piece, but for the simple use case, Scooper has a great solution.

onetwo’s picture

Just appending new links got me a messed up order - If you have the same problem; just prepend them like here below.

function phptemplate_preprocess_page(&$vars) {
    global $user;

	error_log(">>>>>> phptemplate_preprocess_page() hook called");
	error_log(print_r($var['primary_links'], TRUE));
	
	if ($user->uid != 0) {
      	// code for the account and logout links
		$addition['account-link'] = array('attributes' => array('title' => 'Account link'), 'href' => 'user', 'title' => 'Account');
		$addition['logout-link'] = array('attributes' => array('title' => 'Logout link'), 'href' => 'logout', 'title' => 'Logout');
    } else {
		$addition['register-link'] = array('attributes' => array('title' => 'Register link'), 'href' => 'user/register', 'title' => 'Register');
    }
	
	$vars['primary_links'] = array_merge_recursive($addition,$vars['primary_links']);
	
	error_log("    >>>>>> AFTER phptemplate_preprocess_page() hook");
	error_log(print_r($var['primary_links'], TRUE));
}

Thanks for the fix... my 2 cents:

gpk’s picture

Or, if you don't need the My Account and Logout links to be in the Nav menu you could move them to the primary links. For the login menu you could use http://drupal.org/project/loginmenu.

http://drupal.org/project/menu_per_role may also be useful tho' the project looks pretty inactive at the moment.

gpk
----
www.alexoria.co.uk

barrett’s picture

Doesn't the loginmenu project just add a login link to the menu? I've done that, what I can't work out how to do is have the same link be either login or logout as appropriate.

gpk’s picture

Yes, but if I read the project page correctly the login link will only show if you are not logged in.

Rather than having one link that changes from login to logout this is more easily achieved by having 2 menu items (login, logout) but only one visible at a time.

gpk
----
www.alexoria.co.uk

aharown07’s picture

From the loginmenu project page..

Notes for Drupal 6
This module is not needed in Drupal 6. To get the same functionality, go to '/admin/build/menu-customize/navigation' and click "Add Item". Use the following:
Path: user/login
Menu link title: Log in
Parent item:
Weight: 10
----
So what I did was create a path=user/login menu item and a path=logout menu item. The way this behaves is that "logout" item only appears when user is logged in. And "login" item only appears when user is logged out. In appearance it acts like a toggle.

Cablestein’s picture

Just as aharown07 said, make 2 menu items and they magically appear like you want.

So you will have 2 menu items:
Logout (path "logout")
and
Login (path "user/login")

And automatically, only one of them will be shown, depending on your login state!

If you are logged in, the "Login" menu item will not show. If you are logged out, the "Logout" menu item will not show.

I installed no modules for this.

afdiaz’s picture

The option:
Add Menu > Path (user/login) / Weight:10
Add Menu > Path (logout) / Weight:10

works fine for D7 on some themes automatically on the primary links.

Thanks...

hebhansen’s picture

I figured out a workaround that may be satisfactory to some.
Note! this will not give you log out as primary link...

I am setting up my site and wanted to get rid of the menu block in Drupal when log'ed in. As a user this is where I logout, but as admin there is an alternative:

I have the admin menu Module installed to make navigation on a remoteserver so much easier as admin. That menu has a logout-function when log'ed in.

What I did is to grant users access to the admin menu. When log'ed in they have the narrow bar at top of the site.

Note:
1) in User Management > Permissions > admin_menu module
access administration menu
- Give access to Authenticated Users (NOT Anonymous!)
display drupal links
- No access to anyone, unless relevant to users of your site

2) advanced_help module (if installed)
No access to anyone

Check the menu log'ed in as a user and add/remove permissions to your modules accordingly

When Anonymous, the standard login-form is displayed and no admin menu is available
When User, the admin menu is displayed at the top. For me the only link is Log Out Henrik (or Peter or Katrina)
When Admin, Full access to all administration and also a logout

You can probably fine-tune admin access to different roles. haven't come that far yet....

Not a solution as described - but a solution (maybe at least temporarily while in testmode)

mattyoung’s picture

aravind90’s picture

Why all this? Just install Menu per Role module..

mattyoung’s picture

My module serve a very specific purpose and need no configuration. the way it's implemented is very efficient. It doesn't add any hook and nothing is executed on page load. It also makes the login link return to the original page. This is not possible with the built menu.

Judging by the usage stats, many people find it useful.

alpapan’s picture

scooper is right (for drup 6 at least)

If I create 2 primary links: "Login" with path /user/login and "Logout" with path /logout, Drupal is smart enough to only display the Login link for someone not logged in, and only display the Logout link after logged in.

screeno’s picture

After fooling around with various scripts to toggle the login/logout primary links, I was relieved to find this thread describing Drupl 6's ability to display the correct link depending on whether the user is already logged in or not. I was delighted to see that Drupal also toggles a register link. Try it. Create a primary link with the path user/register. If you are not logged in the register link shows, when you log in the register link is hidden. Not code hacking, just default Drupal goodness!

Stephan_M’s picture

(In Drupal 6) Also, if you like to get a minimal "login/logout" switch in the header or someplace else:

In /admin/build/menu add a new menu, call it "Login Menu". Give this menu two menuitems:
+item1: title "log in"; path "user/login"
+item2: title "log out"; path "logout"

Then go to the blocks administration /admin/build/block and move the block that drupal just created from the new "Login Menu" and put it where you like. Then style.

texas-bronius’s picture

This probably worked back in 4.6, but it definitely works in Drupal 6. Add a menu item whose path is "logout" and another one for "user/login" (go ahead, try it now!), and Drupal will only show the appropriate one based on whether your authenticated. Easy, quick, no modules.. everyone should do it.

--
http://drupaltees.com
80s themed Drupal T-Shirts

ratinakage’s picture

The above worked perfectly...

No need for theme hacks or modules. Thanks...

Chim’s picture

Need to add menu items as described here
http://drupal.org/node/264225#comment-863102

goodbyegalaxy’s picture

Thanks, this worked. Very slick D6 feature.

diego.pasc’s picture

It works great.
And it's so simple:
No need to hack or other modules.
Thanks...

Endlessline’s picture

Works in D7, just use user/logout

joelbox-mondial-it’s picture

Use float and div with some css to fit it into the primary menu spot:

global $user;
if($user->uid){
  print '<div class="loginlogout"><a href="/logout">LOGOUT</a></div>';
}
else{
  print '<div class="loginlogout"><a href="/user">LOGIN</a></div>';
}

in a block and place the block in the menu region. Then this css to plug it into the right place of the menu.

.loginlogout {
  float:left;
  width:100px;
}

the float left fits it nicely onto the existing primary links. (The "width" to have both login and logout occupy the same space.)

taiger’s picture

I just moved them from the tabs on the user page to my main-menu.

In a custom site-specific module add:

<?php
/**
  * Implements hook_menu_alter
  */
function mymodule_menu_alter(&$items) {

  $items['user/login']['title'] = 'Login';
  $items['user/login']['type'] = MENU_NORMAL_ITEM;
  $items['user/login']['menu_name'] = 'main-menu';

  $items['user/register']['title'] = 'Register';
  $items['user/register']['type'] = MENU_NORMAL_ITEM;
  $items['user/register']['menu_name'] = 'main-menu';
  
  $items['user/logout']['title'] = 'Logout';
  $items['user/logout']['type'] = MENU_NORMAL_ITEM;
  $items['user/logout']['menu_name'] = 'main-menu';
  
}
?>

So, no tabs on login pages now. I manually created these links as regular menu items as children of the login link.

None of these links will appear if you are logged in because the access callback as defined in the core user module. For example: the user/login path has the access callback of 'user_is_anonymous'.

http://api.drupal.org/api/drupal/modules--system--system.api.php/functio...
http://api.drupal.org/api/drupal/modules--system--system.api.php/functio...

drupik’s picture

Thank's for share, it's works, but how can I add ?destination to the login/register links?

Cablestein’s picture

Using the simple trick posted earlier in this thread...

For Drupal 7, "/logout" is invalid.

The links to use are:
user/login
user/logout

anthony0perez’s picture

It should be built in.

This is used for primary links path:
user/login
user/logout

allio_froggio’s picture

This not only works, it makes me look totally smart. Thanks for the tip! :)

Anonymous’s picture

I found the administration menu module works best.

unsettlingtrend’s picture

Since user/logout is only accessible to those logged in, and likewise for unauthenticated users and user/login, I find this to be the most eloquent solution.

ChrisValentine’s picture

Still can't work out how to do this in Drupal 7. I'm using a Zen theme and I want to add four extra links to the main menu when the user is logged in. Can anyone help?

Web application developer
http://kmi.open.ac.uk/

vm’s picture

what are the menu items linking to?

ChrisValentine’s picture

I wanted links to appear for 'My account', 'Amin' and 'Log out' - but also one to a Page called 'Create'. In the end I used the Menu Block module and simply created an extra menu for logged-in users, modifying the Theme files to have this new menu appear directly onto the end of the existing Main menu. Drupal automatically worked out that it should hide the 'Admin' link from non-admin users.

Web application developer
http://kmi.open.ac.uk/