A Smarter Menu for WordPress
With the release of wordpress 3.0 this function is no longer needed, I’d like to thank everyone showing interest in it:) I’ve always thought it would be nice to combine pages and categories all inside one menu, and recently I was looking for a nice way to add subtitles as well. So I thought it would be cool to write my own menu function to suit my own needs.
First off I want to give credit to a couple of posts on how to add subtitles via custom fields, sadly, each had their separate issue.
In the first post I found by Shantanu you would have to hack classes.php, a WordPress core file (not my cup of tea). The second one by Theme Shaper was lacking one very essential thing, dynamic active classes! (A non-dynamic menu is a non-happy menu).
The second post by Theme Shaper was almost doing what I was looking for so I decided to hack on it. The code was wrapped in a function which I could easily add to any of my themes, and it uses custom fields for the job, easy-peasy:)
I’ve spent a great deal of time figuring out how to do this and finally I came up with a solution that worked, next phase was to add categories and home link, ontop of that, I’ve added some more snacks, for instance you can chose if you want the home link and categories to show up, (with active classes of course) and you can sort the listing. Subtitles for home and categories are fetched from their respective description container. Enjoy!
New code as of 28.02.10 :) Put wp_smart_menu() where you want your menu to appear and paste the code below inside your theme’s functions.php file. If you feel it is missing functionality please add your comment below. Otherwise, enjoy!
// Smart Menu with Subtitles by Jon Kristian Nilsen - http://jonkristian.no
function wp_smart_menu() {
// Some basic settings
$showhome = "true"; // Show home link true/false.
$homedesc = get_bloginfo('description'); // Subtitle for the home url.
$showcat = "true"; // Show categories true/false.
$showpage = "true"; // Show pages true/false.
$subtitle = "subtitle"; // The meta key for your subtitle text on pages.
echo '<ul id="menu">';
// Display Home link
if ($showhome == "true") {
$homeurl = get_bloginfo('home');
echo '<li class="item home'.((is_front_page()) ? ' active' : '').'">';
echo '<span class="title"><a href="'.$homeurl.'" title="Home">Home</a></span>';
echo '<span class="subtitle"><p>'.$homedesc.'</p></span>';
echo '</li>';
}
// Build pages
if ($showpage == "true") {
$pages = get_pages();
global $post;
foreach ($pages as $page) {
$pageurl = get_permalink($page->ID);
$subtitle = get_post_meta($page->ID, 'subtitle', true);
echo '<li class="item '.$page->post_name.((is_page($page->ID)) ? ' active' : '').'">';
if ($page->post_parent != 0) {
echo '<ul class="sub"><li>';
echo '<span class="title"><a href="'.$pageurl.'" title="'.$page->post_title.'">'.$page->post_title.'</a></span>';
echo '<span class="subtitle"><p>'.$subtitle.'</p></span>';
echo '</li></ul>';
} else {
echo '<span class="title"><a href="'.$pageurl.'" title="'.$page->post_title.'">'.$page->post_title.'</a></span>';
echo '<span class="subtitle"><p>'.$subtitle.'</p></span>';
}
echo '</li>';
}
}
// Build categories.
if ($showcat == "true") {
$categories = get_categories();
global $wp_query;
foreach ($categories as $cat) {
$cat_url = get_category_link($cat->term_id);
echo '<li class="item '.$cat->slug.((is_category($cat->term_id) || is_single() && in_category($cat->term_id,$wp_query->post->ID)) ? ' active' : '').'">';
if ($cat->parent != 0) {
echo '<ul class="sub"><li>';
echo '<span class="title"><a href="'.$cat_url.'" title="'.$cat->cat_name.'">'.$cat->cat_name.'</a></span>';
echo '<span class="subtitle"><p>'.$cat->description.'</p></span>';
echo '</li></ul>';
} else {
echo '<span class="title"><a href="'.$cat_url.'" title="'.$cat->cat_name.'">'.$cat->cat_name.'</a></span>';
echo '<span class="subtitle"><p>'.$cat->description.'</p></span>';
}
echo '</li>';
}
}
echo '</ul>';
}
thanks for this, I’m sure it will come in handy at some point.
Just wondering if you had a live demo somewhere?
cheers
paul
Sure, I am using it on this site:)
Great menu idea… Looks sharp on this website. I’m looking forward to trying it on a future project.
Thanks!
Great work! I have worked on the same problem trying to implement jQuery’s Superfish menu with Wordpress. Your solution is much more complete. I will try it out.
This rewriting of the menu code causes you to loose some of the dynamic classes. This makes styling of different menu items difficult. I have a pretty simple plug-in that allows the use of wp_page_menu(). The plug-in is a rewrite of Page Lists Plus to strip out all of the extra code to make this plug-in as simple as possible. It is available on my site http://www.thetemplateblog.com/plug-ins/add-wordpress-menu-description#more-604 if you are interested.
Dave
TheTemplateBlog
Nice, a plugin would be beneficial for some, so kudos to that. I was not aware of any issues with my function, it would be nice to get some feedback instead of reports elsewhere that it isn’t working and why. I will post an updated version to take care of this.
Jon, Please accept my apology for the way this was brought to your attention. I have changed the wording in the post as I thought it was less then flattering of the hard work that you put into your solution.
Dave
Dave, No worries:) apology accepted, and thanks for bringing up the problem. I created this function with focus on the dynamic highlighting classes, so it’s important for me that they work:)
Thanks Jon, I also notice another bug when you set the ‘$show_home’ menu to ‘true’. When I enabled that I got a home menu between each of my other menus.
Dave
I would be happy to test your revisions if you like.
I see, I will take a look at this next week, kinda piled up in work at the moment.
Hi Jon, not totally sure if this is intended or not (guessing not), but it seems that if I set both $show_home and $home_first to true, the Home menu item shows up before each other menu item. This would be a result of it being included in the foreach() loop.
If I may make one suggestion, it would be to store all the output in a string variable and then output that string at the end. This way, you could tack the home link onto the front or back of that string based on the developer’s preference. I’ve updated my version of the code to reflect this and am glad to share if you’re interested…I know life can be busy :)
All the same, thanks for doing development on this! Almost exactly what I needed for a current project.
Thanks for the tip, that sounds good. I was going to revisit the code at some stage, hopefully I will get some time to do this soon:) Life can be really busy ;)
Very cool, I’ve been looking for this for a long time. However what I miss about this is the option to have a custom CSS class for every single page item. I’m working on a navigation where the menu text will be replaced with images, therefore every of my menu items need it’s own CSS class.
This is quite easy to achieve, you just need to fetch the page name and output it, I can include this in the next update. And by the way, I am sorry for not updating my function yet, but I’ve been quite tied up, keep your eyes open for a new one very soon.
Custom css class for every element is added now.
Hi Jon. Cool function. I was just wondering, is it normal for the child pages to be hidden? Or am I doing something wrong?
I’d like to take care of the children with some jQuery so that I can make a dropdown.
Child pages and categories should work fine now. However you will only get one level deep.
Hi, came across this site via a google search. This function is almost exactly what I’ve been looking for; my php skills are minimal, so your script has helped immensely. Looking forward to any updates you have to offer in the future.
On a related matter, would you be able to tell me if it’s possible to query more than one custom meta key? I’ve tried playing with the code, but, as I’ve mentioned, I’m not too hot on php and am not sure if I’m incorrectly querying the db or if it’s just not possible with Wordpress. In any case, thanks for posting such a useful bit of code!
Hi Jon. Don’t mean to annoy you but could you answer this. In your own usage of your code, did your child pages get nested properly as you’d expect them to? That’s all I need to know because if it did it’s most likely the code doesn’t work with wp2.9. I’m not criticising or anything so please don’t think that. You have contributed a great deal by posting this code and I appreciate it. (I just wish I had the talent to get it working for me!)
Hi everyone, thanks for all the feedback! I promise I will look into the code during this week/weekend. So stay tuned for an updated version…
I’ve updated the code now:) It should work fine on 2.9, please report back if not:)
Hi Jon. It works with the parent pages. The children pages are still not showing up in the markup :(
Hi there, is it relevant to have subtitles for sub-pages? I’ll take a swing at it now to see how we can do this:)
Hi Jon. That’s really decent of you :)
No I don’t need subtitles for the subpages.
I really appreciate this.
When I change front page display settings in admin the posts page does not return an active class. The static page chosen to replace the front page works fine. Any idea how to get the new posts page to work?
You are right, it’s because it’s not in the loop. Looks like i need to work some more on this code, change the structure a little. Thanks for pointing this out.
I’m still alive;) I’ve had some great work done on the new function, will release the code as soon as I’ve done enough testing.
How do you sort the list items? I want it sorted by menu order, but it’s sorting it in descending order by default.
I figured it out. Add “sort_column=menu_order&title_li=” inside the get_pages();
Cool, I got a new version coming soon with some changes and more options, will add sorting. I am considering writing it as a plug-in if enough people still wants/uses it:)
It would be great to add an option to add a separator between menu items. This could be a ” | ” by default, but could also be an image.
Yeah I can look into that, however you could try border-right and the :last-child selector to remove it at the end.
Hi Kristian,
Thanks for the code. I tried out the new version and although it shows the child pages it nests them in an unusual way.
Lets say I have one parent page and two child pages; this is what is outputted.
Parent</a>
Sub1
Sub2
As you can see it doesn’t nest them inside the parent li and also it creates two separate ul.
What do you think?
My formatting was deleted. Do i use code tags?
OK I got it to work :)
I took a different approach. It now spits out the pages, subtitles and the child pages nested in the correct, semantic manner.
I’d paste it in here but the tag doesn’t seem to be working. Will I email it to you instead?
Hi Kristian, thanks for sharing you work!
but where should I put your code in the Thematic theme?
I think it would be in functions.php would be missing something? (sorry for my bad english)