Menu locations


WordPress 3 comes with integrated menu management. Although still a bit quirky at times, it makes creating and managing (navigation) menus a breeze. However, now that creating and displaying a menu takes nothing more than one line of code (wp_nav_menu), we appear to have lost the ability to “manually” add our own stuff.

For instance, by design, there is no “home” link on any menu. Though it is easy to create a custom menu item in the menu management, there is an easier way, using WordPress filters.

The navigation menu can be “filtered”, and so can the navigation menu items. This allows us to add menu items at will.

Inspired by a support request, I did a bit of digging, the result are the following three code snippets, that you can add to your themes functions.php file and will add a login/logout link, add a search field or a Home Page link to your WordPress 3 navigation menu.



Add a login/logout link to your navigation menu

add_filter('wp_nav_menu_items', 'add_login_logout_link', 10, 2);
function add_login_logout_link($items, $args) {

		ob_start();
		wp_loginout('index.php');
		$loginoutlink = ob_get_contents();
		ob_end_clean();

		$items .= '<li>'. $loginoutlink .'</li>';

	return $items;
}

Explanation:

First we add a function add_login_logout_link to the wp_nav_menu_items filter. Then, the ob_start, ob_get_contents and ob_end_clean (lines 4, 6 and 7) functions are “output Buffering” PHP functions that will “intercept” the information that would otherwise be sent to the browser. wp_loginout('index.php'); will add the logic and html code to login (if not logged in yet), or logout (if logged in). Since we don’t want to send that code to the browser yet, we “capture” the output (using ob_get_contents) in a variable ($searchform), and finally include that variable as a list item in the menu.

Add a search field to your navigation menu

add_filter('wp_nav_menu_items','add_search_box', 10, 2);
function add_search_box($items, $args) {

		ob_start();
		get_search_form();
		$searchform = ob_get_contents();
		ob_end_clean();

		$items .= '<li>' . $searchform . '</li>';

	return $items;
}

Create your own searchform template

The add_search_box function will include the default searchform in the menu bar. This however may not be the desired layout (perhaps it contains preceding text “search:” and a “search” button), so you should create a template file searchform.php in your theme template directory, and add the following code:

<form method="get" class="search-form" id="search-form" action="<?php bloginfo( 'home' ); ?>/">

	<div class="formfield">
		<input class="formInputText" type="text" name="s" id="search-text" value="Search ..." size="12" maxlength="16" tabindex="1" onfocus="if (this.value == 'Search ...') {this.value = '';}" onblur="if (this.value == '') {this.value = 'Search ...';}" />
	</div>
	
</form>

Optionally, you can add styling to your form to match your navigation style, using (for example!):

input.formInputText {
	margin-top: 7px;
	color: #666;
	padding: 3px;
	background: #ccc;
}

input.formInputText:hover {
    cursor: help;
    color: 555;
    background: #ccc;
}

Add a Home Page link to your navigation menu

add_filter( 'wp_nav_menu_items', 'add_home_link', 10, 2 );
function add_home_link($items, $args) {

		if (is_front_page())
			$class = 'class="current_page_item"';
		else
			$class = '';

		$homeMenuItem =
				'<li ' . $class . '>' .
				$args->before .
				'<a href="' . home_url( '/' ) . '" title="Home">' .
				$args->link_before . 'Home' . $args->link_after .
				'</a>' .
				$args->after .
				'</li>';

		$items = $homeMenuItem . $items;

	return $items;
}

props to Division by Zero

Add these to a specific menu only

The filter will run for each menu you have defined, so the samples above will be added to each one of those. This may not always be what you want, so to add the desired code to a specific menu location only, add a condition to the code, to make sure the code only executes for a specific menu location:

function add_login_logout_link($items, $args) {

	if($args->theme_location == 'Primary') {

		ob_start();
		wp_loginout('index.php');
		$loginoutlink = ob_get_contents();
		ob_end_clean();

		$items .= '<li>'. $loginoutlink .'</li>';

	}

	return $items;

}