Latest TweetsHeads up: Blasty (DMCA service) MIA: perishablepress.com/avoid-blas…
Perishable Press

Triple Loop for WordPress

[ WordPress Triple Loop ] Two of the themes developed by Perishable Press, Apathy and Information, depend on three WordPress loops to operate as intended. For each of these themes, the three loops consist of two “side” loops and one main loop. The side loops each display posts from one specific category, while the main loop displays posts from every category not specified in the side loops.

Update: It’s now recommended to use WP_Query and other “looping” techniques to customize the WordPress loop, create multiple loops, and so forth. You can learn more about these techniques in my tutorial, 4 Ways to Loop with WordPress. The basic principles of this article still apply, but you should be using WP_Query instead of query_posts whenever possible.

Intro

There are many different multi-loop configurations currently available for WordPress users. Needless to say, despite a wide variety of available loop setups, implementing a customized multiple loop frequently requires a great deal of time of energy. Certain loop sets accomplish one task, but fail at another, while others refuse to provide enough flexibility in general. Indeed, after countless rounds of trial and error establishing multiple loops, we finally developed the almost-perfect triple-loop configuration.

The Upside

The Perishable Press triple loop for WordPress provides several specifically designed features:

  • Each side loop displays posts from any unique category.
  • Each side loop displays any unique number of posts.
  • The main loop may exclude posts from any category.
  • The main loop displays no posts included in either side loop.
  • The main loop displays any unique number of posts.
  • Post views function properly for any post in any loop.

The Downside

The Perishable Press triple loop for WordPress currently encompasses these specific caveats:

  • Archive navigation is only possible for the main loop.
  • The main loop must precede both of the side loops.
  • The “side loops” technically are neither “side” nor “loops”.

Additionally, the main loop will look at the first “x” number of posts, and display only those posts which are not included in either side-loop category. Thus, if the most recent “x” number of posts all belong to either of the side categories, there will be no posts to display in the main loop. Fortunately, there are several relatively simple solutions for this situation, which will be discussed at the end of this article.

The Main Loop

As mentioned, the main loop must appear before the two side loops. Fortunately, the magic of CSS nullifies the restriction imposed by this requirement. Another important point to mention involves the lack of archive navigation (e.g., << previous | next >>) for either of the side posts. Although this may be possible, I have yet to determine an optimal method.

Nonetheless, complete navigation comes standard with the main loop. The side loops work perfectly for displaying the latest “x” number of posts from their respective categories. An elegant solution would be to provide a nice “Read more posts from this category »” link for each side loop display.

Moving along, our first task is to exclude our two chosen side categories from the main loop. Here, we are instructing WordPress to process posts as usual, with the exception that all posts from either side-loop category are ignored. Here are the first three lines of the main loop:

<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
<?php if ( in_category('7') && is_home() ) continue; ?>
<?php if ( in_category('8') && is_home() ) continue; ?>

Above, the loop starts with the usual if():while() statement, and then proceeds into a key pair of conditional if statements. The first conditional statement filters out all posts from category 7, while the second does the same for category 8. The remainder of the main loop is expressed as usual, as generalized here, replete with several key elements:

// the first loop
<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
<?php if ( in_category('7') && is_home() ) continue; ?>
<?php if ( in_category('8') && is_home() ) continue; ?>
<?php the_title(); ?>
<?php the_content(); ?>
<?php comments_template(); ?>
<?php endwhile; ?>
<?php posts_nav_link('','','&laquo; Previous') ?><?php previous_post('&laquo; %', '', 'yes'); ?>
<?php posts_nav_link('','Next &raquo;','') ?><?php next_post('% &raquo;', '', 'yes'); ?>
<?php else : ?>
<p>Sorry..</p>
<?php endif; ?>

The previous loop example includes title, contents, comments, and navigational elements, as well as an else statement issuing a nice “Sorry” message for those awkward, missing-post moments. For more information regarding the WordPress loop, check out the WordPress Codex and 4 Ways to Loop with WordPress.

The Side Loops

As previously noted, the term “side loops” is a bit of a misnomer. Instead of the standard if():while() loop intro, the two secondary loops each begin with get_posts() and foreach():start_wp() statements. With such, the secondary loops function similar to standard loops, but employ a different functional method. As far as calling them “side” loops, well that is just a convenient name, as they may display posts anywhere, not just on the side of a web page.

Now, with the main loop in place, it is time to add the two side loops. Here is the basic setup:

// the second loop
<?php query_posts('cat=7&showposts=3'); ?>
<?php $posts = get_posts('category=7&numberposts=3&offset=0'); 
foreach ($posts as $post) : start_wp(); ?>
<?php the_title(); ?>
<?php the_excerpt(); ?>
<?php endforeach; ?>

// the third loop
<?php query_posts('cat=8&showposts=3'); ?>
<?php $posts = get_posts('category=8&numberposts=3&offset=0'); 
foreach ($posts as $post) : start_wp(); ?>
<?php the_title(); ?>
<?php the_excerpt(); ?>
<?php endforeach; ?>

Okay, in the previous example, the second loop is querying all posts in category 7 and displaying the first three, beginning with the most recent posts. The second post acts similarly, with the exception that it queries posts from category 8. Each loop also contains a title and excerpt element, included for the sake of demonstrative clarity.

Several important points should be mentioned here. For each of the two side loops, there are two parameters indicating category number, two parameters indicating the number of displayed posts, and one parameter indicating an offset value. For this triple-loop configuration to function properly, it is essential to provide matching parameters for both category and post display number. That is, the values cat=8&showposts=3 must correspond precisely to the values category=8&numberposts=3. Same category, same number of posts to display. Meanwhile, the offset parameter should remain at zero.

Thus, to customize the two secondary loops, simply choose two unique category ID’s and corresponding values specifying how many posts from either category you wish to display.

All Together Now

Now that I have bored you nearly to death with all of the gruesome details, here is the complete code for the Perishable Press triple loop for WordPress:

// the first loop
<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
<?php if ( in_category('7') && is_home() ) continue; ?>
<?php if ( in_category('8') && is_home() ) continue; ?>
<?php the_title(); ?>
<?php the_content(); ?>
<?php comments_template(); ?>
<?php endwhile; ?>
<?php posts_nav_link('','','&laquo; Previous') ?><?php previous_post('&laquo; %', '', 'yes'); ?>
<?php posts_nav_link('','Next &raquo;','') ?><?php next_post('% &raquo;', '', 'yes'); ?>
<?php else : ?>
<p>Sorry..</p>
<?php endif; ?>

// the second loop
<?php query_posts('cat=7&showposts=3'); ?>
<?php $posts = get_posts('category=7&numberposts=3&offset=0'); 
foreach ($posts as $post) : start_wp(); ?>
<?php the_title(); ?>
<?php the_excerpt(); ?>
<?php endforeach; ?>

// the third loop
<?php query_posts('cat=8&showposts=3'); ?>
<?php $posts = get_posts('category=8&numberposts=3&offset=0'); 
foreach ($posts as $post) : start_wp(); ?>
<?php the_title(); ?>
<?php the_excerpt(); ?>
<?php endforeach; ?>

That’s all there is to it — copy, paste, and tweak to taste!

Caveat

As previously discussed, the main loop will look at the first “x” number of posts, and display only those posts which are not included in either side-loop category. Thus, if the most recent “x” number of posts all belong to either of the side categories, there will be no posts to display in the main loop. Fortunately, there are several relatively simple solutions for this situation:

  1. Increase the number of posts that are displayed in the main loop via the Admin > Options > Reading panel.
  2. Decrease the number of posts that are displayed in the side loops via step 5a and 5b in the Installation instructions above.
  3. Simply add a few more (or however many it takes) posts to categories appearing in the main loop (i.e., non-side-loop categories).

A Million Loops

With a little imagination, it is easy to envision a case where more than three loops might be required. Fortunately, our method for dishing three WordPress loops may be extrapolated into four WordPress loops, five WordPress, loops, six WordPress loops, …even a million WordPress loops. Well, okay, maybe not. Nonetheless, for any reasonable number of loops, if you have the categories, we have the code!

Here is a hypothetical, generalized example demonstrating “n” number of WordPress loops:

// the first loop
<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
<?php if ( in_category('2') && is_home() ) continue; ?>
<?php if ( in_category('3') && is_home() ) continue; ?>
<?php if ( in_category('4') && is_home() ) continue; ?>
<?php if ( in_category('5') && is_home() ) continue; ?>
.                .      .         .            .
.                .      .         .            .
.                .      .         .            .
<?php if ( in_category('n') && is_home() ) continue; ?>
<?php the_title(); ?>
<?php the_content(); ?>
<?php endwhile; ?>
<?php else : ?>
<?php endif; ?>

// the second loop
<?php query_posts('cat=2&showposts=3'); ?>
<?php $posts = get_posts('category=2&numberposts=3&offset=0'); 
foreach ($posts as $post) : start_wp(); ?>
<?php the_title(); ?>
<?php the_excerpt(); ?>
<?php endforeach; ?>

// the third loop
<?php query_posts('cat=3&showposts=3'); ?>
<?php $posts = get_posts('category=3&numberposts=3&offset=0'); 
foreach ($posts as $post) : start_wp(); ?>
<?php the_title(); ?>
<?php the_excerpt(); ?>
<?php endforeach; ?>

// the fourth loop
<?php query_posts('cat=4&showposts=3'); ?>
<?php $posts = get_posts('category=4&numberposts=3&offset=0'); 
foreach ($posts as $post) : start_wp(); ?>
<?php the_title(); ?>
<?php the_excerpt(); ?>
<?php endforeach; ?>

// the fifth loop
<?php query_posts('cat=5&showposts=3'); ?>
<?php $posts = get_posts('category=5&numberposts=3&offset=0'); 
foreach ($posts as $post) : start_wp(); ?>
<?php the_title(); ?>
<?php the_excerpt(); ?>
<?php endforeach; ?>
.     .     .     
.     .     . 
.     .     . 
// the nth loop
<?php query_posts('cat=n&showposts=3'); ?>
<?php $posts = get_posts('category=n&numberposts=3&offset=0'); 
foreach ($posts as $post) : start_wp(); ?>
<?php the_title(); ?>
<?php the_excerpt(); ?>
<?php endforeach; ?>

Well, surely I have worn out my welcome here. Perhaps you will be so kind as to drop a comment to share your particular experience with multiple WordPress loops. Cheers!

Jeff Starr
About the Author Jeff Starr = Web Developer. Security Specialist. WordPress Buff.
Archives
50 responses
  1. That’s very interesting.

    In my old blog (WP 2.0.5), I just created a WP page and slapped the php into the WP page and let EXEC-PHP handle it. Worked fine.

    But definitely not working in the new blog (WP 2.1.2). Frankly, it didn’t occur to me put it in the code of the page itself especially since it worked it in the text of the WP page.

    I’ll try it.

    (I don’t have shell access and so am waiting for my host to help me restore to WP 2.1.2 since something went awry in an attempted upgrade to 2.3. But can hardly wait to try it.)

  2. Jeff Starr

    Danny,

    Okay, the reason I ask is because I am not sure that WordPress loops will run properly (or at all) when executed via a plugin such as Exec-PHP. The post itself is already being processed within a loop, and I am not certain that execution of a “loop within a loop” is possible. Have you tried running the additional/side loops directly from within the index.php (or other) file? Sorry if I am assuming too much here, I am only trying to help. ;)

    Jeff

  3. Early signs for me are that it works as expected when put into the code of a page as you suggested (and intended). I was trying to get it to do something that it was not intended to do, and I so very much appreciate you helping me get straightened out.

    This could be really sweet… thank you so very much.

  4. Jeff Starr

    You’re welcome!

    It is interesting that you managed to get a secondary loop to run via EXEC-PHP in WordPress 2.0.5. I wonder if that is an anomaly in that version of WordPress that was fixed in subsequent versions. Regardless, I think it is more secure/stable to run the loop directly via .php document rather than through a page or post.

    In any case, I am glad to hear that you got it working.
    Best of luck to you and your blog ;)

  5. I have the multiple loops working perfectly on a test blog on my workstation server, with no repeating of posts in the main blog area, however I’ve just taken the whole thing live and the posts in select categories do show up in the highlighted sections as desired, but they are repeating in the content area of the blog. Any suggestions would be much appreciated.

    http://www.article6blog.com/

    Arthur

  6. Doah!!! Never mind — forgot to change the category numbers in the main index template. Now it’s working fine.

  7. Hi, just a question and please sorry for my english :P

    What about excluding from the side loops just the post (and not the category) displayed in the main loop?
    Obviously while still assigning a category for each side loop.

  8. Jeff Starr

    @Arthur: Glad to hear you got it working!

    @hedgehog: I have yet to venture into those waters, however, you may want to try experimenting with the built-in private posts feature. If that doesn’t provide any clues, you may try cannibalizing code from a plugin that deals with individual post filtering, such as static front page or something.. Sorry if that wasn’t very helpful — hopefully it will provide a few leads to follow. Good luck!

  9. Luke Knowles December 18, 2007 @ 4:47 pm

    This is a great tutorial. One question. How do I order the posts alphabetically by the title for the second loop? Thanks for your help on this.

  10. Jeff Starr

    Hi Luke,

    To do this via plain code injection (per category view):

    <?php if (is_category()) { $posts = query_posts($query_string . '&orderby=title&order=asc'); } ?>

    Or, throw down via WP plugin:

    1. Custom Query String Reloaded (extra phat, very flexible)
    2. Sort Category Posts by Title (exactly what it says)
    3. WP-Snap Plugin (auto-listed, alphabetic posts)
    4. Smart Sort WordPress Plugin (sort posts by custom field)
    5. aStickyPostOrderER (customizable post organization)

    That should get you started. Great site, btw — read on it earlier today via WPThemesPlugin.com :)

    Regards,
    Jeff_

  11. I have several loops working on the blog, article6blog.com. On one of them there is a box that features the title of the most recent post in a certain category, along with that post’s Optional Excerpt info, and then below that are the titles of the five most recent posts from the same category. As it now stands, the most recent post’s title gets repeated in that secondary list area. Is it possible to call for the list of (x) most recent posts but have the actual most recent one skipped?

    Thanks in advance for any advice.

  12. Jeff Starr

    Hi Authur,

    Have you tried using the offset parameter?

    For example, using this code in your secondary loop:

    <?php query_posts('cat=7&showposts=3&offset=1'); ?>

    You would skip the first post in category 7 and display the next 3 most recent..

[ Comments are closed for this post ]