For
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.
March 27, 2009 at 10:33 am
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?
March 27, 2009 at 6:40 pm
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.
April 3, 2009 at 9:56 pm
Hey,
I think this is missing a <?php opening statement. And even when I add that it doesn’t appear to work.
April 3, 2009 at 10:35 pm
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.
April 8, 2009 at 3:40 pm
There’s a plugin for this now 🙂 http://www.dontdream.it/category/wordpress-menubar
April 8, 2009 at 9:19 pm
Dukessa: That’s sweet! If you’re not into building your own templates, that’s an excellent option. Thanks for the tip!
April 18, 2009 at 11:52 am
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
April 18, 2009 at 12:31 pm
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 🙂
May 24, 2009 at 3:20 pm
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.
May 24, 2009 at 10:09 pm
Linda: Cool! I will definitely check that out. Thanks for the tip!
May 27, 2009 at 7:31 pm
Very interesting post, I love finding a good quality blog thats not full of rubbish. I would love to do a link exchange.
June 19, 2009 at 12:49 pm
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!
June 20, 2009 at 9:12 pm
marnix bras: Thanks for noticing! I’ve corrected the example.
June 30, 2009 at 1:12 pm
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 Page1
Is it possible to insert a span within the anchor somehow? so the php would output something like this?
Sub Page1
Or would this make things complicated?
June 30, 2009 at 2:31 pm
sorry about the links in that last comment
I basically want it to output something like this (ignore the extra spaces)
Sub Page1
hope it works this time
June 30, 2009 at 4:19 pm
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!
July 21, 2009 at 2:39 am
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
July 21, 2009 at 11:45 am
@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.August 6, 2009 at 6:03 pm
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.
August 14, 2009 at 3:46 pm
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.
August 14, 2009 at 3:48 pm
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.”
September 14, 2009 at 11:50 pm
I love your script, is what a need, but all the sub-pages are showin in the search page, how can a fix this?
October 24, 2009 at 7:03 am
Just wanted to thank you for this, this works perfectly and was exactly what I was looking for.
Thanks again.
October 29, 2009 at 6:37 pm
thanks, great post, works great!
November 23, 2009 at 2:35 am
Thanks! This saved me heaps of time and worked straight out of the box. You’re a champion 🙂
January 15, 2010 at 11:01 am
Thank you. Worked for me first time.
February 4, 2010 at 11:32 pm
Thanks for the hack! Worked perfectly.
February 9, 2010 at 12:27 pm
Thanks, you helped me allot!
March 11, 2010 at 12:17 am
Like many others, you’re help saved the day and I really appreciate you taking the time to share the knowledge!
Cheers!
April 23, 2010 at 5:33 am
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!
April 26, 2010 at 6:36 am
good thank you
May 13, 2010 at 2:01 pm
ID.’&echo=0′);
if ($children) { ?>
I found this shorter, simpler version you might like.
May 18, 2010 at 1:27 pm
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
June 7, 2010 at 8:41 pm
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.
June 13, 2010 at 11:07 pm
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!
June 13, 2010 at 11:08 pm
EDIT: Also i cannot figureout where i edit the UL for the subsubmenu.
June 18, 2010 at 9:33 am
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.
October 22, 2010 at 8:29 am
how to write main menu to submenus and sub-sub menus
November 5, 2010 at 9:26 am
thanks for the code, it’s EXACTLY what I needed!
November 10, 2010 at 9:12 am
Great post. Over a year old and still useful. Thank you!.
November 17, 2010 at 1:56 pm
NAme
January 29, 2011 at 2:22 am
Hey There. I found your blog using msn. This is a really well written article. I?ll make sure to bookmark it and come back to read more of your useful information. Thanks for the post. I will definitely return.
February 4, 2011 at 3:57 pm
Thanks, It really worked…
March 4, 2011 at 9:28 am
Hi, This looks exactly what I am looking for, however I am completely alien to PHP.
I understand I have to put the code within the page.php file, but I am not sure where exactly it goes. I have tried inserting it into various places but it doesn’t seem to work.
Can somebody please let me know exactly where I place the code?
And also if there is any other amendments that need to be done in any other files css etc?
Thank you in advance.
March 4, 2011 at 11:54 am
@Sarah,
The example sais use it in page.php, altho i do not know if it is theme dependant
When you look at page.php u see a reference to navigation.php
“” in my case.
Try adding the code WITHIN the menu-div on Navigation.php as that seemed to work for me.
If experiencing trouble drop me a mail @ Dvermeer@ictmbo.nl
March 9, 2011 at 12:42 pm
hi it is the great thing that we see here it give us the idea about the submenu
May 4, 2011 at 9:44 pm
Hi Gabriel,
Many many thanks for this – it works wonderfully on my code. However, not being a php savvy ( I am just a designer) I encountered a problem, wondering if you might help.
i am using custom templates on some of my subpages, and it seems your code does not recognizes them as subpages, so on those pages the submenu is not fetched. However, on the other pages using the default template (page.php) the submenu works great, including showing the link to the customized subpage….do you know how i could fix this?
Thanks!
May 6, 2011 at 1:29 am
Your code helped me to accomplish something I needed to do on a custom page template. Thanks.
Do you know how I could edit this code to have it also output the post thumbnail for each of the pages in the list? I’m using the post thumbnail / featured post option built in to WordPress 3.1.
May 16, 2011 at 2:04 pm
very tuff.
June 24, 2011 at 6:05 am
Perfect!!! thanks mate.
August 15, 2011 at 1:06 am
Thanks ! This very helped me. 🙂
August 20, 2011 at 9:54 pm
If you want get submenu of menu WP, you can use this plugin: http://wordpress.org/extend/plugins/browse/new/
November 17, 2011 at 4:54 pm
Hi Gabriel! Even though I’m swedish too, I’ll keep it in english.
First of all: Thanks a lot!
I’m doing a web site for a friend who’s starting a new tattoo studio. There are two artists there and I’d like to put it like this:
Artists (parent)
Artist #1 (child of Artists, parent of Tattoo style #1 & #2)
Tattoo style #1 (child of Artist #1)
Tattoo style #2 (child of Artist #1)
Artist #2 (child of Artists, parent of Tattoo style #3 & #4)
Tattoo style #3 (child of Artist #2)
Tattoo style #4 (child of Artist #2)
It works as is, but I want to hide the Tatto Styles when I’m on the Artists page. I only want to show one generation och children at a time, which means that when I go to the page Artists I want to show it’s children only: Artist #1 & #2. When I click on Artist #1 I only want to show it’s children, not Artist #2s children.
Any thoughts?
November 17, 2011 at 5:05 pm
And also, when I click on Tattoo style #1, #2, #3 or #4 it’s parent disappears. I Only get the main parent, Artists and the two children belonging to the middle parent (Artist #X) which has disappeared. The other middle parent is also missing.
December 14, 2011 at 11:02 pm
This stumps me. I’ve used most of the day trying to find an example that says: “That’s easy, here’s what you do…” but all I find are articles like these
http://wordpress.org/support/topic/wp_nav_menu-list-only-2nd-level-separate-submenu
http://wordpress.stackexchange.com/questions/9504/is-it-still-not-possible-to-show-separate-submenu-with-custom-menu
And your own article.
It should make me angry – but I am more amazed. Separate submenus is practially in every website I develop – and you mean to say that the most used CMS system in the world doesn’t have a simple startLevel parameter in the wp_nav_menu function?
Please tell me I am wrong!
May 10, 2012 at 1:30 pm
A startLevel would be amazing. I have no clue how this can possibly be missing – it was much easier with list_pages, but somehow someone decided we didn’t need that kind of functionality anymore. Fools.
I’ve been searching on/off for weeks for the right way to make relative childmenus in wordpress 3+, without luck.
I am out of options.
December 15, 2011 at 1:23 am
This was perfect. Just the kind of script I was looking for. Your generosity is much appreciated.
December 21, 2011 at 12:45 pm
Just an update to your post.
Function explained and lots of examples on wordpress: http://codex.wordpress.org/Function_Reference/wp_list_pages
January 27, 2012 at 10:07 pm
This is great. Thanks! I was wondering if you could help me figure out where to put the style tags. I’ve wrapped the entire code in a div tag, which works for the child pages, but I’d like to use my h2 style for the parent page, but I can’t figure out how to include that. Thanks so much!
April 6, 2012 at 11:26 am
Brilliant, just what I was looking for. You saved my site!
April 7, 2012 at 10:13 am
Hi. This is Mohamed Shafiee here. Just wanted to share this because I want to make your lives easier with wordpress. My problem was displaying a list of menu items for a specific page or category. The menu was created by using wp_nav_menu(). I was able to achieve this, but it accesses the mysql database as I’m not that experienced with wordpress yet. It works like a charm. Here is the code:
function get_sidemenu() {
$page_id = @$_GET[‘page_id’];
$cat = @$_GET[‘cat’];
$id = $page_id . $cat;
$sql = “SELECT caption, guid, post_id, menu_order FROM ((SELECT CONCAT(id, ‘-‘,(SELECT ‘post_type’)) AS pid, post_title AS caption, (SELECT ‘post_type’) AS type, guid FROM wp_posts) UNION (SELECT CONCAT(term_id, ‘-‘, (SELECT ‘taxonomy’)) AS pid, name AS caption, (SELECT ‘taxonomy’) AS type, CONCAT(‘./?cat=’, term_id) AS guid FROM wp_terms)) posts INNER JOIN (SELECT post_id, CONCAT(SUM(IF(meta_key=’_menu_item_object_id’, meta_value, 0)), ‘-‘, GROUP_CONCAT(IF(meta_key=’_menu_item_type’, meta_value, ”) SEPARATOR ”)) AS object_id, SUM(IF(meta_key=’_menu_item_menu_item_parent’, meta_value, 0)) AS parent FROM (SELECT post_id, meta_key, meta_value FROM (SELECT * FROM wp_postmeta WHERE post_id IN(SELECT post_id FROM wp_postmeta WHERE meta_key=’_menu_item_menu_item_parent’ AND meta_value=(SELECT meta_value FROM wp_postmeta WHERE post_id=(SELECT post_id FROM wp_postmeta WHERE meta_key=’_menu_item_object_id’ AND meta_value=[id]) AND meta_key=’_menu_item_menu_item_parent’))) k WHERE meta_key=’_menu_item_object_id’ OR meta_key=’_menu_item_menu_item_parent’ OR meta_key=’_menu_item_type’ ORDER BY post_id ASC) menu GROUP BY post_id) postmeta ON posts.pid = postmeta.object_id INNER JOIN (SELECT id, menu_order FROM wp_posts) pst ON postmeta.post_id=pst.id ORDER BY menu_order;”;
$sql = str_replace(‘[id]’, $id, $sql);
$res = mysql_query($sql);
$html = ”;
while ($arr = mysql_fetch_array($res)) {
$html .= ‘‘ . $arr[‘caption’] . ‘‘;
}
$html .= ”;
return $html;
}
Put the function in functions.php and use it where ever you need it. The SQL statement is not optimized yet coz I’m running out of time. Do you guys have any comments about this? If you do please email me. My email address is shafee_mohamed@hotmail.com.
April 7, 2012 at 10:16 am
I believe that wp_nav_menu should create a menu that can be accessed when creating themes don’t you think? I wouldn’t have had this problem if that was available.
July 11, 2012 at 2:14 pm
Thanks this was exactly what I needed, I couldn’t find a script for this anywhere!
July 11, 2012 at 6:16 pm
You have to check the var $post->ID
If its not higher than 0 it can be a 404 Page.
if (!$post->ID > 0) $has_subpages = false;
July 25, 2012 at 12:44 pm
Thank you very much, it works perfectly and help me a lot!
October 3, 2012 at 10:33 pm
Doesn’t work for me. Made my navbar disappear.
February 28, 2014 at 1:12 pm
How do we put the code in wordpress ?
I am a novice
Team – Equinox e Services – http://www.equinoxes.in