4.1.1 Customizing the Loop As we mentioned in the previous chapter, if there is one thing that you need to understand to be a true badass theme developer, it is how the loop works and what you can do with it. With this as our mantra, let’s spend the first part of this chapter looking at how to do lots of different stuff with the Loop. To set the stage, a customized loop is going to have this structure: <?php // The Query - Customize! query_posts('showposts=5'); // The Loop if (have_posts()) : while (have_posts()) : the_post(); endwhile; else: endif; // Reset Query wp_reset_query(); ?> 87 Theme Design and Development 4 88 4.1.2 The Loop Doesn’t Care About Markup It’s true. Here is a pretty “normal” loop: <?php if (have_posts()) : while (have_posts()) : the_post(); ?> <div class="post" id="post-<?php the_ID(); ?>"> <h2><a href="<?php the_permalink(); ?>" rel="bookmark" title="Permanent Link to <?php the_title_attribute(); ?>"><?php the_ title(); ?></a></h2> <p class="meta">Posted on <?php the_time('F jS, Y'); ?></p> <?php the_content('Read More'); ?> <p><?php the_tags('Tags: ', ', ', '<br />'); ?> Posted in <?php the_category(', '); ?> | <?php edit_post_link('Edit', '', ' | '); ?> <?php comments_popup_link('No Comments »', '1 Comment »', '% Comments »'); ?></p> </div> <?php endwhile; ?> <?php next_posts_link('« Older Entries') ?> <?php previous_posts_link('Newer Entries »') ?> <?php else : ?> <h2>No Posts Found</h2> <?php endif; ?> And here is the same exact loop, only marked up as a simple ordered list: <?php if (have_posts()) : ?> <ol> <?php while (have_posts()) : the_post(); ?> 89 <li id="post-<?php the_ID(); ?>"> <strong><a href="<?php the_permalink(); ?>" rel="bookmark" title="Permanent Link to <?php the_title_attribute(); ?>"><?php the_ title(); ?></a></strong> <?php the_content('Read More'); ?> </li> <?php endwhile; ?> </ol> <?php else : ?> <h2>No Posts Found</h2> <?php endif; ?> And here it is again as a definition list: <?php if (have_posts()) : ?> <dl> <?php while (have_posts()) : the_post(); ?> <dt id="post-<?php the_ID(); ?>"> <a href="<?php the_permalink(); ?>" rel="bookmark" title="Permanent Link to <?php the_title_attribute(); ?>"><?php the_ title(); ?></a> </dt> <dd> <?php the_excerpt(); ?> </dd> <?php endwhile; ?> </dl> 90 <?php next_posts_link('« Older Entries'); ?> <?php previous_posts_link('Newer Entries »'); ?> <?php else : ?> <h2>No Posts Found</h2> <?php endif; ?> Notice that not only is the markup different in each of these different examples, but the functions we use are different as well. For example, the definition list example uses the_excerpt() instead of the_content(), which only displays a small portion of the entire content (assuming the main content of the Post is longer than 55 words, the default excerpt length). This might be more appropriate for, say, a loop in the sidebar showing recent posts. 4.1.3 The Power of query_posts A lot of the magic ahead is accomplished by using the query_posts function, which is definitely worth getting to know! To use it properly, you call it before the beginning of the loop, and specify the parameters you need to customize the perfect loop for your scenario. As we learned in section 3.4.3, every execution of the loop is based on a default query that changes according to the type of page being viewed, your settings, and so on. This default query is not set in stone, however, and may be overridden or modified by specifying your own query using the query_posts function. In many cases, you might want to preserve the original query and adjust only certain parts of it. To do so, simply call the function using the $query_string variable and then append additional parameters to the query string, like so: query_posts($query_string . '&showposts=6'); 91 Let’s look through some more tasty “recipes” for common things you might want to do with the loop. 4.1.4 Displaying Dierent Numbers of Posts There is a global setting in the Admin area for setting the number of Posts to display. On page 48, we talk about a plugin that allows more fine-grained control for this setting, but you can also control it directly through the loop itself. For example, here we are overriding the default number of posts to display: query_posts($query_string . '&showposts=6'); 4.1.5 Excluding Specific Categories One of the most common customization requests for WordPress is, “how do I prevent posts in a certain category from displaying on my home page?” Say you have a category about hamsters that, for whatever reason, you want to omit from the post loop on your home page. You still want hamsters content in your feeds, just not on your website. How would we do something like this? Although there are multiple ways to handle this request, the simplest solution is to be found in… yep, you guessed it, the query_posts function: query_posts($query_string . '&cat=-3'); In general, a dash (or minus sign, “-”) appearing before a parameter value signifies exclusion. Thus, here we are excluding category number three, which happens to be our hamsters category. When this code is placed before our loop, posts about hamsters will not be displayed. Other possible ways to exclude a category include using PHP’s “continue” function to advance the loop prematurely, hiding content with CSS or JavaScript, hacking the core, and using a plugin. Still, this method is the cleanest and most flexible. Overriding Parameters If the $query_string already contains a parameter (e.g. year) you can override it by passing that parameter again after it. NOT …on the Home Page. 92 4.1.6 Changing the Sort Order WordPress is sort of a LIFO application by default. That is, Last In First Out. It’s a smart default, because most blog-like sites like to show off their newest content first. This gives people a reason to return since they know the new stuff will be displayed up front and center. However, that might not be the ideal configuration for every site. Say you were using WordPress to write and present a novel. You were writing it and releasing it chronologically chapter by chapter. So when visitors came to your site, you want to show them Chapter One, but that is actually your oldest post, so it will be buried beneath the newer chapters. No problem, just reverse the sort order: query_posts('orderby=date&order=ASC'); 4.1.7 Show Specific Pages, Embed a Page within a Page Another interesting and useful loop trick is to use the query_posts function to display only one specific Page. This could be useful for a variety of reasons, including a situation where you needed to embed the contents of one Page within another Page. Here is how to do it: <?php query_posts('pagename=about'); // retrieves the about page only ?> 4.1.8 Using Multiple Loops There is nothing holding you to using only one loop. You can have as many loops as you’d like! In fact, it’s fairly common to have multiple loops going in a theme. A simple example would be a homepage that shows the full content of the newest three posts. But then in the sidebar, there is second loop which shows the title and date of the next seven posts after that. Nothing wrong with it, works just fine. Let’s look at a more complex example. Let’s say we have some fancy four-column theme. We have a left sidebar where we want to show a list of posts only from the pagename=about Note that the pagename value used here refers to the actual slug for the page. See Chapter 2.3.5 for help with slugs. 93 query_posts(array( 'cat': 7, 'posts_per_page': 3 )); Give me three posts from category seven query_posts(array( 'cat': -7, 'posts_per_page': 5 )); Give me ve posts not from category seven query_posts(array( 'cat': -7, 'offset': 5, 'posts_per_page': 5 )); Five more posts not from category seven (skip ve) query_posts(array( 'cat': -7, 'offset': 10, 'posts_per_page': 10 )); Ten more posts not from category seven (skip ten) 1 - Left Sidebar 2 - Main Left 3 - Main Right 4 - Right Sidebar “events” category. Then we have a main column, split into two, where we display the ten most recent posts in two columns of five each. Then in the right sidebar, we show another ten posts, beginning after the posts featured in the main column. For this setup, we are going to include four loops within the theme file(s) required to generate our fancy four-column page. For the sake of simplicity, we will say that all of these loops are contained within our index.php file, even though in practice the loops could be located in any combination of theme files. Now that our four loops are in place, we need to ensure they are going to deliver our carefully planned display of posts. If we were to simply plop down four default WordPress loops, our web page would display four columns, each containing the exact same posts. So, to massage our loops into shape, we turn again to the powerful query_posts function. As shown in the diagram at the top of this page, we add two or three (depending on the loop) parameters to each of our four query_posts functions. These parameters cause the following behavior: • The “cat” parameter Loop 1 - display posts only from category seven Loop 2 - display posts not from category seven Loop 3 - display posts not from category seven Loop 4 - display posts not from category seven 94 • The “posts_per_page” parameter Loop 1 - display only three posts Loop 2 - display only five posts Loop 3 - display only five posts Loop 4 - display only ten posts • The “offset” parameter Loop 1 - (not used) Loop 2 - (not used) Loop 3 - skip the first five posts Loop 4 - skip the first ten posts At this point, the loops have each been modified to display the desired posts. The only other thing to consider before calling it a night is whether or not we want to display post navigation links for one of our loops. In a single-loop setup, we can use the posts_nav_link() template tag to display post navigation links on our home, index, category, and archive pages. Such navigation links would enable visitors to check out previous or more recent posts, depending on page view. If we don’t need to display the post-navigation links, such as would be the case in a “magazine-style” theme, then our work here is finished. If, on the other hand, we do want the navigation links for one of our loops, the query_posts function will be insufficient to get the job done. In our current loop setup, query_posts will override the default posts object query, making it impossible for posts_nav_link to show the next series of posts. The key to restoring proper post pagination when using multiple loops is to preserve the paged offset parameter of our default posts query. There are several ways to do this, but the easiest is to simply redefine the $posts variable by appending our custom parameters onto the original query. This is done as follows: <?php $posts = query_posts($query_string.'&cat=-7&posts_per_page=5'); ?> Now we can restore post pagination by using this new query to replace one of the four query_posts functions currently in place. The loop that will be modified by this WP Page Navigation For a denitive guide to WordPress page navigation, check out Digging into WordPress: http://digwp.com/u/401 Multiple & Custom Loops At Perishable Press, one of my specialties is the WordPress Loop. If you are looking for more in-depth information on creating and using multiple & custom loops, scan through the library of articles in the “loop" tag archive: http://digwp.com/u/402 95 new query is the one that will be equipped to use the navigation links generated by the posts_nav_link function. Because our new query is already set up for our second, main-left loop, we will go ahead and choose that loop for our navigation links. Thus, after implementing our new query for the second loop, our fancy four- loop functionality will employ the following code (simplified for clarity): <?php query_posts('cat=7&posts_per_page=3'); if (have_posts()) : while (have_posts()) : the_post(); the_content(); endwhile; endif; ?> <?php $posts = query_posts($query_string.'&cat=-7&posts_per_page=5'); if (have_posts()) : while (have_posts()) : the_post(); the_content(); endwhile; posts_nav_link(); endif; ?> <?php query_posts('cat=-7&posts_per_page=5&offset=5'); if (have_posts()) : while (have_posts()) : the_post(); the_content(); endwhile; endif; ?> <?php query_posts('cat=-7&posts_per_page=10&offset=10'); if (have_posts()) : while (have_posts()) : the_post(); the_content(); endwhile; endif; ?> Now that is a thing of beauty. If using this PHP template to implement your own loops, you will need to use some (X)HMTL and additional template tags to flesh Loop 1 - Left Sidebar Normal loop using query_posts to display only three posts from category seven. Loop 2 - Main Left Normal loop using a custom query_posts for the value of the $posts variable. Here we are displaying ve posts not from category seven, and then including some post navigation using the posts_nav_link tag. Loop 3 - Right Main Normal loop using query_ posts to display ve more posts not from category seven. We also use an offset parameter to avoid post duplication. Loop 4 - Right Sidebar Normal loop using query_ posts to display ten more posts not from category seven. Again, the offset parameter is used to avoid duplication of posts. 96 things out and display the relevant post information, such as the title, date, author, and so on. The key thing is getting the multiple-loop functionality working with page navigation, and this template will take care of you in that department. 4.2.1 Sidebars and Footers Sidebars and footers are such ubiquitous design elements that there are special functions for calling them, just like the header. Let’s take an example like this: Ah, notice the two sidebars? That is an excellent way of presenting lots of information to your visitors. Here’s how it’s done… 4.2.2 Multiple Sidebars The code for creating a layout like the one shown above would look something like this: Header Footer Main Content Left Sidebar Right Sidebar . Loop 1 - display only three posts Loop 2 - display only five posts Loop 3 - display only five posts Loop 4 - display only ten posts • The “offset” parameter Loop 1 - (not used) Loop 2 - (not. 'cat': -7 , 'offset': 10, 'posts_per_page': 10 )); Ten more posts not from category seven (skip ten) 1 - Left Sidebar 2 - Main Left 3 - Main Right 4 - Right Sidebar “events”. “cat” parameter Loop 1 - display posts only from category seven Loop 2 - display posts not from category seven Loop 3 - display posts not from category seven Loop 4 - display posts not from