new Wp_Query() or pre_get_posts() to view ALL posts for custom post type?

bestprogrammerintheworld picture bestprogrammerintheworld · Jan 23, 2014 · Viewed 8k times · Source

I have an archive-template file that shows all posts for custom post type personnel (called archive-personnel.php):

This is the begining of the file...

<?php 
get_header(); 

//Show all posts for this custom posttype (personnel)
$args = array( 'post_type' => 'personnel', 'posts_per_page' => -1 );
$personnel_query = new WP_Query( $args );
if (have_posts()) : while ($personnel_query->have_posts()) : $personnel_query->the_post(); 

This is working, but I know that I can use pre_get_posts() as well. But with pre_get_posts() - filter you have to check if it affects admin etc.

So my question is: Does it really matter which alternative I use or is just a matter of preference/taste?

Answer

birgire picture birgire · Jan 23, 2014

Main query versus secondary queries:

Does it really matter which alternative I use or is just a matter of preference/taste?

Yes , there is a real difference:

1) pre_get_posts is modifying the main query (or all queries) versus adding a secondary query using WP_Query.

2) If you want paging to work on the secondary query, you usually have to make modifications to the main query.

By using the pre_get_posts hook you can modify all queries that are instances of WP_Query(), including the main query, which is an instance of WP_Query() and is present for every page request.

Remember that get_posts() is a wrapper for WP_Query() and the filter is active when the suppress_filters attribute is set as FALSE.

When using pre_get_posts you usually want to target specific queries by using some conditional tags. Here are few examples, you can use:

a) is_main_query() to determine if the current query is the main query.

b) ! is_admin() to prevent modifications to queries in the backend.

c) is_post_type_archive() to target the post type archives.

When you add your custom WP_Query(), then you are adding extra queries in addition to the main query.

I usually go with the pre_get_posts action if I can, instead of adding a secondary query.

Example:

If you want to modify the main query, for the archive of the custom post type personnel, you can try:

add_action( 'pre_get_posts', function( $query ){
  if ( ! is_admin() && $query->is_main_query() ) {
    if ( is_post_type_archive( 'personnel' ) ) {
      $query->set('posts_per_page', -1 );
    }
  }
});

This is untested but you get the idea ;-)

Further reading:

Hopefully the following links can give you more information regarding the difference: