Creating a Submenu in WordPress
For a project I’m currently working on I wanted to create a submenu that included the parent page as well as the supbages. I just wanted to display the submenu only if the parent page had subpages. Searching the WordPress Codex and googling for a solution I couldn’t quite find an example that took all these factors into consideration so I had to figure it out myself. Here’s the approach I came up with.
Checking if the page has subpages
I searched in vain for a method to determine if the current page has any subpages or not. I first assumed that there would be a has_subpages() method, but so far I haven’t found any. Lacking that, I came up with a very crude way of checking it. I explicitly had to try to fetch all the subpages with the function wp_list_pages() and then check if it returned anything. It’s not pretty but it works.
$children = wp_list_pages('&child_of='.$post->ID.'&echo=0');
if($children) {
// This page has subpages
}
Checking if it’s a parent page or a subpage
The next thing I had to figure out was how to check i the current page is a parent page or a subpage. That’s done with the following code.
if(is_page() && $post->post_parent) {
// This is a subpage
} else {
// This a parent page
}
Fetching the submenu
Now I needed a way to fetch the subpages. This is done with the wp_list_pages() function. The tricky part about this is that there’s no way to get both the parent page and the subpages in the same call. So therefor we have to call the function twice. The call also looks a little different depending on if we’re on the parent page or on the subpage.
if(is_page() && $post->post_parent) {
// This is a subpage
$children = wp_list_pages("title_li=&include=".$post->post_parent ."&echo=0");
$children .= wp_list_pages("title_li=&child_of=".$post->post_parent ."&echo=0");
} else if($has_subpages) {
// This is a parent page that have subpages
$children = wp_list_pages("title_li=&include=".$post->ID ."&echo=0");
$children .= wp_list_pages("title_li=&child_of=".$post->ID ."&echo=0");
}
There are other ways of doing this, but the benefit of this approach is that we automatically get class="current_page_item" on the list-item that represents the page that we’re currently on. That’s handy if you want to style that item in any particular way.
Outputting the HTML
The last step is to output the actual HTML. I’ve chosen to output it as an unordered list.
<?php // Check to see if we have anything to output ?>
<?php if ($children) { ?>
<ul class="submenu">
<?php echo $children; ?>
</ul>
<?php } ?>
Putting it all together
Now it’s time to put all the pieces together. Just put this code in your page template one of the pages in your template, like for example page.php or sidebar.php and you’re good to go. These pages are located in /wp-content/themes/your-theme/.
<?php
$has_subpages = false;
// Check to see if the current page has any subpages
$children = wp_list_pages('&child_of='.$post->ID.'&echo=0');
if($children) {
$has_subpages = true;
}
// Reseting $children
$children = "";
// Fetching the right thing depending on if we're on a subpage or on a parent page (that has subpages)
if(is_page() && $post->post_parent) {
// This is a subpage
$children = wp_list_pages("title_li=&include=".$post->post_parent ."&echo=0");
$children .= wp_list_pages("title_li=&child_of=".$post->post_parent ."&echo=0");
} else if($has_subpages) {
// This is a parent page that have subpages
$children = wp_list_pages("title_li=&include=".$post->ID ."&echo=0");
$children .= wp_list_pages("title_li=&child_of=".$post->ID ."&echo=0");
}
?>
<?php // Check to see if we have anything to output ?>
<?php if ($children) { ?>
<ul class="submenu">
<?php echo $children; ?>
</ul>
<?php } ?>
Conclusion
I think that WordPress is an absolutely awesome CMS/Blog engine, but it do lack some handy methods. Fortunately it’s almost always possible to create workarounds. I hope that you will find this useful in your own WordPress Template. Don’t hesitate to tell me if you have a smarter way of doing this.
You mention adding this to the template file, where in the template file do you add this? and by template file i presume you mean “template.php” in admin>includes?
Hi Matt,
No I mean one of the files that makes up a template, like for example page.php or sidebar.php in /wp-content/themes/your-theme/. Sorry for being unclear about that. I’ve updated the article accordingly.
Hey,
I think this is missing a <?php opening statement. And even when I add that it doesn’t appear to work.
Tim: Your’e absolutely right Tim! There was a missing php opening statement. On top of that there was also a missing php closing statement. I’m really sorry about that. I have now corrected the code in the example so please try it again.
There’s a plugin for this now
http://www.dontdream.it/category/wordpress-menubar
Dukessa: That’s sweet! If you’re not into building your own templates, that’s an excellent option. Thanks for the tip!
hey dude,
thx for the nice script! i’m wandering though! my navigation is split in 2, mainNav is in the header.php and i’m calling your nice code (my subNav) into my index.php like that:
the results are, when i click on a page in the mainNav that has subNav pages (lets say 3 for example) i’m seeing actually 4 pages (the mainNav page as a subNav page and my 3 subNav pages) and that’s fine, but.
my 1st question is how could i rename the the mainNav page name that is automaticly shown in the subNav?
and, my 2nd question (the most important) is how can i get the
mainNav li.current_page_itme {}to remain active when i’m clicking on another subNav pages (that is not pulled from the mainNav)?thanks so much
marc
oh,
sry for bothering! i just found the answer to the 2nd question. i needed to add the following code to my CSS.
.mainNav li.current_page_ancestor {}uuppps
Just thought to let you know that an alternative way to do this is to use the code from the sidebar of the K2 Theme. Just strip away all the other stuff and you are left with a very nice piece of code and it’s a simple thing to make the heading clickable also if you want.
Linda: Cool! I will definitely check that out. Thanks for the tip!
Very interesting post, I love finding a good quality blog thats not full of rubbish. I would love to do a link exchange.
Super script: Nice and well explained! Love that!
One small thing: you mention:
// Check to see if we have anything to output
And that particular text shows up in my WordPress project
Because it is outside a PHP tag…
Tanks for your blogpost!
marnix bras: Thanks for noticing! I’ve corrected the example.
Hi
Great post, pretty much exactly what I was looking for, thanks for that!
I am very new to both wordpress and php so I’m sorry if this is a stupid question but I’m stuck
The code that is output from this php looks something like his for each list item:
Sub Page1Is it possible to insert a span within the anchor somehow? so the php would output something like this?
Sub Page1Or would this make things complicated?
sorry about the links in that last comment
I basically want it to output something like this (ignore the extra spaces)
Sub Page1hope it works this time
Sorry for the flooding.. managed to insert a span in the anchors by using link_before and link_after like so
if(is_page() && $post->post_parent) {
// This is a subpage
$children = wp_list_pages("title_li=&include=".$post->post_parent ."&link_before=&link_after=&echo=0");
$children .= wp_list_pages("title_li=&child_of=".$post->post_parent ."&link_before=&link_after=&echo=0");
} else if($has_subpages) {
// This is a parent page that have subpages
$children = wp_list_pages("title_li=&include=".$post->ID ."&link_before=&link_after=&echo=0");
$children .= wp_list_pages("title_li=&child_of=".$post->ID ."&link_before=&link_after=&echo=0");
}
sorted!
Hi, Love the work you’ve done on this little submenu code, it was a piece of cake to add to my custom theme, however I’m just wondering how it would be possible to have the submenu output on a single horizontal line? (eg submenu1 | submenu2 | submenu3 | submenu4)
Tim
@Tim: Your best bet is to use CSS to style the unordered list so that it’s horizontal. A now old, but still excellent article on how to do this is CSS Design: Taming Lists at A List Apart. http://www.alistapart.com/articles/taminglists/
Hint: Try
.submenu li {display: inline}in your CSS.Can someone help me with this? I have lots of articles and I want to display them under different parents. Here is my question:
1. I want parent pages to be formatted differently than child page list
For example in the link here: http://www.theagitator.com/publications/
My parent page is called “Feature-Length Articles” [which is NOT a link and is formatted differently]
Now I want to show all the children pages as links [] list with publish date.
Thanks for all the help.
What about having a completely seperated and with the submenu only showing when a main page has subpages, set the submenu still shows when a subpage has been clicked.
That sounds much more difficult and is what I’m current working on.
WordPress scrubbed my custom divs so that post didn’t make sense. Here it is again:
“What about having a completely separated [div id="menu][/div] and [div id="submenu"][/div] with the submenu only showing when a main page has subpages, yet the submenu still shows when a subpage has been clicked.
That sounds much more difficult and is what I’m current working on.”
I love your script, is what a need, but all the sub-pages are showin in the search page, how can a fix this?
[...] Marc Wiest was kind to share wit us a solution to this problem, based on the above hack and work by Gabriel Svennerberg. Here is how to create a dynamic [...]
Just wanted to thank you for this, this works perfectly and was exactly what I was looking for.
Thanks again.
thanks, great post, works great!
Thanks! This saved me heaps of time and worked straight out of the box. You’re a champion
Thank you. Worked for me first time.
Thanks for the hack! Worked perfectly.
Thanks, you helped me allot!
Like many others, you’re help saved the day and I really appreciate you taking the time to share the knowledge!
Cheers!
I really like your writing style, its not generic and extremly long and tedious like a lot of blog posts I read, you get to the point and I really enjoy reading your articles! Oh, and merry Christmas!
good thank you
ID.’&echo=0′);
if ($children) { ?>
I found this shorter, simpler version you might like.
This has worked perfectly for me, thanks! It is exactly what I have been searching for all day – after trying a lot of other suggestions thatall failed! Wish I had found this first! lol
Thanks so much for this Gabriel. I’ve used a few different PHP snippets for secondary menus on various WordPress sites, but none of them were able to highlight the parent menu item when that page was active. But yours fixes that. Really appreciate it.
Hi!
I a newbie at PHP and wordpress. I used you script and it works great!
Now I have a problem though. How do I add a menulevel 3? So topmenu -> submenu ->subsubmenu
It works displaying the subsubmenu but clicking the subsubmenu the other pages in the menu dissaper.
Also i cannot figureout where i edit the for the subsubmenu.
Anyway helt would be deeply appriciated.
Thanks!
EDIT: Also i cannot figureout where i edit the UL for the subsubmenu.
Hello Gabriel Svennerberg, I am new in wordpress and I’m confused for using this now..
maybe this is weird question, but want to ask, where I can put the code that you have written it? thx for the answer.
[...] Q2: How do you create a dynamic submenu? Marc Wiest was kind to share wit us a solution to this problem, based on the above hack and work by Gabriel Svennerberg. [...]