Snippet: WordPress 3.0 Menus - Add a login / logout link

The new WordPress 3.0 menu system is pretty powerful and provides some very interesting new options for creating menus in WordPress. Previously, I have always used wp_list_pages and a custom Walker class to provide hierarchical menus based on the page structure, but that's a topic for another post. This super-short snippet shows you how to add a login / logout link to one of your WordPress menus.

WordPress contains some special functions for creating login and logout links: wp_login_url and wp_logout_url. They both take a string argument which is the URL you want them to redirect to after performing the login/logout action. In the example below I am adding the login / logout link to the beginning of the menu and redirecting to the home page (index.php) in both cases.

// functions.php
function add_login_logout_link($items, $args)
{
  if(is_user_logged_in())
  {
    $newitems = '<li><a title="Logout" href="'. wp_logout_url('index.php') .'">Logout</a></li>';
    $newitems .= $items;
  }
  else
  {
    $newitems = '<li><a title="Login" href="'. wp_login_url('index.php') .'">Login</a></li>';
    $newitems .= $items;
  }
  return $newitems;
}
add_filter('wp_nav_menu_items', 'add_login_logout_link', 10, 2);

If the current user is logged in, they will see a logout link and vice versa. To use this snippet, copy and paste the code into your theme's functions.php file. You can easily change it to redirect to the dashboard after login, or have the login / logout link at the end of the menu like this:

// functions.php
function add_login_logout_link($items, $args)
{
  if(is_user_logged_in())
  {
    $newitems = $items;
    $newitems .= '<li><a title="Logout" href="'. wp_logout_url('index.php') .'">Logout</a></li>';
  }
  else
  {
    $newitems = $items;
    $newitems .= '<li><a title="Login" href="'. wp_login_url('wp-admin/index.php') .'">Login</a></li>';
  }

  return $newitems;
}
add_filter('wp_nav_menu_items', 'add_login_logout_link', 10, 2);

You can also place the login / logout link elsewhere in the menu structure. However, you need to split the menu items apart, locate the right position, insert your menu item and then stick the menu items back together again to return. An example of putting the link second is shown below:

// functions.php
function add_login_logout_link($items, $args)
{
  $newposition = 2;
  
  // split the menu items into an array using the ending <li> tag
  $items = explode('</li>',$items);

  // setup our new link (without the end li tag)
  if(is_user_logged_in())
  {
    $newlink = '<li>' . $args->before . '<a title="Logout" href="'. wp_logout_url('index.php') .'">' . $args->link_before . 'Logout' . $args->link_after . '</a>' . $args->after; // no </li> needed this is added later
  }
  else
  {
  $newlink = '<li>' . $args->before . '<a title="Login" href="'. wp_login_url('index.php') .'">' . $args->link_before . 'Login' . $args->link_after . '</a>' . $args->after; // no </li> needed this is added later
  }

  $newitems = array();

  // loop through the menu items, and add the new link at the right position
  foreach($items as $index => $item)
  {
    // array indexes are always one less than the position (1st item is index 0)
    if($index == $newposition-1)
    {
      $newitems[] = $newlink;
    }
    $newitems[] = $item;
  }

  // finally put all the menu items back together into a string using the ending <li> tag and return
  $newitems = implode('</li>',$newitems);

  return $newitems;
}
add_filter('wp_nav_menu_items', 'add_login_logout_link', 10, 2);

Note that in the above example, I have also used the before, after, before_link and after_link args values so that the additional link has the same display properties as the generated ones. Also the add_filter function takes 4 arguments: the "hook" or point in the code where this code should be executed, the function to be carried out, the priority (1 is executed first, 12 is executed last) and the number of arguments the function accepts. Using priority 10 means the code is executed near last.

A Note on Snippets: When customising a CMS such as Wordpress it is often the simplest pieces of code which are the hardest to either find or remember. These snippets are placed here for my own reference and will hopefully be useful to others. If you find them useful or have any suggestions, please let me know.