Search
Close this search box.
Search
Close this search box.

The WordPress Loop

while ( have_posts() ) : the_post();
    // do stuff here with each item that is found
endwhile;

Modify the WordPress Loop with pre_get_posts

Have you ever wanted to tweak what content WordPress served up on a particular portion of your website? Perhaps on your home page instead of the default 10 posts you only want to show 3 or maybe you want to exclude a particular category.

The way most people do it is by editing the WordPress loop in your themes template files. It’s usually done by adding a call to the query_posts function and a few arguments right before the while portion of the loop. There are a couple problems with this method though. It doesn’t support pagination and you have to edit every template file where you want to modify the query
This makes this method a poor choice. Lot’s of themes and plugins use pagination and it’s great way to navigate your posts. Why break it? Also, anytime you upgrade your theme you will overwrite your changes. You could just copy those templates into a child theme but if you are going to copy all the structure over to a child theme, it’s not really a child theme anymore.

So what if I told you there was a much easier and cleaner way of doing this?

With pre_get_posts you can modify the main query anywhere on your site without ever touching a single file within your theme and pagination will continue to work as expected. pre_get_posts is an action hook that is called after the query variable object is created, but before the actual query is run. This means your changes are directly to the object itself and not during run time which offers a lot more control and flexibility.

Here is a sample of how it works.

function modify_main_query($query) {
    if ($query->is_home() && $query->is_main_query()) {
        $query->query_vars['posts_per_page'] = 5; // // Show only 5 posts on the homepage only
    }
}
add_action('pre_get_posts', 'modify_main_query');

Pretty simple, right? Just place your own version of this code in a site functionality plugin or your child themes functions.php file and you’re done.

Display multiple post types, including custom post types:

 $args = array(
     'post_type' => array( 'post', 'page' ),
     'orderby' => 'menu_order',
     'cat' => 137,
     'posts_per_page' => -1
 );
query_posts( $args );
while ( have_posts() ) : the_post();
    // do stuff here with each item that is found
endwhile;

Options

Here are a few of the most common WP_Query options:

  • posts_per_page (int) – number of posts to show per page. Use -1 to show all posts.
  • order (string) – Designates the ascending or descending order of the ‘orderby‘ parameter. Defaults to ‘DESC’.
  • orderby (string) – Sort retrieved posts by parameter. Defaults to ‘date’. One or more options can be passed.

Get loop items in random order

Just use ‘rand’ in ‘orderby’. If it’s not working, make sure that you remove all order filters (which may be used by a plugin), before the query.

remove_all_filters('posts_orderby'); // use this line, if rand does not work
$args = array(
    'orderby' => 'rand'
);

Loops within another WordPress Loop

You can make loops within another WordPress loop fairly easy using the get_posts() WordPress function. If you use as $post, then the code is:

$args = array(
    'posts_per_page' => 2,
    'post_type' => 'page'
);
$theposts = get_posts($args);
foreach ($theposts as $post) :
    the_title();
endforeach;

If you use a $my_custom_var the the code is:

$args = array(
    'posts_per_page' => 2,
    'post_type' => 'page'
);
$theposts = get_posts($args);
foreach ($theposts as $my_custom_var) :
    echo $my_custom_var->post_title;
endforeach;

Learning Resources