How to use the Thesis Custom Loop API

by Alderete on January 17, 2011

In the latest release of the Thesis theme for WordPress a new feature for advanced theme customization was added called the Thesis Custom Loop API. The Thesis User’s Guide explains the basics of how to use the Custom Loop API. This article expands on that documentation, offering additional context to explain what the Custom Loop API is, what it’s good for, and examples of how to use it.

Wait! There’s more! I’ve written a follow-up to this article, Thesis Custom Loop Starter Template, which provides a complete custom loop class ready for you to customize, along with useful helper methods and additional explanations.

A Bit of WordPress and Thesis Background

To understand what the Thesis Custom Loop is, we need to take a step back, and look at just WordPress. Setting aside plugins for a moment, before the Thesis theme, there was only one way to alter the HTML and contents of your site’s theme: hack away on the theme files themselves. And once you started hacking on your copy of a theme’s files, it became a real challenge to update to a newer version of that theme.

Among other innovations, the Thesis theme made it possible to customize the theme extensively without altering the theme’s files. By isolating theme customizations into a few files in the thesis/custom directory, it became easy, almost trivial to update to newer versions of the theme. (These days child theme functionality is built into WordPress, but it works differently than Thesis, overriding theme files directly, rather than with an API, so it’s not relevant here.)

Thesis achieved this by moving the vast majority of the theme’s code out of standard WordPress theme files and into libraries and classes in the Thesis core code, and weaving into it the Thesis API—the hooks and filters we know and love.

With Thesis, you don’t hack away on the theme files, because there is nothing there. (Check out the thesis/index.php file, it has one line of code.) Instead of altering the HTML and WordPress Loop code directly, you use the hooks and filters to re-order, remove, or alter the various pieces of the Thesis HTML, post content, metadata about those posts (tags, categories, author, etc.), and so on.

What is the Thesis Custom Loop API?

If you have worked with Thesis much, at this point you’re thinking “I know all this, but what does it have to do with the Custom Loop API?”

Standard WordPress theme files don’t merely contain HTML and content tags, they also contain The Loop. The Loop is the heart of WordPress output, and it is how WordPress acquires, processes, and iterates through a set of posts (or pages, etc.) to convert them from database table rows to e.g. your blog’s home page.

When Thesis moved the contents of theme files from the files themselves to functions and classes inside Thesis, it also moved The Loop. While you can use hooks and filters to alter the HTML that Thesis generates when processing The Loop, before Thesis 1.8 there was no (good) way to use anything but a standard WordPress Loop on a Thesis site.

The Thesis Custom Loop API opens that up again. A cynic might say it just returns a built-in WordPress feature that was taken away by earlier versions of Thesis, but actually the Thesis Custom Loop can be a much cleaner way to work with The Loop. We’ll see how in a bit.

The Loop Inside the Custom Loop API

The WordPress Codex has a solid introduction to The Loop and developer details including multiple examples, which explain what the WordPress Loop is, and why and how a WordPress developer might want to modify it. Kristarella.com also has a great take on WordPress Loops. Since the Custom Loop API is simply the Thesis way to affect The Loop, at some point you will want to read these docs carefully, especially to achieve advanced customizations.

To explore the Thesis Custom Loop API we can use a simplified version of what happens during a request to a WordPress blog (ignoring initialization, error conditions, and other distractions):

  1. Parse the URL requested into a set of query conditions and variable settings.
  2. Run the query against the database.
  3. Turn the database results into a structured list of posts.
  4. Pick out the appropriate theme file (index, category, author, etc.), and turn control over to it.
  5. The theme file runs The Loop to convert the list of posts into HTML.

To simplify it even further, you can think of it this way:

  1. Get some posts.
  2. Process the posts into HTML. (Technically, only this second part is The Loop.)

The HTML generated by The Loop affects each item processed by The Loop, whether that is a collection of posts, e.g. for the blog index or an archive page, a single item, e.g. for a static page or individual post, or (in rare situations) no items at all. All of the HTML generated is placed inside the Thesis #content div, i.e.:

1
2
3
4
5
<!-- [...] -->
<div id="content">
    (The Loop output goes here.)
</div>
<!-- [...] -->

Why Play with the Loop?

With all that background under our belts, it shouldn’t be hard to think of reasons why you might want to alter, extend, or replace the standard WordPress Loop, to create pages which are significantly different from standard WordPress or Thesis versions. The most obvious thing to do is to alter the set of posts that are retrieved from the database. Possibilities include:

  • Alter the sort order of the posts, e.g., to sort teasers alphabetically.
  • Show posts only from certain categories, e.g., shared link items or featured posts.
  • Exclude posts from certain categories, e.g., your archived tweets auto-created by Twitter Tools.
  • Do any of these for specific tags, authors, post custom fields, etc.

Another thing you can do by altering The Loop is to affect output, but only when displaying certain pages. For example, you might want to:

  • Start a page (the Home page, a certain Category page, or any specific static page) off with some static content, and then display a list of posts.
  • Add a list of posts to an existing static page.
  • Treat custom post type or custom taxonomy archive pages differently than “standard” pages.
  • Create a custom Authors page.

And then there are times when you want to customize the HTML for a page beyond what’s available via hooks and filters. That should be rare, but with the Custom Loop API, you can completely replace the HTML output for the #content div of any page.

Getting Started: A Simple Custom Loop

Here is possibly the simplest Custom Loop that actually does something useful (put this in your thesis/custom/custom_functions.php file):

1
2
3
4
5
6
7
8
9
10
class tlooper extends thesis_custom_loop {
 
	function home() {
		global $query_string;
		query_posts($query_string . "&orderby=title&order=ASC");
		thesis_loop::home();
	}
 
}
$the_looper = new tlooper;

This Custom Loop changes the sort order for the home page, to sort by post title, instead of by date. (Why is this useful? Image a site that lists books or movies, you may not care about when a title was added to the site, you just want to look alphabetically. At any rate, it was requested in the Thesis Support Forum.)

It also illustrates the fundamentals of creating your own Custom Loop. First, there is the essential structure:

  1. Lines 1-9 define a new Custom Loop class, which extends the thesis_custom_loop class.
  2. Within the class, lines 3-7 define a function to be used for the loop to be changed, in this case, the loop for the home page.
  3. Line 10 creates a new instance of this class, which is the “trigger” that tells Thesis to actually use it.

This structure of: a class that extends thesis_custom_loop; one or more loop functions, and; activation by instantiating the class, is pretty much the whole Custom Loop API. Indeed, the class definition and instantiation are each one line, and they are dead simple. All of the complexity of creating Custom Loops will be in the loop functions—and they don’t have to be that complicated.

Let’s look at this simple loop function again, line-by-line:

1
2
3
4
5
function home() {
	global $query_string;
	query_posts($query_string . "&orderby=title&order=ASC");
	thesis_loop::home();
}
  1. The function signature. Two things to note. First, there are no parameters. None of the Custom Loop functions take parameters; any request params or WordPress variables or settings you might want to access must be brought in from the global scope. Second, the method name is one of 16 defined in the Custom Loop API (see the API Reference section below for specifics). Each one represents a request type (home, post, archives, category, etc.) for which you can override the loop definition. More on this below.

  2. Bring the variable $query_string into scope. $query_string is a WordPress global variable, which contains the query string portion of the URL requested, i.e., everything after the “?” in the URL.

  3. Run the query for posts, with two new parameters added to the query string. query_posts() is a WordPress function that runs the database query and puts the results in a WordPress global variable for use inside The Loop. When called with parameters, the new parameters override whatever WordPress parsed out of the request URL. Here, appending the new parameters to the existing query string preserves any other query parameters that might already exist.

  4. Call the default Thesis HTML output loop for the home page (this is basically just a call to the superclass). This turns control back over to Thesis to handle the conversion of database results into HTML.

To go back to our ultra-simplified explanation of what happens in The Loop…

  1. Get some posts.
  2. Process the posts into HTML.

…this Custom Loop only affects #1, and leaves #2 unchanged. Processing the posts into HTML can be a lot of work, so it’s really cool that Thesis lets you skip that part, if the default HTML is fine. (Traditional WordPress themes don’t allow you to skip that part.)

This example is extremely simple, but it’s a great model for any situation where you just want to change the query that gathers the posts to display on a page. You only have to change one line to change the query. To offer a few variations on this initial theme, here are a few more useful query-only custom loops:

Order by the number of comments on the post, most comments to least:

1
2
3
4
5
function home() {
	global $query_string;
	query_posts($query_string . "&orderby=comment_count&order=DESC");
	thesis_loop::home();
}

Show only posts from certain categories:

1
2
3
4
5
function home() {
	global $query_string;
	query_posts($query_string . "&cat=3,4");
	thesis_loop::home();
}

Exclude posts from certain categories:

1
2
3
4
5
function home() {
	global $query_string;
	query_posts($query_string . "&cat=-1,-14");
	thesis_loop::home();
}

Show posts by a specific author with a specific tag:

1
2
3
4
5
function home() {
	global $query_string;
	query_posts($query_string . "&author_name=Twain&tag=american");
	thesis_loop::home();
}

See the WordPress Codex page on query_posts() for more documentation on the various parameters you can use to affect the query, there is a lot you can do here.

A More Complex Loop: Make A Page “Special”

Here’s the scenario: We have a site where we’re posting a selection of books from Project Gutenberg. Our site has three categories: fiction, non-fiction, and announcements. The first two are for the books, the third is for notifications for site visitors.

So, on the category archive pages for books, we want to list posts in alphabetical order by title. For the announcements, we want a date order. Additionally, we want to format the two different kinds of items, well, differently.

Here’s a custom category() loop method that handles this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
function category() {
 
	if(is_category('Announcements')) {
 
		// Default sort order (by date) is correct
		// But we want to change the HTML output
 
		// This creates standard Thesis HTML content blocks that 
		// will automatically pick up Thesis styles
		thesis_archive_intro();
		echo '<div class="post_box top">' . "\n";
		echo '  <div class="format_text">' . "\n";
		echo '    <ul class="system_announcements">' . "\n";
 
		// Here's an actual WordPress Loop!
		while(have_posts()) { // This is standard WordPress
			the_post(); // Standard WordPress, sets up global variables
 
			// Output our notices with custom HTML
			echo '      <li><strong><a href="' . get_permalink() . '">' . 
			     get_the_title() . '</a></strong> &mdash; ' . 
			     get_the_time(get_option('date_format')) . "<br />\n" .
			     get_the_content() . "</li>\n";
		}
 
		// This closes the HTML blocks we opened
		echo "    </ul>\n";
		echo "  </div>\n";
		echo "</div>\n";
	}
	else { // For all other categories
 
		// Change the sort order to title, alpha order
		global $query_string;
		query_posts($query_string . "&orderby=title&order=ASC");
 
		// But we're happy with the default HTML output, so delegate the rest
		thesis_loop::category();
	}
}

Here are a few interesting points about this example:

  • First, this is just the loop method; you need to put this inside a thesis_custom_loop class for it to work. See the first example for the full structure.

  • This loop is divided into two sections by the if statement on line 3. The first section (lines 4-30) runs if the requested category is “Announcements”, and the second section (the else block on lines 31-39) runs for the other categories. is_category() is a standard WordPress function.

  • When the category is Announcements, we want the default WordPress sort order, which is by date, most recent to least recent. So, we don’t need to modify the query.

  • Line 10 uses a Thesis function to output the introduction block for this archive category. This is the headline, and the intro description for the category if you entered one in Posts > Categories > Introductory Content.

  • Lines 11-13 output some basic HTML blocks, using Thesis classes that will pick up styles from Thesis automatically. How do you know what you should output? More on that in a bit.

  • Lines 16-17 are the start of The Loop, the standard WordPress version, which we are customizing. Note that it’s a slightly abbreviated version, we don’t need the standard if(have_posts()) test, because we wouldn’t be in this loop function if it failed. Thesis “pre-flights” the loop, that’s part of how it decides which Custom Loop function to run on any given request.

  • Lines 20-23 are our replacement for the built-in Thesis functions that output a post. Our version is much simpler than what Thesis does in the standard loop. It also doesn’t run hooks or filters, more on that below.

  • Finally, lines 32-38 are the else clause, running for all the other category archive pages. It should look very familiar, from the earlier examples.

How Do I Know What to Put in a Custom Loop?

While you may understand all of the code in the previous example, it may be a little mysterious how I came to write it. How did I know what Thesis HTML and classes to use? How did I know to use the thesis_archive_intro() function to start the page? How do you write a Custom Loop that will still invoke hooks and filters?

When working with a traditional WordPress theme, if you want to customize The Loop, you don’t have to start with a blank slate. The simplest way to get a jumpstart is to make a copy of the relevant theme file, move it into your child theme directory, and modify the code you find in your copied file.

Similarly, the easiest way to make a complex customization of a Thesis loop is to copy the code from the relevant Thesis loop, and paste it into your Custom Loop class. You can find all of the Thesis loops in thesis/lib/classes/loop.php. So, if you want to customize the archive() loop, copy the thesis_loop::archive() method from that file, and paste it into your implementation of thesis_custom_loop. Then start making changes.

Before you do this, though, a word of caution. Thesis is cleverly put together. Before you start hacking away at code you’ve copied out of loop.php it’s worth reading and understanding all of the code you find there. You will certainly learn things about how Thesis works, which will better equip you to make changes to those workings. More importantly, it will help you avoid pitfalls, and track down problems you may encounter.</word>

Add Posts to a Static Page

Here’s the scenario: We have a static page on our site where we would like to add a list of posts with a particular tag below the main page content. For example, perhaps you have a portfolio page that shows off some of your recent projects. Or maybe it’s a page that archives your tweets. In any event, the goal is to have the content of a static page display, and then have a blog-like index of posts below it, which is not your blog page.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
function page() {
	if(is_page('portfolio')) {
		// We need this query var to maintain paging through the list of posts
		$paged = $this->get_paged_param();
 
		// First, show the page's content
 
		// This is a stripped down version of the thesis_loop::page() method
		// Post image and comments removed; all hooks preserved
		while (have_posts()) { // Standard WordPress
			the_post(); // Standard WordPress
 
			thesis_hook_before_post_box();
			echo "\t\t\t<div class=\"post_box top\" id=\"post-" . 
				 get_the_ID() . "\">\n";
			thesis_hook_post_box_top();
			thesis_headline_area();
			echo "\t\t\t\t<div class=\"format_text\">\n";
			thesis_post_content();
			echo "\t\t\t\t</div>\n";
			thesis_hook_post_box_bottom();
			echo "\t\t\t</div>\n";
			thesis_hook_after_post_box();
		}
		wp_reset_query();
 
		// Now, show our list of posts (portfolio posts only)
 
		// Build a set of query arguments, and load in the new set of posts
		$portfolio_query_args = array(
			'paged' => $paged,
			'post_type' => 'post',
			'post_status' => 'publish',
			'tag' => 'portfolio',
		);
		query_posts($portfolio_query_args);
 
		// An initial container div, for CSS styling
		echo "\t\t\t<div class=\"portfolio\">\n";
 
		// Another WordPress loop, to output the portfolio posts
		// Note: this assumes adding proper images to portfolio items
		// And making it look good requires additional CSS styles in custom.css
		if(have_posts()) { while(have_posts()) {
			the_post();
			$post_image = thesis_post_image_info('thumb');				
 
			echo "\t\t\t\t<div class=\"folio_item post_box\" id=\"post-" . 
				 get_the_ID() . "\">";
			echo "\t\t\t\t\t" . $post_image['output'];
			echo "\t\t\t\t\t<h2><a href=\"" . get_permalink() . "\">" . 
				 get_the_title() . "</a></h2>\n";
			echo "\t\t\t\t\t<div class=\"format_text\">\n";
			echo get_the_excerpt();
			echo "\t\t\t\t\t</div>\n";
			echo "\t\t\t\t</div>\n";
		}} // end WordPress Loop (both if and while)
 
		// Close our portfolio container div
		echo "\t\t\t</div>\n";
	}
	else {
		thesis_loop::page();
	}
}
 
/* PRIVATE METHODS */
 
// Deal with an irritating inconsistency in WP 3.0.4 and earlier
private function get_paged_param() {
	if(is_front_page()) {
		$paged = (get_query_var('page') ? get_query_var('page') : 1);
	}
	else {
		$paged = (get_query_var('paged') ? get_query_var('paged') : 1);
	}
	return($paged);
}

Understanding this loop:

  • First of all, in spite of the length, you should recognize the basic structure. We have a simple “if this is the special page do something interesting, else just do the normal loop” structure. If you have a bunch of “special” pages on your site, this could get awkward. In that case, create private methods, one for each special page, and call those methods from a case statement in your actual custom loop method.

  • The next thing to notice is there are two WordPress Loops! The first one, lines 10-24, is there to display the page’s content. The second, lines 44-57, is for our list of portfolio posts.

  • Line 4 uses a private method to grab a request parameter for what screen of posts to display. That is, if you have more than 10 posts that should display here, preserving this parameter will give you working [Previous] and [Next] links to “page” through them.

    I put this in a separate method, shown on lines 70-78, because a WordPress inconsistency makes this more complicated than it should be. Also, (I believe) capturing the value needs to be done at the start of the method, before we re-run or reset the query.

  • Lines 10-24 are the first Loop, which should only have one item to process, the current static page. The interior of the loop is copy-and-pasted from the Thesis page loop, simplified to remove the Thesis image and WordPress comments elements that don’t necessarily fit on a portfolio page. All of the Thesis hook functions remain, which means that your custom hook functions will continue to run on this page. If that isn’t what you want, you can remove them here.

  • Line 25 resets the WordPress query object, in preparation for re-using it. This is just basic cleanup, but you need to do it if another query is going to be run on the page.

  • Lines 30-35 build up the parameters for our second query. This is a slightly different way of doing it than constructing a query string, as we did in earlier examples. Using an array is generally neater when you have a larger number of parameters, and makes it easier to modify or add to later.

  • Line 36 runs the query, putting the items found into the global $wp_query object for use in The Loop.

  • Line 39 adds a <div> to the page (line 60 closes it), to contain our portfolio items, and to add a CSS class to allow us to style the portfolio items differently from, say, teasers. (What CSS styling to use is an exercise for the reader, but it goes into your thesis/custom/custom.css file, the same as all of your theme style customizations.)

  • Lines 44-57 are the second WordPress Loop. This one is the full monty, because we need to handle the situation where there are no matching posts retrieved by query_posts(). For the most part this just outputs HTML with the relevant Thesis classes attached in the usual places, but does not call hooks or use the Thesis formatting methods, instead using the standard get_the_title() and get_the_excerpt() WordPress functions. Note that we do attach a portfolio-specific class ‘folio_item’ to the div containing the portfolio post HTML.

  • The one Thesis-specific item in this loop, beyond the CSS classes, is on line 46, where we retrieve the Thesis post image for the item, and then on line 50, where the image HTML is outputted. You can display the thumbnail instead of the full-size image by using thesis_post_image_info('thumb') instead of ‘image’.

Don’t let the length of this loop function or any seeming complexity discourage you. I built this loop up slowly, one piece at a time, until I had completed it. Start with a basic if/else or case statement, then add the first WordPress Loop structure with simple output, and then build that output up a line at a time. Then move on to the next piece of your customization. The first one will seem hard, and take a while, but do a couple of loops yourself, and you’ll be knocking them out like they’re nothing in no time. Really!

Thesis Custom Loop API Reference

There are a total of 16 different loops you can customize on your Thesis-equipped WordPress site. As explained above, you do this by writing functions inside your Custom Loop class. You can define each of these loop functions inside the same Custom Loop class—you only need one. (In theory you can create multiple Custom Loop classes, and have them all be active on the same site, but that’s needlessly complicated.)

Some of the 16 loops available through the Custom Loop API have a hierarchical relationship. That is, by default or with certain settings many of the loops delegate to a “parent” loop, and if you customize that parent loop, all of the child loops will be affected as well. In general, you want to customize the most specific loop that you can.

Additionally, each of the 16 loops has a method that delegates control to the corresponding standard Thesis loop, as described in the first loop example above. The method name is the same as the Custom Loop method name, in the form of thesis_loop::method_name().

Special Loops

These loops are unique in some way, mostly by not belonging to a group of related loops.

  • home()

    This is the loop for the site’s blog index page. In a default WordPress configuration, this is the site’s home or top-level index page. However, this can be changed to any static page, using Settings > Reading > Posts Page.

    Additionally, this loop is used by the archives loop (and all child loops) unless Thesis > Design Options > Display Options > Archives is set to Titles Only. If you customize this loop, you may need to also (un)customize $this->archive().

  • search()

    The loop that handles a search results page. By default it delegates displaying results to the $this->archive() loop if there are results, but merely shows a search form if there are no results. A custom search loop must handle both conditions.

  • fourohfour()

    The loop that handles the “404 Not Found” error page. This means that the URL requested does not correspond to any page.

    If you want to do something really clever when people try to reach a funky URL, this is the place, but if you just want to display a customized message, a search form, and maybe some popular posts, it’s probably easier to do it via the 404 hooks.

  • nothing()

    The loop that handles a page without any posts or pages. Different from the 404 page, it means that the requested URL maps to a legitimate page, but there is no post data to display. I think this should be rare.

Post Loops

These two loops handle individual posts. Calling this a “loop” is somewhat misleading, because in this context the query should only return one post to process.

  • single()

    The loop for displaying an individual post, i.e. the one-article-per-page view of a post.

  • attachment()delegates to $this->single()

    The loop for displaying an individual attachment, usually an image, on a post.

Page Loops

These two loops handle individual static pages. Again, calling this a “loop” is somewhat misleading, because in this context the query should only return one page to process.

  • page()

    The loop for static pages.

  • front()delegates to $this->page()

    The loop for a static front page configured in Settings > Reading > Front Page. Has no effect if no static front page is set.

Archive Loops

These loops handle archive-style pages. By default, all of these use the main archive() loop, which is not to be confused with a static archives page, as described in the Thesis User’s Guide article “Create and Customize an Archives Page”. In this case, the term “archive” is simply used generically.

  • archive()

    The default loop for all of the archive-style pages. Many Thesis display settings affect the formatting of archives pages, so be sure to start there, before resorting to a custom loop.

    Important: The archive() loop delegates to $this->home() unless Thesis > Design Options > Display Options > Archives is set to Titles Only.

  • category()delegates to $this->archive()

    The loop for category pages, that is, the page you see when you click a category link.

  • tag()delegates to $this->archive()

    The loop for tag pages. You probably guessed that.

  • tax()delegates to $this->archive()

    The loop for custom taxonomy pages. Only useful if you have defined a custom taxonomy.

  • author()delegates to $this->archive()

    The loop handling the display of a single author’s archive page.

  • year()delegates to $this->archive()

  • month()delegates to $this->archive()
  • day()delegates to $this->archive()

    I really think you can figure these last three out without my spelling it out for you. :-)

Wait! There’s even more! I’ve written a follow-up to this article, Thesis Custom Loop Starter Template, which provides a complete, functionally benign custom loop class, along with useful helper methods and additional explanations.

What Not to Use the Custom Loop API For

Thesis users got by without the Custom Loop API for quite some time, it was only added in the most recent version of Thesis. If affecting The Loop is so useful, how did people get along without this feature?

The answer is, many effects can be achieved using other features of Thesis, and indeed, before you begin writing a Custom Loop, it’s always worth investigating whether you can achieve the same end via a setting, or using Thesis hooks and filters. Customizations implemented with those mechanisms will require less maintenance in the long run, as they are more isolated from changes in WordPress or Thesis.

Here are a few things that people often want to do, where you might think you need to create a Custom Loop, along with links to articles or forum posts that show an easier way.

If you’re a Thesis developer, there are a lot of great articles and forum posts, so it’s always worth looking for answers before you start digging on your own. Start by reading the various articles about Thesis hooks, and then move onto specific techniques and solutions. Thesis is incredibly flexible, once you get to know it.

Credits, Resources, and Further Reading

I found the following articles useful while learning about the Thesis Custom Loop API, and some of my examples are inspired by code I found in them. If you really want to learn more about writing custom loops, these are great places to start.

The code presented here was developed and tested on a standard install of WordPress 3.0.4 with the Thesis Theme for WordPress 1.8. No plugins were activated.

{ 15 comments… read them below or add one }

Wendy January 18, 2011 at 10:45 am

Thank you for this very informative post. Your explanations and examples are exemplary.

Reply

Rick Anderson January 19, 2011 at 9:52 am

Michael – thanks for the very thorough article. I’m going to need to come back to it and re-read portions of it a few times before it entirely sinks in.

A couple of Questions –
1. You suggest explicitly brining $query_string into scope. Isn’t it automatically in scope when using query_posts()? I notice that the examples in the Thesis Loop API rtfm don’t include adding that. I ask this not to be argumentative but because I’ve recently discovered that my understanding of $query_string isn’t complete.

2. In your long example, why would you use 2 instances of query_posts and include all of that in the customized page loop? Why not simply attach a function with WP_query to the end of the post content?

3. Does the answer above have something to do with paging? I’ve spent what seems like hundreds of hours trying to get paging to work consistently with custom loops and with wp_query. Your private function looks very similar to code that I’ve used outside of the class structure.

Thanks again – I’ve bookmarked a couple of your posts on the DIY Forums.

Reply

Alderete January 19, 2011 at 3:17 pm

Hi Rick, and thanks for visiting! Your posts on the DIY Forums were highly influential on my article. In particular, I never would have gotten paging working correctly without them — that’s why the code looks so familiar — which is why it’s the second item in my credits. Honestly, your example there was more useful than the official API docs! :-)

Regarding your questions:

1. I was using a code snippet which (I believe) I found on the query_posts() function reference page in the WordPress Codex. At least, I find that idiom there.

2. & 3. That’s a great question, and I think the answer is long enough that it’s going to get its own blog post. Short version, I tried it multiple different ways, and only by re-using query_posts() — which the WordPress documentation specifically recommends against — was I able to preserve paging.

Medium answer, I believe that you need to use query_posts() last on whatever query you want to page through, whether that’s the query that normally comes up at that URL, or a custom query.

In my example, I didn’t need a customized query for the first loop, but that loop was only for the static page contents, one item, and didn’t require paging. But the portfolio listing did require paging, so I needed to (re-?) use query_posts() to get that to work.

Reply

Allen Snook February 12, 2011 at 7:37 pm

Thank you! This article really helped with a custom loop problem I was having for a client’s site. Thank you very much!

Reply

Adam February 25, 2011 at 2:37 am

This is the kind of example I’ve been looking for all morning!

One question though I’m using your Add Posts to a Static Page example – but is there a way to preserve the featured posts layout like I have on my main page? Any help would be greatly appreciated!

Reply

Alderete February 25, 2011 at 1:34 pm

@Adam: I’m not sure I understand what you’re asking here. If you have HTML you want to use, simply replace the tags from the example with your own. Beyond that advice, you’ll have to provide much more detail in your question, since I have no way of knowing how you have customized your site.

Reply

Adam February 25, 2011 at 1:46 pm

Sorry I wasn’t very clear :) I’m using the themes featured posts settings so that my posts appear in squares on the main posts page.

Like this:
http://techpatio.com/wp-content/uploads/thesis_featured_post_screenshot.png

I wondered if it was possible to maintain that squared layout when running the query instead of them being displayed line by line.

If not I shall spend the weekend messing about with it! Thanks again.

Reply

Alderete February 25, 2011 at 7:57 pm

@Adam. Hmmm. Well, my example creates a page that has just one static page, which then pulls in a list of secondary posts. The standard home() loop is going to pull in a set of 10 (by default) regular posts. Just to be clear, my example won’t affect the Home page at all, just the one specific static page.

What I think you’re asking for is to have those secondary posts be displayed as two-by-two teasers, instead of as a stream of posts. While you can mostly accomplish this using CSS alone, there are enough corner cases with very small or wide window sizes that the Home page uses extra HTML elements to ensure correct behavior. So the best way to do this for your custom loop would be to review the Home loop, as described in How Do I Know What to Put in a Custom Loop?, to understand the technique and find useful Thesis functions.

But the Home loop is a kind of complicated, at least until you’ve been hacking Thesis for a while. You probably don’t want to just copy it into your own custom loop as-is. So here’s the basic idea: before every odd post, open a <div class="teasers_box">, and after every even post, close that <div>. (There’s more if you want to call all the Thesis teaser hooks, etc., but that’s the basic idea.) That might look something like this (this snippet replaces lines 44-57 in my original example):

$post_count = 0; // NEW
if(have_posts()) { while(have_posts()) {
    the_post();
    $post_image = thesis_post_image_info('thumb');              
    $post_count++; //NEW
    
    if(($post_count % 2) == 1) echo "\t\t\t<div class=\"teasers_box\">\n"; // NEW
    echo "\t\t\t\t<div class=\"folio_item post_box\" id=\"post-" . 
         get_the_ID() . "\">";
    echo "\t\t\t\t\t" . $post_image['output'];
    echo "\t\t\t\t\t<h2><a href=\"" . get_permalink() . "\" rel="nofollow">" . 
         get_the_title() . "</a></h2>\n";
    echo "\t\t\t\t\t<div class=\"format_text\">\n";
    echo get_the_excerpt();
    echo "\t\t\t\t\t</div>\n";
    echo "\t\t\t\t</div>\n";
    if(($post_count % 2) == 0) echo "\t\t\t</div>\n"; // NEW
}} // end WordPress Loop (both if and while)

You may need to add some styles to your CSS file to tweak the display, but the new <div> wraps and groups each pair of posts, which should allow you to display them two-by-two.

HTH!

Reply

Joshua April 15, 2011 at 3:56 pm

I’m trying to create a separate category page that appears like the blog page (basically splitting the “news” category into a News page, with full posts that match the format of the blog page). I am using a static home page that is different from my blog page, as well.

I have already excluded the news category from my blog page, now I just need to create my custom page and have it display everything in the news category. I’ve almost got it, but I’m going at it from a different angle and can’t get the byline dates to work. So, I’m thinking that a custom loop API would be the thing.

I’m wondering if you can help me out. This is a great post, but it’s a little over my head. I get the custom loops, but I just need some direction as to how I go from a custom loop to making a category specific page that displays full posts in thesis.

Reply

Sean June 12, 2011 at 1:17 pm

Hey Alderete,

I have a question regarding this tutorial. I am trying to create a custom category loop for the category pages and show only the intro content on the 1st page, then on the paged pages not show it. The thing is on the main page I want to have the subcategories for that category with 5 posts shown in a UL (like now). Yet on the 2nd, 3rd, 4th etc pages I would like to show only 20 posts in a UL…

Right now, I have gotten so far as to have the intro content dissapear when is_paged and also have the list of posts in that category. So, for the main page I just need to add in the subcategory UL. Then on the second page, 3rd page, etc I would like the list of recent articles in that catty to be 20, rather than 5.

Here is the code I have created so far:

//CUSTOM CATEGORY LOOP//
$loopty_loop = new seans_loop;

class seans_loop extends thesis_custom_loop {
function category() {
if ( is_category() && !is_paged() ) {
thesis_archive_intro();
echo "\n";
echo "\t\n";
echo "Related Articles:";
echo "\t\t\n";
while (have_posts()) {
the_post();
echo "\t\t\t" . get_the_title() . "\n";
}
echo "\t\t\n";
echo "\t\n";
echo "\n";
}
if ( is_category() && is_paged() ) {
echo "\n";
echo "\t\n";
echo "Related Articles:";
echo "\t\t\n";
while (have_posts()) {
the_post();
echo "\t\t\t" . get_the_title() . "\n";
}
echo "\t\t\n";
echo "\t\n";
echo "\n";
}
}
}

Reply

Sean June 12, 2011 at 1:18 pm

I should add that I have tried using wp conditionals to do this but wasn’t successful. Also tried applying this tutorial at yoast for the subcategories:
http://yoast.com/showing-subcategories-on-wordpress-category-pages/

Reply

Mike Sweitzer-Beckman July 24, 2011 at 8:59 am

I’ve got some stuff going on in my loop that isn’t making much sense to me. It mostly has to do with my shortcomings in understanding the structure of the code, especially when I want multiple arguments.

What I want to do on this category page (http://fortunate.sweitman-solutions.com/category/resources/our-stories/) is sort the posts by subcategory name within this Our Stories category (there are several subs) and then by post title within those categories.

Below is my code … for some reason, it isn’t really doing anything I wanted – it’s showing unrelated categories (Articles & Brochures), it’s not showing more than 10 posts, etc. What am I doing wrong?

/* BEGIN MODIFY THE LOOP */
class tlooper extends thesis_custom_loop {

// Change display of Parents' Stories category
	
	function category() {
 
		if(is_category(13)) {
			// sort by category name and then by post title
			query_posts(array('cat'=>13, 'posts_per_page'=>-1, 'orderby'=>'category', 'order'=>'ASC'));
			
			// But we want to change the HTML output
 	
			// This creates standard Thesis HTML content blocks that 
			// will automatically pick up Thesis styles
			thesis_archive_intro();
			echo '' . "\n";
			echo '  ' . "\n";
			echo '    ' . "\n";
 
			// Here's an actual WordPress Loop!
			while(have_posts()) { // This is standard WordPress
				the_post(); // Standard WordPress, sets up global variables
 
				// Output the post titles and subcategory names, ordered by subcategory and then title with custom HTML
				$category = get_the_category();
				echo '      ' . 
				     get_the_title() . ' — ' .  
					 $category[0]->cat_name;
					 get_the_category(0) . "\n";
				}
 
			// This closes the HTML blocks we opened
			echo "    \n";
			echo "  \n";
			echo "\n";
		}
		
		else {
			 thesis_loop::category();
		}

	}
}
$the_looper = new tlooper;

Reply

Alderete July 24, 2011 at 1:10 pm

@Mike: Hmmm, that’s a nice use case! I mean, it’s a nice example to illustrate a more complex custom loop. I don’t have the time this weekend to do it justice, but here are a couple issues I see:

First, getting the sorting right is a little complicated. You can’t simply sort by the category, because what is the category for a post with multiple categories? There’s no “right” answer that works for every blog or category scheme, and so WordPress doesn’t really provide a solution here. You can sort by the field as you have done here, but results may not always be what you expect, or even the same from page load to page load.

There are a couple possible answers for making your posts sortable by category and sub-category. The simplest is to not sort in your `query_posts()` call, but instead write your own utility method that will sort the _results_ from `query_posts()`. That method can inspect each post in the results, and appropriately pull out and combine the sub-category and post title fields for sorting.

A second method, which would probably be more efficient if you’re dealing with a lot of posts, would be to add a custom field to your posts, which contains a sortable value (probably a concatenation of the sub-category and post title). If you write a hook method, you can have WordPress maintain this sortable field automatically. Then you just sort by this field in your `query_posts()` call.

Second, and more briefly, I think you probably want to create your own WP_Query, instead of using `query_posts()`. See my discussion about it in the Custom Loop template post for some background and links, but I think creating your own query object should work around the 10 posts limit.

HTH!

Reply

Katie September 18, 2011 at 11:53 am

I’m trying to create a page that also displays posts and this article has been extremely helpful. First I got a single page working where I supplied the page name and the category ID. Then I customized the function further so that I can pass the category ID from the page through a custom field and the function automatically runs the proper query. Now I want to use the category variable to determine whether or not to use the new page function in the first place. This way I won’t have to edit the function whenever my client wants to add a new hybrid page. He can just add the custom field/value and take care of it himself.

I’m not sure how to do this since I can’t test for the presence of the variable at the start of the custom page function. I have to get into the while loop, then test, and then break out of the custom page function altogether and call the regular Thesis page function. Your example uses an if/else construct to get out of the custom function and revert to the default function. Here’s what I have so far:

function page() {

// We need this query var to maintain paging through the list of posts
$paged = $this->get_paged_param();

// First, show the page’s content

// This is a stripped down version of the thesis_loop::page() method
// Post image and comments removed; all hooks preserved
while (have_posts()) { // Standard WordPress
the_post(); // Standard WordPress

// Get the category ID from a custom field on the page
global $post;
$postID = $post->ID;
$custom_cat = get_post_meta($postID, ‘custom_cat_page’,$single=true);

if ($custom_cat==null){
Somehow break out and run thesis_loop::page()
}

thesis_hook_before_post_box();
echo “\t\t\t\n”;
thesis_hook_post_box_top();
thesis_headline_area();
echo “\t\t\t\t\n”;
thesis_post_content();
echo “\t\t\t\t\n”;
thesis_hook_post_box_bottom();
echo “\t\t\t\n”;
thesis_hook_after_post_box();

}
wp_reset_query();

// Now, show our list of posts (portfolio posts only)

// Build a set of query arguments, and load in the new set of posts

$hybrid_query_args = array(
‘paged’ => $paged,
‘post_type’ => ‘post’,
‘post_status’ => ‘publish’,
‘cat’ => $custom_cat,
);
query_posts($hybrid_query_args);

// An initial container div, for CSS styling
echo “\t\t\t\n”;

// Another WordPress loop, to output the portfolio posts
// Note: this assumes adding proper images to portfolio items
// And making it look good requires additional CSS styles in custom.css
if(have_posts()) { while(have_posts()) {
the_post();
$post_image = thesis_post_image_info(‘thumb’);

echo “\t\t\t\t”;
echo “\t\t\t\t\t” .
get_the_title() . “
\n”;
echo “\t\t\t\t\t” . $post_image[‘output’];
echo “\t\t\t\t\t\n”;
echo get_the_excerpt();
echo “\t\t\t\t\t\n”;
echo “\t\t\t\t\n”;
}} // end WordPress Loop (both if and while)

// Close our portfolio container div
echo “\t\t\t\n”;

} //end function page()

Thanks in advance for the help. I’m not a coder and can run into trouble when customizing other people’s code.

Reply

Thomas November 7, 2011 at 2:00 pm

Thank you for a great explanation – I used it in a very simple form to alphabetically sort the posts in the category archive pages:

class tlooper extends thesis_custom_loop {
function category()
{
global $query_string;
query_posts($query_string . “&orderby=title&order=ASC”);
thesis_loop::category();
}
}
$the_looper = new tlooper;

My problem is that the script includes the category header (i.e. http://sovse.dk/category/marinader/) – do you have a proposal for a solution?

Regards
Thomas

Reply

Cancel reply

Leave a Comment

{ 3 trackbacks }