Justin Tadlock

WordPress Custom Fields: Listing A Series Of Posts

Creating a list of related posts in a blog series

This is an updated version of this article. If you’re looking for the older version, see page 2.

Do you write long series of posts? Do you have a bunch of articles that definitely need to be linked together? This WordPress custom fields technique will allow you to do that without a lot of hassle. Basically, this is a simple, customized related posts script. It checks to see whether a post is in a series, then lists all the posts in the series.

The WordPress custom fields tutorial series uses this code for listing posts. You can scroll to the bottom of this entry to see what the outcome looks like.

The reason I’m writing this tutorial is precisely because of the WordPress custom fields series. After three posts, and going back to each previous post to add a link to the new post, I realized that this was only going to get more tedious and time-consuming each time I wrote another article in the series. So, this idea was born from that.

How to set up your posts

You’ll probably want more than one post. This is a series after all.

Create a custom field key called Series first. Give it a unique custom field value. You should give every article in the series this exact same key and value.

This is all you have to do on the Write Post screen.

Adding the series function

Open your theme’s functions.php file and paste this code into it.

<?php
function article_series() {
    global $post;
    $series = get_post_meta($post->ID, 'Series', true);
    if($series) :
        $args = array(
            'numberposts' => -1,
            'meta_key' => 'Series',
            'meta_value' => $series,
        );
        $series_posts = get_posts($args);
        if($series_posts) :
            $class = preg_replace("/[^a-z0-9\\040\\.\\-\\_\\\\]/i", "", $series);
            $class = strtolower(str_replace(array(' ', '&amp;nbsp;'), '-', $class));
            echo '<div class="series series-' . $class . '"><h4 class="series-title">' . __('Articles in this series') . '</h4><ul>';
            foreach($series_posts as $serial) :
                if($serial->ID == $post->ID)
                    echo '<li class="current-post">' . $serial->post_title . '</li>';
                else
                    echo '<li><a href="' . get_permalink($serial->ID) . '" title="' . str_replace('"', '&quot;', $serial->post_title) . '">' . str_replace('"', '&quot;', $serial->post_title) . '</a></li>';
            endforeach;
            echo '</ul></div>';
        endif;
    endif;
}
?>

Add your function to your single post template

You can add this to single.php and/or page.php. If your theme has a hook after posts/pages, you can even hook it to that with without touching a template file (ask your theme author about this).

So, open your file and add this somewhere in it before the call for comments_template(), preferrably somewhere within the Loop.

<?php article_series(); ?>

That’s it, and you’re done. Just save everything and check out your series list at the end of posts within that series. You can create as many of these as you like.

Final thoughts

Now, that should do it. You can always tweak this script to better apply to your needs. There are also some other uses you can extract from this article.

I’m already loving this because I won’t have to go back to the previous three posts in this series just to link back to this article. Life is much simpler now.

As always, remember to subscribe to the feed to stay updated on the WordPress custom fields tutorial series. I have a few more ideas up my sleeve and am ready to post them as soon as I finish testing.

Let me know if you liked this tutorial. I’m always open to feedback and looking for new ideas to implement.

Set up your posts:

The first thing you will need is at least two posts. You need to create a Key named “Series Name” and assign it to each post. You also need to come up with an actual name for this series, then put that in the Value box. The Key and Value need to be the same for each post. Otherwise, this won’t work.

Modify the code:

Now, open “single.php” from your theme directory. Scroll to the bottom and find the closing

that ends the post. This will be different with individual themes. You can place this wherever you like. My code is after the post and before the comments template.

Insert this code:

// Checks to see if the post is in a series

// Get Series Name
$series_name = get_post_meta($post->ID, 'Series Name', $single = true);

// If post is in a series
if($series_name !== '') {
    // Echo the list header
    echo '<h3>Other articles in the ' . $series_name . ' series:</h3>';

Basically, this checks to see if your article is in a series at all. If it is, a header for your list is displayed. If it’s not, then the rest of the code won’t run.

Now, we need to query the database for posts specifically with the same series name as this post. We do this by narrowing the query down to the post meta Key and post meta Value.

    // Query the database for the posts
    $query_string = "
    SELECT *
    FROM $wpdb->posts
    LEFT JOIN $wpdb->postmeta ON ($wpdb->posts.ID = $wpdb->postmeta.post_id)
    WHERE $wpdb->postmeta.meta_key = 'Series Name'
    AND $wpdb->postmeta.meta_value = '$series_name'
    AND $wpdb->posts.post_status = 'publish'
    AND $wpdb->posts.post_type = 'post'
    ORDER BY $wpdb->posts.post_date ASC
    ";

All that’s left to do now is output the posts in a nice, neat list. I’m currently using an unordered list (

    ), but you can easily change this to an ordered list (
      ). Add this last bit of code and you’re done.

          // List the posts
          $series_posts = $wpdb->get_results($query_string, OBJECT);
              if ($series_posts):
              echo '<ul>';
              foreach ($series_posts as $post):
                  echo '<li>'; ?>
                  <a href="<?php echo the_permalink(); ?>" title="<?php echo the_title(); ?>">
                  <?php echo the_title();
                  echo '</a></li>';
              endforeach;
              echo '</ul>';
              endif;
              rewind_posts();
          } // End check for series
      ?>

      This is a little more complicated than some of our other scripts in the Wordpress custom field series because of the database query. If you noticed, I changed a little something with the naming of the Key in this post of the series. Do you know what it is?

      I capitalized the name and used a space between the words: “Series Name.” In the previous posts, this would have looked like “series-name.” The reason I changed, was to show you a different way to name your Keys. You should note that custom field Keys are case-sensitive.

      What if I use a related entries plugin?

      I use a related posts plugin on this site, and this is quite useless when I’m customizing my related posts with this method. I’m going to fix this little problem by using a PHP “else” statement.

      So, if this post is in a series, my related posts are replaced by my list of the posts in the series. The related posts plugin is used if the post is not in a series.

      <?php
      else {
          if(function_exists('related_posts')) { ?>
              <h3>Related Posts</h3>
              <ul>
                  <?php related_posts(); ?>
              </ul>
              <?php }
          } // end else ?>

      Custom post titles in the list:

      If you want to add custom titles to individual articles specifically for this list, you can create a Key named “Series Article” and give it a Value of “Your Custom Title.” This might be useful if your titles are something like “Example Series: Bla Bla Bla” and “Example Series: Yada Yada Yada.” You may want to remove the “Example Series” part because your readers will already know what series of articles this is.

      In the above code, replace the code between the “foreach” and “endforeach” with this:

      // get article titles
      $series_article = get_post_meta($post->ID, 'Series Article', $single = true);
      echo '<li>'; ?>
      <a href="<?php echo the_permalink(); ?>" title="<?php echo the_title(); ?>">
      <?php if($series_article !== '') echo $series_article; else echo the_title();
      echo '</a></li>';