How to Code an Automatic Section Menus Widget in WordPress

How to Code an Automatic Section Menus Widget in WordPress

If you’re a regular user of large e-commerce or news sites, you’ll have noticed that they have section menus, with links to all of the pages in the section that you’re currently in. Adding one of these to your site helps users find related content and will reduce your bounce rate.

But setting up a menu that automatically detects which section a user is in and gives them relevant links isn’t so straightforward. You could add a Custom Menu widget to your sidebar but this would show the same menu on every page of your site. So how do you go about adding a menu that automatically identifies where in the site the user’s currently browsing and gives them links to other pages in that section?

In this post, I’ll show you how to write a plugin that does just that. It does two things:

  • Firstly, it detects which part of the site we’re in, and what the top level page is for that section.
  • Then it outputs a list of all the child pages of that top level page, with a link to the top level page first.
  • Finally, it creates a widget that you can use to output the section menu.

If your user is on a second level page, they’ll see a link to the page above that and all its child pages. And if they’re on a top level page, they’ll see a link to the same page and all of its children.

Note: I’ve uploaded the code for this post to GitHub so you can check it if you’re following along.

What You’ll Need

This is a code based post, so you’ll need a couple of things if you’re going to follow along:

  • A development or testing installation of WordPress.
  • A code editor.

Note: It also helps if you’ve got an understanding of how to write plugins. If this is new to you, take a look at our Academy course on WordPress Development for Beginners.

Creating the Plugin

Start by creating your empty plugin. In your wp-content/plugins directory, create a folder for your plugin and then inside that create an empty php file. Give it a name that’s memorable and describes what the plugin does.

Note: Although for now my plugin only has one file, it’s a good idea to put it in its own folder so that if you want to add extra files such as a stylesheet at a later date, you can do so easily.

Open your new file and add this to it:

Now activate your plugin via the Plugins admin screen.

Checking If We’re On a Top Level Page

First we’ll write a function that checks if we’re on a top level page and if so, saves that page ID as a variable we can use later. If we’re on a second level page, it will identify the top level page above it and save the ID for that page.

In your plugin, add this:

Let’s step through that code to see what it does:

  • Firstly, it calls the global $post variable, which we’ll be using in the function.
  • It the uses if ( $post->post_parent ) to check if the current post has any parents.
  • If so, it uses array_reverse( get_post_ancestors( $post->ID ) to fetch a list of ancestors for the current post and saves those in a variable called $parents.
  • It returns the ID of the top level ancestor using return $parents[0].
  • If the current post doesn’t have any ancestors, it returns the ID of the current post instead.

This means that this function returns one of two things: the ID of the current post if it’s top level, or the ID of its top ancestor if it has ancestors.

We’ll then use this ID in our next function.

Listing the Pages in the Current Section

The next step is to use this ID to list the relevant pages.

Now in your plugin file, add an empty function:

We need to add two things to that function. First we’ll set things up, calling the wpmu_check_for_top_page() function and defining the arguments for the get_pages() and wp_list_pages() functions. Then we’ll add the code to output those pages with links.

First let’s set things up. Inside your empty function, add this:

We’ve called the results of our first function and saved it as a variable called $ancestor. Then we use that as one of the arguments for get_pages(). The arguments also define the depth of the lists and its title, which is blank.

Now let’s output those pages with links. Still inside your function, add this:

Let’s work through this:

  • First we’re running get_pages() using our arguments, and defining that as a new variable called $list_pages.
  • Then we check if our variable is populated, i.e. if get_pages() has returned anything.
  • If so, we open a ul element.
  • The first item in the list is the ancestor itself. This won’t be called by the wp_list_pages() function, as all that will return is the children of the ancestor, so we add that manually. If you don’t want to include the top level page in your list, you can leave this line out.
  • Then we run wp_list_pages() with our arguments, which will output a list of the pages with links.

So that’s our code set up. If you wanted, you could simply add the wpmu_list_subpages() function somewhere in your theme template files to run it (for example in your sidebar). But it gives us more flexibility if we turn it into a widget, so let’s do that.

Creating a Widget to Output Our List of Pages

I’m not going to go into a lot of detail on how the code to create a widget works, but I will work through the code step by step. If you want to learn more, you can work through our post on creating your own custom WordPress widget.

The first step is to set up our widget function using the WP_Widget class. Add this to your plugin:

This function will need to contain four things: the constructor function to create the widget, the form function to output a form in the Widgets admin screen (and the Customizer), the update function to save anything input to the form, and finally the function to output the contents of the widget on the site.

Inside your function, start by adding the constructor function:

Now add the function to add your widget to the Widgets admin screen and the Customizer:

This creates the HTML that will display a form in your admin screens.

The next step is to add the update function. Without this, nothing you add in the admin screens will be saved:

And then finally, add the code to output the contents of the widget on the site:

Let’s take a look at what that last function does:

  • First it checks that we’re on a page that isn’t the home page. This is because the home page doesn’t have subpages so shouldn’t display a section menu. If this is different in your site, you could remove that bit.
  • Then it echoes out any arguments before the widget, as defined by our form function, and defines the title of the widget (which you can edit in the admin screens).
  • Then it creates an aside element, outputs the title and runs our wpmu_list_subpages() function.
  • Finally it closes the aside element and aches out any arguments for after the widget.

That’s the widget set up. But it won’t work until you register it. Here’s the final function you need to add to your plugin:

Using Your Widget in the Site

You now have a plugin with a widget that will automatically display section menus. Here it is in the Widgets admin screen:

Section menus widget in the Widgets admin screen

And this is how it’s output in the front end of the site:

Section menu list in the sidebar
data-true

From now on when you add new pages to your site structure, they will automatically be added to the section menu for the relevant section. Job done!

An Automated Section Menu Will Help Your Users Navigate Your Site

If your site is based on a hierarchical page structure, adding section menus will help your users to find content that’s related to the page they’re currently viewing, and navigate your site. In the sidebar, it acts as a useful addition to your site’s main navigation.

You could customize this plugin to create a list of pages in the current section at the bottom of each page, for example, maybe adding featured images too. That would entail adding featured image support to pages as well as posts – why not try it out?

Rachel McCollin
I hope you've found this tutorial helpful! If you have any questions about the code, please ask in the comments below.