Friday, November 12, 2010

Creating a Submenu in WordPress

For a project I’m currently working on I wanted to create a submenu that included the parent page as well as the supbages. I just wanted to display the submenu only if the parent page had subpages. Searching the WordPress Codex and googling for a solution I couldn’t quite find an example that took all these factors into consideration so I had to figure it out myself. Here’s the approach I came up with.

Checking if the page has subpages

I searched in vain for a method to determine if the current page has any subpages or not. I first assumed that there would be a has_subpages() method, but so far I haven’t found any. Lacking that, I came up with a very crude way of checking it. I explicitly had to try to fetch all the subpages with the function wp_list_pages() and then check if it returned anything. It’s not pretty but it works.

$children = wp_list_pages('&child_of='.$post->ID.'&echo=0');
if($children) {
// This page has subpages
}

Checking if it’s a parent page or a subpage

The next thing I had to figure out was how to check i the current page is a parent page or a subpage. That’s done with the following code.

if(is_page() && $post->post_parent) {
// This is a subpage
} else {
// This a parent page
}

Fetching the submenu

Now I needed a way to fetch the subpages. This is done with the wp_list_pages() function. The tricky part about this is that there’s no way to get both the parent page and the subpages in the same call. So therefor we have to call the function twice. The call also looks a little different depending on if we’re on the parent page or on the subpage.

if(is_page() && $post->post_parent) {
// This is a subpage
$children = wp_list_pages("title_li=&include=".$post->post_parent ."&echo=0");
$children .= wp_list_pages("title_li=&child_of=".$post->post_parent ."&echo=0");
} else if($has_subpages) {
// This is a parent page that have subpages
$children = wp_list_pages("title_li=&include=".$post->ID ."&echo=0");
$children .= wp_list_pages("title_li=&child_of=".$post->ID ."&echo=0");
}

There are other ways of doing this, but the benefit of this approach is that we automatically get class="current_page_item" on the list-item that represents the page that we’re currently on. That’s handy if you want to style that item in any particular way.

Outputting the HTML

The last step is to output the actual HTML. I’ve chosen to output it as an unordered list.

<?php // Check to see if we have anything to output ?>

<?php if ($children) { ?>

<ul class="submenu">

<?php echo $children; ?>

</ul>

<?php } ?>




Putting it all together

Now it’s time to put all the pieces together. Just put this code in your page template one of the pages in your template, like for example page.php or sidebar.php and you’re good to go. These pages are located in /wp-content/themes/your-theme/.

<?php

$has_subpages = false;

// Check to see if the current page has any subpages

$children = wp_list_pages('&child_of='.$post->ID.'&echo=0');

if($children) {

$has_subpages = true;

}

// Reseting $children

$children = "";


// Fetching the right thing depending on if we're on a subpage or on a parent page (that has subpages)

if(is_page() && $post->post_parent) {

// This is a subpage

$children = wp_list_pages("title_li=&include=".$post->post_parent ."&echo=0");

$children .= wp_list_pages("title_li=&child_of=".$post->post_parent ."&echo=0");

} else if($has_subpages) {

// This is a parent page that have subpages

$children = wp_list_pages("title_li=&include=".$post->ID ."&echo=0");

$children .= wp_list_pages("title_li=&child_of=".$post->ID ."&echo=0");

}

?>

<?php // Check to see if we have anything to output ?>

<?php if ($children) { ?>

<ul class="submenu">

<?php echo $children; ?>

</ul>

<?php } ?>



I think that WordPress is an absolutely awesome CMS/Blog engine, but it do lack some handy methods. Fortunately it’s almost always possible to create workarounds. I hope that you will find this useful in your own WordPress Template. Don’t hesitate to tell me if you have a smarter way of doing this.

2 comments:

  1. All I can say is thank you for this very useful information. It will surely help me in my Wordpress Development.

    ReplyDelete
  2. Nice post.

    I have a mix of pages and categories in my menu.
    I would like to only display the sub-menu of the page I'm in. Any idea on how to do it?

    For example, I have:
    Page1
    -Page2
    --Category1
    --Category2

    If I'm in the Page2, I want a menu to be displayed and showing:
    Category1
    Category2

    Thanks

    ReplyDelete