Worpress queries: When to use WP_Query, get_posts, query_posts or pre_get_posts
original source : http://beebell.co.uk/wordpress-queries-when-to-use-wp_query-get_posts-query_posts-pre_get_posts/
When you’re creating a custom theme, at some point you may to want to bring back a set of results other than what WordPress defaults to. The question is, do you use WP_Query
,get_posts
, query_posts
or pre_get_posts
?
Scenario 1 – You just need an archive page
Soluion: None of the above
If something can be accomplished without writing code, let WordPress do it for you.
- If you want to move your main blog posts archive (ie. list of all your posts, usually just the excerpts) from the front page to another page (eg. a page entitled ‘Blog’), all you need to do is:
a) create a new page called ‘Blog’
b) Go to Settings > Reading and select ‘Front page displays: A static page’ and select your posts page:
- If you want an archive or single page for a custom post type, use the relevant templates from the template hierarchy. Eg. For a custom post type ‘books’, use archive-books.php. The default loop will display all ‘books’ posts, and each individual post will be displayed with single-books.php. The exact link will depend on your permalink structure. If you’re using the ‘post name’ option (see Seetings > Permalinks) then http://yourdomain/books will automatically load your books archive template.
Scenario 2 – Your page already utilises a loop and you need an additional loop
Solutions: WP_Query or get_posts()
The difference between the two is that WP_Query
returns an object and get_posts
returns an array. If the content you want is fairly lightweight, for example a list of titles, then you can use get_posts
and loop through the array with a foreach
. If you want a fully blown WordPress Loop and the ability to use template tags such as the_content()
, go for theWP_Query
option.
Scenario 3 – you want to alter the main loop
Solutions: query_posts() or pre_get_posts
By the time Worpress loads your template and runs the code in your template, it has already run a query on the database and is holding the results ready for you to use in the loop. If you use query_posts
to modify the results, WordPress throws away the previous results and runs another query on the database to bring back your results.
Because of this, it is generally recommended to hook into pre_get_posts
instead. To do this you would create a function in your theme’s functions.php. This enables you to alter the query before it is run. However, this affects all of the queries on your site, front-end and admin, if you’re not careful. Therefore you need to put in checks to make sure it’s not an admin page/it is the main loop/it is in fact the template you wanted to affect.
In this example I have created a custom post type called ‘product’, and have a custom field called ‘colour’. My wordpress front page is set to ‘Your latest posts’. WordPress will use the home.php template to disply this if it is available. Here I am altering the query for the home page to only show Products that are red:
function bb_red_things( $query ) { if ( is_home() ) { // Set post type to 'product' $query->set( 'post_type', 'product' ); // Limit to products with a custom field 'colour' set to 'red' $query->set( 'meta_key', 'colour'); $query->set( 'meta_value', 'red'); } } add_action( 'pre_get_posts', 'bb_red_things' );
Note that pre_get_posts
doesn’t work with Pages. Also, some template tags will not work (as they’ve not been set up yes at this point). For example, is_front_page()
will not work, although is_home()
will work. See the Codex on pre_get_posts for more details and examples.