Another way of querying in WordPress is by using get_posts(). The difference here is that get_posts() returns an array of post objects as the result for you to manipulate. To go through the data this time, you need to loop through the result in a slightly different way from the other options:
$new_posts = get_posts( $args ); foreach ( $new_posts as $post ): setup_postdata($post);
// Do stuff - using normal template tags endforeach;
In the preceding example, I used a standard foreach loop in PHP to go through the array. The important part is to use $post as the value argument in the foreach loop. By doing this, it allows you to use the setup_postdata() function to give you the template tags to use as normal. However, when this method is used, the main post data from the default query is overwritten. When you do this, you need to reset the data so that functions you may want to use later on that relate to the main query don’t get caught up with the leftover data from your modified query. That’s where the wp_reset_postdata() function comes in. (You’ll be taking a more detailed look at resetting things in WordPress later on in the chapter.)
If you don’t use the setup_postdata() function to make the template tags available, you need to use the raw data returned by the get_posts() function as follows:
$new_posts = get_posts( $args ); foreach ( $new_posts as $post ):
echo '<h1>'.$post->post_title.'</h1>'; echo $post->post_content; // raw
echo apply_filters('the_content', $post->post_content); // formatted endforeach;
The preceding code shows how to access the raw data through the post variable you get from the get_posts() query. I also included two ways of outputting the content data. The first gets the raw data as you’ve written it into the content editor, so if you leave some of the formatting to WordPress (such as p tags), you’ll need to use the apply_filters() function to process the content data the same way WordPress does when it sets up the post data as normal.
One more thing to note about get_posts() is that although it does take many of the same arguments as the previous two query types, there are a few subtle differences. For instance, to change the number of posts queried for, use numberposts instead of posts_per_page. (For a full list of parameters, take a look at
http://wp-themes-book.com/03001.)
WP_Query
To loop with a WP_Query object, you use query parameters as arguments when creating a new instance of the WP_Query class. It’s similar to the way in which you use query_posts()—both functions accept the same parameters—but you use the new constructor and pass the result into a variable that looks like this:
$new_query = new WP_Query( $args );
if( $new_query->have_posts() ): while( $new_query->have_posts() ): $new_query->the_post(); // Do stuff - with normal template tags
endwhile; endif;
The $new_query variable now becomes an instance of the WP_Query class. To set up your loop instead of calling have_posts() and the_post() functions as usual, you need to call them as methods of the new instance of the class you created $new_query->have_posts. This then gives you use of the same template and conditional tags used before in a regular loop.
Chapter 3 ■ Content options and the Loop
Modifying the Default Query
Now you’ll look at customizing the queries you create using the methods just discussed. The first way of customizing content is to modify the default query, the one that I talked about that gets created based on the settings and page URL.
But if the query is being created automatically, how can you modify it? The query parameters are also stored in a variable in WordPress that you can access in your template files: the $query_string global. This is one of those variables created by the WP_Query class early on in the setup of the initial page load (I told you it would come in handy):
// access the global variable which stores the default query string global $query_string;
query_posts( $query_string . "&cat=-5" );
if( have_posts() ): while( have_posts() ): the_post(); // Do stuff
endwhile; endif;
The preceding code takes the $query_string variable and uses query_posts()—more on that in a second. You can do this because the $query_string quite literally does exactly what it says on the tin: it’s a string containing the current query that will be run on the database. You create the new query by simply concatenating more query parameters to the end of the default string and then pass it as the argument to the query_posts() function.
Note
■
remember to start your additional parameters with an ampersand (
&) as you add to the current query
parameters; think of it as
'query_string' & 'new parameters'.
I already mentioned that there lots of caveats to be aware of when using the query_posts() function. It is not the most preferred or efficient method of setting up a new query in WordPress. It is, however, the best method of modifying a default query when you’re already in the page template. If you want to intercept the query before you get to the template, however, you can use the pre_get_posts hook, which is called after the query variable is built, but before the query is actually run by WordPress. This method does come with a few caveats. Because the query has yet to be run, there are a lot of functions that aren’t available (namely, the is_front_page() conditional function), but is_home() is available, so you can use it for tasks such as modifying what appears on the post listing page.
Here’s an example of using the hook to remove a category from display in the main posts list: function exclude_category( $query ) {
if ( $query->is_home() && $query->is_main_query() ) { $query->set( 'cat', '-5' );
} }
add_action( 'pre_get_posts', 'exclude_category' );
The $query object is the main instance of the WP_Query; the object variable is passed in by reference here, so the function doesn’t need to return the variable after you’ve modified it—you’re working with the $query object itself. Also notice that you’re using more methods of the WP_Query object to check the conditional functions and to add an extra parameter using the set method (it just takes the parameter you want to set and the value to set it to as two arguments of the function).