Dec
5
2011

WordPress Parent Child Page Links

WordPress page links can be accessed by default functions such as wp_list_pages and wp_page_nav. Yet I came across a project where I need the ability to control the WordPress page Parent->child links with more accuracy. I needed the ability to break apart the default WordPress data into groups of parent pages and their children, and then be able to display them using any HTML container I chose.

WordPress Page function Limitations

WordPress functions to access page links retrieve a string of all the pages requested, as set by the filters we specify. We can exclude pages or request only specific pages and their children. Most of the WordPress page functions return a list of pages in, quite literally, an HTML list! Well, that certainly doesn’t allow control over each group or it’s containers on it’s own. To break it up and get control I would need to use several PHP string manipulations or regular expressions to do this. Typically, any WordPress function call to get page links would return data that looks like this:

  • Fruit
    • Apples
    • Peaches
  • Dairy
    • Milk
    • Cheese
  • Meat

Using CSS we can refine how that will look on the page using display: inline-block; and other common methods. Yet this still doesn’t give us the ability to define the page link containers or each group of parent pages and their children pages.

Gaining Control of WordPress Page Links

In order to get full control of page links I created a function:

<?php
/**#@+
 * FUNCTION urm_parent_child
 *
 * @creates a custom list of parent-> child links
 *
 * @param  array type [$page_list] array of pages by page name or page number
 *           ex: $parent_pages = array('Marketing',	'70', SEO);
 * @param  string type [$class] CSS class name for container
 * @author Neil Davidson
 * @version 1.0.2
 */
function urm_parent_child($page_list, $container_class)
{
	global 	$wpdb;
	if(!is_array($page_list) && !empty($page_list))	// if list is not array then its descriptor of single page
		$page_list = array($page_list);				// so we put it to array and pretend we are processing array of one page
	
	if($page_list && count($page_list))
	{
		foreach($page_list as $title)
		{
			if(!$title =='')
			{
				if(is_numeric($title))
				{
					$parent_ID = $title;
					$parent = get_post($title);	
					$parent_link = '<li><a href="'.get_permalink($parent->ID).'">'.$parent->post_title.'</a></li>';
				}
				else
				{
					$parent = get_page_by_title($title);
					$parent_ID = $parent->ID;
					$parent_link = '<li><a href="'.get_permalink($parent->ID).'">'.$parent->post_title.'</a></li>';
				}
				$child_pages = $wpdb->get_results("SELECT *  FROM $wpdb->posts WHERE post_parent = $parent_ID AND (post_type = 'page' AND post_status = 'publish') ORDER BY menu_order",'OBJECT'); 
				if(!$parent_ID =='')
				{
					$parent_child_return_list .= '<ul class="'.$container_class.'">';
					$parent_child_return_list .=  $parent_link;
				}
				if ( $child_pages )
				{
					foreach ( $child_pages as $pageChild )
					{
						 setup_postdata( $pageChild ); 	//initializes template tags like the_content and others (alternative to the_post())
						 $parent_child_return_list .= '<li><a href="'.get_permalink($pageChild->ID).'" rel="bookmark" title="'.$pageChild->post_title.'">'.$pageChild->post_title.'</a></li>';
					}
					$parent_child_return_list .= '</ul>';
				}
				/*
				* if no children exist for the page but we put it in the array, lets simply list that page in it's own container
				* which we do by simply closing off the parent container.  Because there are no children the code
				* skips by the conditionals and loop straight from the $parent_link list to the closing tag
				*/
				else if(!$parent_ID =='')
					$parent_child_return_list .= '</ul>';
			}
		}
	}
	return $parent_child_return_list;
}

Instead of breaking down the code like I normally do I will show you how to use this function and open up discussions to you!

The function accepts an array of pages or a single page, and uses PHP is_numeric to determine if it is a page id or a page name. I wanted to be able to keep the function dynamic enough to allow use of both.

The function also requires the CSS class name to use.

Basic Usage

Using just the function without being creative it will display all the pages in the array and any children they have. Very similar to a sitemap. Default use would look like the above grocery list group and be called like this:

             <?php
			    //include the custom function_exists
				include (TEMPLATEPATH . '/scripts/urm_parent_child.php'); 			 
			 
			     //create an array of pages to list children of
			    $page_titles = array(
				'Fruit',
				'Dairy',
                                'Meat'
				);
                             urm_parent_child($page_titles,'class_name');
			
			?>

Notice that the array doesn’t include child pages? That’s because the function takes in the Parent page and, if children pages exist, displays it. If no children pages exist it will only display a parent page. This would print out something like:

  • Fruit
    • Apples
    • Peaches
  • Dairy
    • Milk
    • Cheese
  • Meat

Advanced Usage

I mentioned earlier that WordPress didn’t give me full control or the ability to easily break apart page links into groups. Well, using this function we can now do that by placing the array in a foreach loop!:

             <?php
			    //include the custom function_exists
				include (TEMPLATEPATH . '/scripts/urm_parent_child.php'); 			 
			 
			     //create an array of pages to list children of
			    $page_titles = array(
				'Fruit',
				'Dairy',
                                'Meat'
				);
				//loop through the array so we can best utilize the modulus for layout.
				foreach($page_titles as $value){				
				//echo the container and it's children, if any
				$link_string = urm_parent_child($value,'class_name');
				    //only create a container if something exists
					if(!empty($link_string)){
						echo '<div class="Main_Container">';
						echo $link_string;		
						echo '</div>';
					}//end if not empty string
				}//end foreach
			
			?>

Which could give us the ability to display each block something like this:

  • Fruit
    • Apples
    • Peaches
  • Dairy
    • Milk
    • Cheese
  • Meat

If I want to change the links from displaying as a list item I simply change the surrounding HTML in the function and set it to whatever I want and/or need to use.

Summary

If you need more control over WordPress page links and want the ability to define your own page link containers this function will be a blessing to you.

You can download the function, if you like!

Happy Coding!

Related posts:

About the Author: Neil Davidson

Neil Davidson writes articles and tutorials about web development. He is happily married with three dogs, two cats and an ominous spirit in his home.

2 Comments + Add Comment

  • Hi! Great stuff, using your function along with a custom wp_query to dynamically get all the parent-pages.. However, it doesn’t seem to take into account to put the childpages inside their own ul-tag.. right now both parentpage and child is both in the same ul. This is how my code looks:

    http://pastebin.com/YjxugHhs

    • Thank you for your feedback. What is actually happening is you are requesting all children pages to be returned for each parent you send to the function. Within the function you can define how you want to set the display. In the above example I have added HTML list tags but you can use anything you wish. Whatever is used, if anything, is returned by the function.

      If you look at line 40 of the above function you will note the start of the HTML unordered list. The last thing we add is the end of that list. If you want the child links to be within their own unordered list you would simply add an HTML open tag around line 48 and close it at line 49.

      This function is very generic and can easily be adapted to fit any layouts and needs. The tutorial was for instructional purposes, but this function can be added to quite easily to add layout controls. I left an open example within the function using the variable $container_class.

      This can be extended to, say, call a specific layout styling for lists, tables, menus, or any such. As the key functions are there it would take little to adjust the code to be more adaptable for layouts.

Leave a comment