Alphabetical Post Navigation in WordPress

Have you ever had a need to build a page with alphabetical navigation in WordPress? There are lots of scenarios where this makes sense:

  • Alphabetical sitemaps.
  • A Glossary or Table of Contents


I’m building a site right now focused on terms and their definitions. Presenting terms in a default archive loop makes no sense. A better experience is to present them as a glossary of terms with alphabetical navigation.

There are plugins that can get you where you need to go, but they’re not necessary. A little bit of custom template code leveraging PHP output buffering gets you where you want to go pretty efficiently.

Create a new Template

I’m building a glossary page that will list all of the posts in a custom post type, called term. By using the WordPress Template Hierarchy I know that WordPress will create that page using a template namedarchive-terms.php if I create one in my theme. This is a logical place to put my custom query and template code. Place yours wherever it makes sense.

Query the Content You Want to Display in the Alphabetical List

By default, any template code you write operates against WordPress’ default loop. If that’s what you want in your list, you don’t need to create a new query. I want my Glossary page to list all of the terms in the glossary alphabetically. I need to create a custom query that selects and loops the right content.

Build and Buffer the Content

That query gives me the content I want in my glossary page. Now I need to loop over the query and do something with it’s results:

  1. Build the alphabetical navigation elements.
  2. Build the alphabetically-sorted list of posts that can be navigated to using alphabetical navigation.

We have two choices. We can loop the content multiple times and build the two distinct elements. The second choice is to loop once and use output buffering to control what renders when. We’ll do multiple loops first, then combine and simplify in the final example.

Building the Alphabetical Navigational Elements

First, lets loop through the results and capture the first letter of all the posts to build our navigation:

The template code above is a cookie-cutter WordPress loop that iterates through the posts, captures the first letter of each post, and renders a navigation list of each letter that links to the anchor#begins-with-<letter>. If you’ve got a basic understanding of WordPress Loops and basic theme coding, it’s not too complex. Because our query already specified ascending alphabetical order, we don’t have to worry about sorting the list ourselves.

Now it needs something to link to.

Building the Alphabetical List of Posts

Next, we need to build out our list of content. In this example we’ll keep it simple: we’ll build a two-tier list with anchors.

In the code above we built a list of letters linked to the alphabetical navigation menu. Each list element contains a child unordered list of all posts that start with that letter. We create some flags that track the current letter and whether or not we’re in the middle of a list. We use these to properly open and close our ordered list and list item tags.

Putting it All Together

The two blocks above can be simplified by leveraging PHP’s output buffering functions. Output buffering essentially stores your output in memory so you can retrieve and display it at a later time. Using output buffering we avoid duplicate queries and loops. And we completely avoid tracking flags used to control tag nesting.

The first thing we do is create $alphabet, which is an associative array that will have letters as keys and arrays of output sections as values. As we loop our content we create an output buffer using ob_start(), output each post as a list item linked to it’s permalink, and capture that output using ob_get_contents(), save the output into the current letter, and close the buffer with ob_end_clean().

Finally, we use the keys of the associative array to build our alphabetical navigation. Then we use the array one more time to build anchored sections of content.

0 replies

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.