Sometimes I get a client job that requires a site built entirely on pages. No fancy database queries, no extra template files - just a whole bunch of pages in a hierarchical structure.
A very large site built on pages can become unwieldy and confusing for users if the navigation isn't done right, so it's helpful to provide a list of all the pages in the current branch of the page hierarchy on each page.
For example, if your site is for an organization and each of the organization's functions has a top level page with subpages for individual departments, then you'll want to list all of those departments along with a link to the top level function page. You'll want to do this on each of those department pages and on any subpages they might have as well as with the top level page itself.
To do this, you won't be able to output lists of related content by running queries on the current post type or taxonomy term. Instead, you'll have to identify where in the structure the current page is and then display a list of links accordingly.
Here, I'll show you how to do just this, by creating a function you can add to your sidebar file or perhaps above the content in your template files (or activate via a hook if your theme uses those).
This consists of two stages:
- identifying where the current page is in the structure
- outputting a list of pages
What You'll Need
To complete this tutorial, you'll need:
- an installation of WordPress
- a text editor
Creating Your Plugin
I'm going to create this function in a plugin so that its theme independent. So your first step is to create a plugin file. Mine is called tutsplus-list-subpages.php
.
Open your plugin file and add the following:
<?php /*Plugin Name: List Subpages Description: This plugin checks if the current page has parent or child pages and if so, outputs a list of the highest ancestor page and its descendants. It creates a function called tutsplus_list_subpages() which you insert into your theme or activate via a hook to work. Version: 1.0 Author: Rachel McCollin Author URI: http://rachelmccollin.com License: GPLv2 */ ?>
Obviously, your code will be different as the plugin author and URL will change, and you might want to amend the description.
Including the name of the function in the description is helpful as it means that when you install your plugin on a site, you don't need to check the code to remind yourself how to use it.
Identifying the Current Page in the Hierarchy
To find out where the current page is in the page hierarchy, you need to do four things:
- Check that this is actually a page
- Check if this post has parents
- If not, then you know it's the top level ancestor for this part of the hierarchy
- If so, you need to identify the top level ancestor using
get_post_ancestors()
So let's do it!
Create a new function with a conditional tag in it to check we're on a page:
<?php function tutsplus_check_for_page_tree() { //start by checking if we're on a page if( is_page() ) { } } ?>
Now, inside the is_page()
conditional tag, start by defining the $post
global variable:
<?php function tutsplus_check_for_page_tree() { // start by checking if we're on a page if( is_page() ) { global $post; } } ?>
Next you need to identify whether the current page has parents, which you do using if( &post->post_parent )
:
<?php function tutsplus_check_for_page_tree() { // start by checking if we're on a page if ( is_page() ) { global $post; // next check if the page has parents if ( $post->post_parent ) { } } } ?>
If the page does have ancestors, you need to identify the top-most of these, which you do using get_post_ancestors()
:
<?php function tutsplus_check_for_page_tree() { //start by checking if we're on a page if( is_page() ) { global $post; // next check if the page has parents if ( $post->post_parent ){ // fetch the list of ancestors $parents = array_reverse( get_post_ancestors( $post->ID ) ); // get the top level ancestor return $parents[0]; } } } ?>
This defines a new variable of $parents
whose value is the ID of the topmost page in the current branch of the hierarchy. The line return $parents[0];
outputs that value so that you can use it in a later function.
Finally, you need to define what happens if the current page doesn't have parents, i.e. if it's the topmost ancestor itself. In that case you want to output the current page's ID, so you add the following to your function:
return $post->ID;
Your entire function will now look like this:
<?php function tutsplus_check_for_page_tree() { //start by checking if we're on a page if( is_page() ) { global $post; // next check if the page has parents if ( $post->post_parent ){ // fetch the list of ancestors $parents = array_reverse( get_post_ancestors( $post->ID ) ); // get the top level ancestor return $parents[0]; } // return the id - this will be the topmost ancestor if there is one, or the current page if not return $post->ID; } } ?>
Outputting a List of Subpages
Now that you know the ID of the topmost page in the current branch of the hierarchy, outputting a list of its subpages is relatively straightforward. You use get_pages()
to identify the child pages of the page whose ID you've identified. You'll also need to output a link to the ancestor page at the beginning of the list.
Using list_pages() to Identify Subpages
Start by creating a new function with a check that we're on a page:
<?php function tutsplus_list_subpages() { // don't run on the main blog page if ( is_page() ) { } } ?>
Note that if you're going to add this function to your page.php
template, you can leave out the check that a page is being displayed.
The first thing you need to do inside that conditional tag is pull in the page ID you identified in the tutsplus_check_for_page_tree()
function, which you do with this line of code:
$ancestor = tutsplus_check_for_page_tree();
Below that, define the arguments for the get_pages()
function:
$args = array( 'child_of' => $ancestor, 'depth' => '-1', 'title_li' => '', );
Let's have a quick look at the arguments I've used:
-
'child_of' => $ancestor
identifies those pages which are a child of the$ancestor
page -
'depth' => '-1'
tells the function to go to as many levels in the hierarchy as there are in the site. You can change this if you just want to display one or two levels. -
'title_li' => ''
ensures that what's output isn't wrapped in any HTML tags - as I'll be adding those later.
Next, you need to run the list_pages()
function:
$list_pages = get_pages( $args );
Outputting the List of Pages
Now that you have your pages, you need to output them with links. To do this, first check that list_pages()
hasn't returned an empty array:
if ( $list_pages ) { }
Inside that check, the first link is to the top level page:
<ul class="page-tree"> <?php // list ancestor page ?> <li class="ancestor"> <a href="<?php echo get_permalink( $ancestor ); ?>"><?php echo get_the_title( $ancestor ); ?></a> </li> </ul>
And then below that first <li>
element but still inside the <ul>
, use the wp_list_pages()
function to output a list of the pages wrapped in hyperlinks to them:
wp_list_pages( $args );
This will display a list of the page titles as links.
Your entire tutsplus_list_subpages()
function will now look like this:
<?php function tutsplus_list_subpages() { // don't run on the main blog page if ( is_page() ) { // run the tutsplus_check_for_page_tree function to fetch top level page $ancestor = tutsplus_check_for_page_tree(); // set the arguments for children of the ancestor page $args = array( 'child_of' => $ancestor, 'depth' => '-1', 'title_li' => '', ); // set a value for get_pages to check if it's empty $list_pages = get_pages( $args ); // check if $list_pages has values if ( $list_pages ) { // open a list with the ancestor page at the top ?> <ul class="page-tree"> <?php // list ancestor page ?> <li class="ancestor"> <a href="<?php echo get_permalink( $ancestor ); ?>"><?php echo get_the_title( $ancestor ); ?></a> </li> <?php // use wp_list_pages to list subpages of ancestor or current page wp_list_pages( $args );; // close the page-tree list ?> </ul> <?php } } } ?>
Activating the Function
You can activate the function in one of two ways:
- By calling
tutsplus_list_subpages()
in one of your theme's template files, such as thesidebar.php
file - By attaching it to a hook in your theme.
For example, if your theme has a tutsplus_sidebar
hook in the sidebar.php
file, you'd add the following to your functions.php
file:
<?php add_action( 'tutsplus_sidebar', 'tutsplus_list_subpages' ); ?>
Summary
The code I've demonstrated lets you automatically add a list of related pages to a page anywhere in your site's hierarchy.
If you're using it for client sites, you'll need to make sure the client understands how to create pages hierarchically, but other than that it won't mean they have to think about it at all.
If you wanted to make the code even more user-friendly for clients you could create a widget (or maybe a shortcode) to output the list of pages, but that's a topic for another day!
Comments