If you’re building a wordpress theme that has the links to all your wordpress-created Pages on its navigation bar, you’ll probably want to have those links generated dynamically as you create new Pages or delete the existing ones. Sure, you can always hard-code the links to those Pages into your theme files, but that would mean you have to dig in and change the code everytime you add or delete any of those Pages, a definite no-no especially if you’re planning to have the theme released to the public.

So how can you achieve that? Turns out it’s quite easy using the wordpress built-in template tag, wp_list_pages(). Suppose that you want to create a horizontal navigation bar with the links to all the first-level pages, like the one I have up there. Firstly, you have to hard-code the Home link in your header.php file, like so:

<ul id="menu">
   <li <?php if ( is_single() || is_home() ) { echo 'class="current_page_item"'; } ?>>
      <a href="<?php echo bloginfo('url'); ?>">Home</a>
   </li>

Notice that I’m using an unordered list to list out all the pages. This is more than just a matter of semantic coding, because it is after all a list of links of pages. The WordPress wp_list_pages() template tag will generate the links to those pages in as a list , so you have to use either <ul> or <ol>.

Next, we would want the template to automatically generate the list of other first-level pages to follow the hard-coded Home link. We do this like so:

   <?php wp_list_pages('echo=1&sort_column=menu_order&depth=1&title_li=&exclude=804'); ?>
   </ul>

The PHP code above automatically generates the list of first-level pages, which you can then style to your heart’s content. Notice that the wp_list_pages() template tag takes an argument to customise how the list should be displayed. in the example above, the code will print out the list of pages to the web page (echo=1), sort it according to the Page Order set from the WordPress back-end (sort_column=menu_order), display only first level pages and none of their children (depth=1), does not add any title to the list (title_li=), and exclude a particular page that has an ID of 804 (exclude=804). You can check out the other optional parameters it takes at this WordPress Codex page.

Now that should print out the entire list of first-level pages to your webpage, and the formatting and styling are all yours. If you want to display the subpages as well, just set the depth=# parameter with the maximum depth that you want, for example depth=2 to list out the first-level pages and their children only, and not their grandchildren. WordPress will automatically render the pages in a nested unordered list.

Note also that WordPress will automatically add the class current_page_item to the list item that corresponds with the page that is currently being viewed, so use that class selector in your CSS file to give it any particular style your design might have, for example:

// In your style.css file
#menu .current_page_item a, #menu .current_page_item a:visited{
   background:url(images/bg_nav-hover.png) repeat-x;
   border:1px solid #fff;
   padding:0 17px;
   color:#000;
}

If for some reason you want to separate the parent and the children pages (most probably because of formatting and styling reasons), you can do that by first setting depth=1 in the code that displays the first-level pages. Then, you can use the following code to print out the children pages where you want them to be displayed, usually in your header.php file:

<?php
   if($post->post_parent)
      $children = wp_list_pages("title_li=&child_of=".$post->post_parent."&echo=0");
   else
      $children = wp_list_pages("title_li=&child_of=".$post->ID."&echo=0");
   if ($children) { ?>
      <ul id="submenu">
         <?php echo $children; ?>
      </ul>
<?php } ?>

The chunk of code above will allow you to style not only the current subpage that is being viewed, but also the parent to that subpage. WordPress will append the class current_page_item to the current subpage being viewed, current_page_parent to its parent page, as well as current_page_ancestor to its grandparent page, so you can use those classes to style them accordingly.

My experience with using this code is that it somehow displays all pages in the subpage area when you are viewing a search results page or a single page that has no post. You can fix that using a conditional statement so that the subpages will only be displayed if the current page being viewed is not a search results page and have at least one post being displayed. To do that, replace:

<?php echo $children; ?>

with:

<?php if (!is_search() && have_posts()) {echo $children;} ?>

With that, you should be good to go. If you have any question or need more clarification, just post a comment below. Good luck!

Should you require more information on the wp_list_pages template tag or the available WordPress conditional tags (such as the is_search() conditional tag), try looking at these pages: