Post Archive
› July 16, 2005
CSS context sensitive menus in WordPress
I really like using CSS to indicate "you are here" in a menu or navigation system. I'm building something using WordPress, and wanted to do this - the solution wasn't difficult, but wasn't obvious either - so I'll share it here.
First a little background
You can set this type of navigation to work automagically and save yourself a lot of work. For example, if you add id="about" to the body tag for all pages that exist within the about us section, you can use that hook to indicate in your menu that this is the about us section. Something like this:
#about #aboutnav { color:red; }
This says - when the item with id "aboutnav" exsits within the item with id "about".. then color "aboutnav" red. This works because the condition only exists on pages that you've id'ed as "about" pages through the body id.
Doing this in WordPress
One of the things I like about wordpress, is that I can put my underdeveloped PHP skills to work and make the system do unique things. I couldn't easily see a template tag that would allow me to add a id="something" to the body tag. There is a wp_title() function, but it's intended for use in page titles and as content (it has spaces in it, etc). So I was delighted to find that a little string manipulation is all that sits between wp_title() and this way of doing navigation that I like so much.
So to convert the wp_title() to something we can use as a body id, I folded the following snippet of PHP into my header template:
<?php
$tname = wp_title('', false); // get the title
$tname = ereg_replace(' ', '', $tname); // remove all whitespace
$tname = strtolower($tname); // make it lowercase
$tname = 'sec_'. $tname ; // add a prefix of sec_
?>
<body id="<?=$tname?>">
Now in WordPress, if I have a "Page" or category called "About Us", I can count on those pages having a body id of "sec_aboutus" in my CSS, and I can style the navigation appropriately.
Comments
1. July 16, 2005 10:47 AM
2. July 16, 2005 11:09 AM
Moises Kirsch Posted…
I was able to accomplish the same effect and a few extra ones using the custom tags plugin.
What I did was to setup a custom tag named class and then used the get custom fields plugin to echo the valuen in the html.
With something like this you could easily change the look for certain posts or pages.
3. July 16, 2005 11:50 AM
Nate Posted…
Oh what a neat idea Moises. Thanks for sharing that plugin link, this really opens up a lot of possibilities.
4. July 16, 2005 11:53 AM
5. July 16, 2005 01:06 PM
Perun Posted…
Hi, nice Idea. But im missing something in your post. You have found a way to insert wp_title into the body-tag but what ist with the ID in the Menu? Because you need 2 "points" (ex. #about #about_nav) to complete it.
6. July 16, 2005 01:36 PM
Nate Posted…
Oh good point Perun. I'm doing the menu statically with includes (using this plugin). In the menu, I'm using an unordered list, with each LI getting it's own ID. Example: #aboutnav
This is the second hook I use.. so the CSS ends up like:#abouus_sec #aboutnav a { color:red }
Hope this helps!
7. July 17, 2005 03:09 PM
Bart Posted…
Nice! Thx for sharing that. Now I only need to include that on my page :)
8. July 25, 2005 01:01 PM
Hunox Posted…
Why can't you just use post slug/category url as your page name? They are unqiue.
9. July 26, 2005 08:17 PM
mkraken Posted…
Very nice solution for using the title!
You can add id's to your page links dynamically. I did this by changing a few
lines of code, and making a couple configuration changes. It works by using
the page slugs.
It leaves declaring the new selectors in your .css as the only thing that must
be maintained.
First - you'll have to enable permalinks. By default, your urls look like "?id=xxxx". This won't work, so'll you'll have to go into options>permalinks, and in the Structure field, type /%postname%/. Then update the permalink structure. (caution: if you have custom .htaccess files this will over write what you had. But, if needed you probably add what ever you had back in afterwards)
Next, you'll need to edit some of the functions wp uses. I copied then tweaked 2 existing functions: wp_list_pages and _page_level_out. I renamed the copied versions wp_get_navbar and _nav_level_out. These are in template-functions-post.php, which can be found in the wp-includes folder.
In wp_get_navbar I changed/added:
if ( $r['title_li'] )
//changed li id to div id
echo '<div id="nav_bar">' . $r['title_li'] . '<ul>';
//added to include home page
echo '<li id="home_page"><a href="' . get_bloginfo('url')
. '" title="' . get_bloginfo(name) . '">Home</a></li>';
This is to add a link to the home page. You'll probably want one of these, since most good sites have a link back to home on every page.
Then, in _nav_level_out I added:
foreach($page_tree[$parent]['children'] as $page_id) {$cur_page = $page_tree[$page_id];
$title = $cur_page['title'];
//Mk Added
$slug = $cur_page['name'];
//end added
//$css_class = 'page_item';
if( $page_id == $queried_obj->ID) {
$css_class .= ' current_page_item';
}
//MK Added
echo $indent . '<li><a href="' . get_page_link($page_id) . '"
title="' . wp_specialchars($title) . '">' . $title . '</a>';
//end added
In the header template you'll need to tweak the <body> tag to:
<body id="<?php echo (is_page()) ? get_query_var('name') : ((is_home())
? "home" : ((is_single()) ? "single": ((is_category()) ?
single_cat_title() : ((is_archive()) ? "archive" : ""))));
?>">
this is something that i got from richardlee (http://wordpress.org/support/profile/16535)
on the wp bb (http://wordpress.org/support/topic/30273)
Finally, you'll want to edit your style sheet to include the selectors based on the body and li id's.
I think that's it. I haven't tested it with sub/child pages yet, but it's a start
Nate Posted…
I forgot to mention.. I added the prefix so that on the homepage of my WordPress site, there is at least a body id of "sec_". It's sort of a failsafe, and helps keep things organized anyway. If it's not obvious, the prefix can be changed in the PHP to whatever you'd like, but avoid starting with an underscore, id's aren't supposed to start with them if I remember correctly.