Mastering the WordPress Loop

The WordPress Loop is one of the key structures in any WordPress blog. It is used to control which posts are shown on each and every one of your blog pages.

In addition, it is also used extensively on your WordPress Dashboard. For example, when you click on Posts on the left navigation bar, a list of your most recently created posts are shown using the WordPress loop. This is also true of Media, Pages, Links, Comments, and much more.

A good understanding of the WordPress Loop is necessary if you want to manipulate not only how and which posts are shown on your blog, but also how and which objects are shown on your WordPress Administration screens.

The WordPress Loop

The WordPress Loop is established by calling the wp() function.

This function does the following –

  • init – Sets up the current user.
  • parse_request – Sets up the proper query arguments.
  • send_headers – Send additional HTTP headers to enable caching, content type, etc.
  • query_posts – Execute the WordPress query and retrieve all objects for the WordPress Looop. Results for the wordpress loop query are stored in the $wp_query and $wp_the_query global variables.
  • handle_404 – If nothing is retrieved from query_posts, then set headers for 404 file not found error.
  • register_globals – Populate blog global variables including $posts, $post, $request, and $query_string with results from query_posts.

The parse_request function is particularly powerful because this is where rewrite rules are parsed and the query arguments of which objects to fetch get filled in. By hooking into the parse_request function you can achieve some very interesting effects with your blog.

Create a Custom Post Type Blog

In my Blog Art site, I converted my main blog objects to galleries instead of posts. The recent posts page shows a list of galleries, search retrieves gallery objects, the archive and category pages show gallery archives and categories, and the blog feed delivers the most recent galleries.

This is achieved by using the request hook which gets run at the end of the parse_request function.

add_filter('request', 'blog_art_request');  // parse_request function

function blog_art_request($q) {
	if (is_admin()) return;

	if (!empty($q) && !isset($q['p']) && !isset($q['page_id']) && !isset($q['name']) && !isset($q['pagename']) && !isset($q['post_type']))
		$q['post_type'] = 'gallery';
	return $q;

Line 1 – Use the request filter to hook into the parse_request function and change the WordPress Loop query arguments.

Line 4 – Only change the WordPress Loop for non-administration pages, i.e. only for site pages.

Lines 6-7 – Change the default post type from post to gallery.

The code above only changes the results of the WordPress Loop. We may also want to change our blog archive and category links so that they show number of galleries instead of number of posts. These functions are not based on the WordPress Loop so we must further hook into each of these functions.

Below we give an example of how to hook into our blog archive links.

add_filter('getarchives_where', 'blog_art_archive', 10, 2);

function blog_art_archive($where, $r) {
   return str_replace("post_type = 'post'","post_type = 'gallery'",$where);

Order WordPress Posts, Pages and Custom Post Types

When we click on posts in our WordPress dashboard, we get a list of posts ordered by date. We get a similar menu when we click on Media, Links, Pages, Comments, and new custom post types.

In WordPress 3.0 and above, these administration tables are rendered using the WP_List_Table object. Posts and custom post type tables are rendered using the WP_Posts_Table object which is an extension of the WP_List_Table object. Similarly media objects are handled by WP_Media_Table, user objects by WP_Users_Table, and so on.

Posts, Pages, Media, and custom post type tables get populated using the WordPress Loop (The WordPress Loop is called from the prepare_items function within WP_List_Table). Therefore, we can change how these tables are displayed by hooking into the WordPress Loop.

In particular, the WordPress Loop query for these tables look like this –

Array ( [order] => DESC 
        [orderby] => date 
        [post_type] => post 
        [posts_per_page] => 20 )

You can change the order of the table elements by modifying the order and orderby arguments.

add_filter('request', 'my_blog_request');  // parse_request function

function my_blog_request($q) {
	if (!is_admin()) return;
        $q['order'] = 'ASC';
	return $q;

The code above changes the order of all administration tables rendered using the WordPress Loop including Posts, Pages, Media and all custom post types.

If we want to limit the ordering to a particular post_type, then we can do the following –

function my_blog_request($q) {
	if (!is_admin()) return;
        if ($q['post_type'] == 'post') {
		$q['order'] = 'ASC';
		$q['orderby'] = 'title';
	return $q;

Valid ‘order’ and ‘orderby’ parameters can be found in the WordPress Codex query_posts page.

Mastering the WordPress Loop

The examples above illustrate the power of the WordPress Loop. By making small changes to the parse_request query, we can achieve useful and sometimes far-ranging results in our WordPress website.

There is much more that you can do with the WordPress Loop so explore your creative side and have some fun!

Related Articles


  1. says

    I came here from your posts on CPT permalinks and was wondering how I can use the request filter to successfully make a CPT slug into %author% *without* adding a static prefix (like your example in part 2 of your series). When I remove the static prefix from your example my CPTs work as expected, but my default post types resolve to 404s.

    Any suggestion or an example would be much appreciated. Thank you!

  2. says

    Great post … well written and some of _List class information makes more sense.

    Do you know how to add meta data (custom fields) to the results in each row?

    For example, get_post_meta(myid, my_custom_field);

  3. Nico says

    All right, I change the way the function is executed to :
    function my_blog_request($q) {
    global $pagenow;
    if ( $pagenow == ‘edit.php’ && $q[‘post_type’] == ‘soy-festival’ ) {
    $q[‘order’] = ‘DESC’;
    return $q;
    And now it works without any warning 🙂

  4. Nico says

    In previous versions of WP, I was using the “manage_pages_query” filter but I saw that it’s no longer supported.
    So I’m trying your solution with the “request” filter but I have an PHP warning on front end when using it :
    The first argument should be an array in …/wp-includes/classes.php on line 395

    DO you have an idea of what’s going wrong ?

Leave a Reply

Your email address will not be published.