WordPress Menu with wp_list_pages and PHP

I’m working on a sidebar navigation menu. I have a three level hierarchy (parent -> child -> grandchild) and I am trying to do the following:

  • If the current page is a parent page, only show all parent pages.
  • If the current page is a child page, only show all child pages for that parent, and all parent pages.
  • And if the current page is a grandchild page, show all grandchildren for this child page, show all child pages for this parent, and show all parent pages.

This is a good case for wp_list_pages but I cannot figure out the how to get this done with PHP. Here is a link to my test site that shows the page behavior the way I would like it to work. The navigation is on the LEFT SIDEBAR.

Any help is appreciated of course.

@ ggeigr,

I’ve figured out a way to do this using the flexipages plugin however I do not want to use a plugin to accomplish this anymore. I checked your website above and noticed that the sidebar now works (I believe the way you want it to?). Can you share how you did this?

Thanks in advance.

I like these forums very much, and if I figure it out I’m glad to post my findings. Getting the WP menu to behave exactly the way YOU want it is nothing less than a mind bender (for me at least). Here’s something that might help you on your way:

<?php
global $post; $thispage = $post->ID; // grabs the current post id from global and then assigns it to $thispage

$pagekids = get_pages("child_of=".$thispage."&sort_column=menu_order"); // gets a list of pages that are sub pages of $thispage and assigns it to $pagekids
?>

<?php if ($pagekids) { // if there are any values stored in $pagekids, meaning there are sub-pages of the current page ?>
  <ul>
    <?php wp_list_pages("depth=1&title_li=&sort_column=menu_order&child_of=".$thispage); // display ONLY the sub pages of the current page ?>
  </ul>
<?php } else { // $pagekids is empty ?>
  <ul>
    <?php wp_list_pages('depth=1&title_li=&child_of='.$post->post_parent.'&sort_column=menu_order'); // display the sub-pages of the current parent page ?>
  </ul>
<?php } ?>

  1. This will tell you whether the current page has child pages or not. Very useful.
  2. the code is ready to do something if the current page has child pages, and do something else if the current page has no child pages.
  3. The wp_list_pages shown here is written do something specific for a site I’m working on, but it might be helpful anyway.

Afraid not…I had been trying different things for hours now. I believe the code basically loops and uses the same function for the parents and ancestors, so the ‘include’ must have numbers for every level of page. I have proven this by putting the ids of the pages with ‘include’…and the correct pages show…but no children. If I add the children’s id into the ‘include’ also, then it will show that child, etc.

I have been thinking of two ways to work around:

  1. Add another ‘if’ function to where the parent “id=17||22||24”, and bypass if not true.

  2. Use some more CSS to keep hiding everything and only show “page-item-17, page-item-22, etc.”

The problem is I only know the parent ids for now…the client will add indefinite children in the future, so I can’t account for them all.

Thanx for sticking to the forum and leaving your answer even though no one really helped. I just found this today, and was exactly what i was looking for.

However…I am trying to figure out how to use ‘include=17,24,25’ so the list only shows select pages. I see the problem with this as the include would be sent for parents and children and ancestors.

What do you suggest?

[N]

Hi Efishant!

Welcome to the Sitepoint forums!!!

If I have come to understand what you asking about, no matter you use include or exclude parameters for parent pages/posts or children pages/posts you can just pass it to the function as other parameters:


$children = wp_list_pages("title_li=&child_of=".$post->parent."&echo=0&depth=2&sort_column=menu_order&include=17,24,25");

I can find the post ancestor array and the post_parent using the following code:

<?php
$node = (int) 234; // or whatever id you are working with
$mypost = get_post($node);
echo "<pre>"; print_r($mypost); echo "</pre>";
?>

I will need some assistance using PHP to show/hide the child <ul> list if the current page has (or doesn’t have) child pages, while keeping all parent pages visible. I believe this could be done with CSS classes.

Any help would be greatly appreciated.

I came across a great post by Curtis Henson called Dynamic Multi-level Page Menus in WordPress that was very helpful in getting the menu to show or hide sub-pages depending on the current page. Unfortunately for me, this is meant for a horizontal menu. I am looking for help modifying the code to meet my needs. I’ll explain below. Here’s the code Curtis provides:

<?php
/**
 * Multi-level pages menu
 */

function wptt_multilevel_menu() {
	global $post;
	// Top level menu is always displayed
	$top_level = wp_list_pages('title_li=&depth=1&sort_column=menu_order&echo=0');

	// Get post ancestors 
	$post_ancestors = get_post_ancestors($post);

	// Check if a page has any parent pages
	if ($post_ancestors) {

		//get the top page id
		$top_page = $post_ancestors ? end($post_ancestors) : $post->ID;

		// How many ancestors does this page have? Counts the array adds one.
		$n = count($post_ancestors) + 1;

		// Get the pages children, if it has any
		$pages = get_pages();
		$page_children = get_page_children($post->ID, $pages);

		// Checks if a page has children
		if (!empty($page_children)) {
			$children = wp_list_pages("title_li=&child_of=". $top_page ."&echo=0&sort_column=menu_order&depth=" . $n);
		} else { // If the page doesn't have children
			$children = wp_list_pages("title_li=&child_of=". $top_page ."&echo=0&sort_column=menu_order&depth=" . ($n - 1));
		}

	} else {
		$children = wp_list_pages("title_li=&child_of=". $post->ID ."&echo=0&sort_column=menu_order&depth=1");
	}

	// Put it all together
	$menu = '<ul class="menu top_level">';
	$menu .= $top_level;
	$menu .= '</ul>';
	// Only show child navigation if there are children
	if ( $children ) {
		$menu .= '<ul class="menu subpages">';
		$menu .= $children;
		$menu .= '</ul>';
	}
	print $menu;
}
?>

The last section “if ($children)” will add an additional unordered list of child pages underneath the main menu. I’m looking for help in adding that additional <ul> into the main <ul> to create the right structure for a vertical menu, like this:

<ul class="menu top_level">
  <li><a>Parent Page</a>
    <ul class="menu subpages">
      <li><a>Sub Page</a></li>
    </ul>
  </li>
</ul>

I sincerely hope there is someone out there who has an idea I could try to get this working. Help is certainly appreciated. Thanks.

Would it be possible to build an array of child and grandchild pages of the current parent (if any), then show those pages in the list?

You might consider this WP plugin… can do a vertical flyout.

customizing sometimes takes a bit of searching the forums but it works really well.

Rather than messing with the PHP and trying to build an array of child and grandchild pages to show/hide, this can be done in CSS.

Step One: grab the code from the WP codex about wp_list_pages showing sub-pages, and make these adjustments

<?php
	if(!$post->post_parent){
		// will display the subpages of this top level page
	$children = wp_list_pages("title_li=&child_of=".$post->parent."&echo=0&depth=2&sort_column=menu_order");
	}else{
		// diplays only the subpages of parent level
		// $children = wp_list_pages("title_li=&child_of=".$post->post_parent."&echo=0");
		
		if($post->ID)
		{
			// now you can get the the top ID of this page
			// wp is putting the ids DESC, thats why the top level ID is the last one
			$ancestors = end($post->ancestors);
			$children = wp_list_pages("title_li=&child_of=".$post->parent."&echo=0&sort_column=menu_order");
			// you will always get the whole subpages list
		}
	}
	
	if ($children) { ?>
		<ul>
			<?php echo $children; ?>
		</ul>
	<?php } ?>

Step Two: hide your child and grandchild lists

#sidebar ul li ul, 
#sidebar ul li ul li ul, 
#sidebar ul li ul li ul li { display: none; }

Step Three: show your lists if WP marks them with the ‘current_page’ class

#sidebar ul li.current_page_item ul,
#sidebar ul li.current_page_parent ul, 
#sidebar ul li.current_page_ancestor ul,
#sidebar ul li ul li.current_page_item ul,
#sidebar ul li ul li.current_page_item ul li,
#sidebar ul li ul li.current_page_parent ul,
#sidebar ul li ul li.current_page_ancestor ul,
#sidebar ul li ul li.current_page_ancestor ul li,
#sidebar ul li ul li ul li.current_page_item,
#sidebar ul li ul li ul li.current_page_item ul li,
#sidebar ul li ul li ul li.current_page_parent ul,
#sidebar ul li ul li ul li.current_page_parent ul li { display: block; }

This forum has given to me in a lot of ways. I hope this helps someone right back.