How to find out whether a Page has sub-pages?

There are several ways to achieve the goal but I guess this one is the most efficient and quickest due to fact it uses WordPress’ built-in recursive function called “get_page_children”. What this function actually does? It matches against the pages parameter against the page ID and in the same time matches all children for the same to retrieve all children of a page. However, be careful because it doesn’t make additional SQL queries to actually get children.


<?php
global $post;
$all_pages = get_pages(); // retrieve all pages
$children = (array)get_page_children( $post->ID, $all_pages ); // $post->ID is supposed to be Page ID, WP treats both equally
// var_dump( $children ); // it'll dump either an empty or array of pages
?>

Any practical example?

We can use it in order to improve “wp_list_pages()” function! For example, let’s say you want to list all the pages as navigation links in sidebar. By using “wp_list_pages()” you can’t make exceptions, you can either make the list of:

  • all root pages only
  • root pages and belonging sub-pages hierarchically (in nested lists)
  • a list of current page children

But what you can’t do is to display only children of a current page while other in nested lists remain hidden. Here’s how WordPress does render stuff hierarchically:
Menu item 1
|- Subitem 1 of menu item 1
|- Subitem 2 of menu item 1
|- Subitem 3 of menu item 1
  |– Subitem 1 of Subitem 3 of menu item 1
  |– Subitem 2 of Subitem 3 of menu item 1
Menu item 2
|- Subitem 1 of menu item 2
|- Subitem 2 of menu item 2
Menu item 3
|- Subitem 1 of menu item 3
|- Subitem 2 of menu item 3
  |– Subitem 1 of Subitem 2 of menu item 3
  |– Subitem 2 of Subitem 2 of menu item 3

…and here’s what we actually want to see in sidebar while reading the page called “Menu item 1″:

Menu item 1
|- Subitem 1 of menu item 1
|- Subitem 2 of menu item 1
|- Subitem 3 of menu item 1
Menu item 2
Menu item 3

What we need now is to intercept default hierarchical menu rendering and inject our own solution/code. Of course, we have to modify ‘wp_list_pages_exclude_these’ function a little bit in order to achieve desired pages menu structure.


<?php
function only_current_page_children() {
	$exclude_these = array();
	$all_published_pages = get_pages();
	$all_children = get_page_children( true, $all_published_pages );

	foreach( $all_children as $child ) {
		array_push( $exclude_these, $child->ID );
	}

	if( !is_page() ) return $exclude_these;

	global $post;
	$my_parenthood = $post->ancestors;
	$my_own_children = get_page_children( $post->ID, $all_published_pages );

	foreach( $my_parenthood as $ancestor ) {
		$my_own_children = array_merge( $my_own_children, get_page_children( $ancestor, $all_published_pages ) );
	}

	foreach ( $my_own_children as $child ) {
		array_push( $my_parenthood, $child->ID );
	}

	return array_diff( $exclude_these, $my_parenthood );
}
// override default 'wp_list_pages_exclude_these'
add_filter( 'wp_list_pages_exclude_these', 'only_current_page_children' );
?>

Where to paste the above code?

If your WP theme doesn’t contain “functions.php” file – create one and simply paste. Otherwise use existing “functions.php”.

USER COMMENTS ( 0 )

Follow Comments via RSS feed. Trackback Comments from your website.

XHTML Allowed tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>