The codex provides a way to display the children and parent page for use as a sub-menu. However, this code displays the parent page in the list even when the parent has no children. How can I modify this code so it only displays if the parent has pages?


 * Gets the id of the topmost ancestor of the current page. Returns the current
 * page's id if there is no parent.
 * @uses object $post
 * @return int 
function get_post_top_ancestor_id(){
    global $post;

        $ancestors = array_reverse(get_post_ancestors($post->ID));
        return $ancestors[0];

    return $post->ID;

Calling it:

<?php wp_list_pages( array('title_li'=>'','include'=>get_post_top_ancestor_id()) ); ?>
<?php wp_list_pages( array('title_li'=>'','depth'=>1,'child_of'=>get_post_top_ancestor_id()) ); ?>
  • The code I gave you earlier today does what you are looking for here, as near as I can tell.
    – s_ha_dum
    Commented May 18, 2013 at 23:57
  • Your code outputs the "Pages" caption and creates an irregular list. Commented May 19, 2013 at 1:12
  • Seriously? Add 'title_li'=> to get rid of the label. You must know that given that you used it in your own code to remove the label. It is a trivial adaptation. No idea what you mean by an "irregular list". The actual list is a nested list generated by WordPress core code.
    – s_ha_dum
    Commented May 19, 2013 at 1:41

3 Answers 3

    if ($post->post_parent) { //We are a child, print out sub menu
            wp_list_pages( array('title_li'=>'','include'=>$post->post_parent) );
            wp_list_pages( array('title_li'=>'','depth'=>1,'child_of'=>$post->post_parent) );

//We are not a child but do we have children
$children = wp_list_pages(array('child_of' => $post->ID, 'echo' => 0));

if ( !empty($children) ) {
    //If so print out the sub menu
    wp_list_pages( array('title_li'=>'','include'=>$post->ID) );
    wp_list_pages( array('title_li'=>'','depth'=>1,'child_of'=>$post->ID) );
//Not a child and not a parent so show nothing and continue 

I tested this and it works as you mentioned, I couldn't figure out that function however maybe someone can post a better solution using that function.

  • For me, this hid the entire list. Commented May 18, 2013 at 21:12

I took a different route and solved this with CSS. Maybe not as robust, but for a quick fix when needed, here is what I used:

html .main-navigation li.menu-item-263{
    display: none;
html .main-navigation li.menu-item-263.menu-item-has-children{
    display: inline-block;

Menu item 263 is my parent menu item that sometimes didn't have children (for non-members that aren't logged in because no access to child pages). I guess it breaks if my menu IDs ever change, and I'd have to repeat the CSS to handle other menus... so not perfect, but quick and easy, and not likely to break anything or require a lot of retesting.

Now for the obvious stuff, for the non-developers reading this:

I placed the above in my theme style.css file. To get the menu item ID I just right-click it in FireFox and select "inspect element" -- the ID will be in the class of the menu element. The first 3 lines of the above code hide the menu item with that ID, the last 3 lines override that (display it) if the "menu-item-has-children" class is set (only if it has children).


This solution was written by MichaelH at the following link: http://wordpress.org/support/topic/how-to-only-list-pages-if-they-have-no-children.

This does not use list-pages, but get_pages instead, so it may not be 100% relevant. I slightly modified this code with the addition of an exclamation mark before "empty". You can remove it to see how it is working.

//get all 'first level' pages, then iterate through those results,
//then for each result, see if there are child pages, and if there
//are no child pages for that page, then display
$pages = get_pages('parent=0');
foreach ($pages as $page) {
  $child = get_pages('child_of='.$page->ID);
  if (!empty($child)) {
    <li><a href="<?php echo get_page_link($page->ID) ?>"><?php echo $page->post_title;?></a></li>

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.