WP_Query – filter or directly?

You need to consider quite a couple of things here and it seems like you are after increasing performance of a query. The first and most important question you must ask yourself is:

Do I need a custom query

I have done an extensive post on this subject a while ago which you should check out. If you answered yes to the question above after reading my post in the link, then you need to consider the following when creating custom queries

  • Avoid (where you can) complex orderby operations like ordering by meta values. SQL is not the best at ordering and PHP is sometimes faster. I tend to prefer usort() for complex ordering to save on resources. Random ordering is also very hard on resources

  • Avoid (where you can) building complex queries with heavily nested meta and tax queries, specially with a lot of OR operators. These are quite tough on resourches.

  • Avoid (where you can) using LIKE operators in your generated SQL. These are also expensive

  • Use transients (and caches) to store expensive queries. For random queries, you cannot do this, so you will need to look into other methods to tackle this issue

  • Always avoid the typical foreach loop whereby you get a list of terms and then running a custom query for each and every term, they are really expensive. Rather query all posts and once and then use usort() to sort the results

  • Create a query according to what you need. Most of the time we only need to query posts in order to get their ids to pass to another function. In cases like these, only query the post ID’s. This really saves a lot on resources. Simply add 'fields'=>'ids', to your query arguments

  • To speed up non paginated queries, use get_posts() or simply pass 'no_found_rows'=>true to WP_Query (this is exactly what `get_posts do). This skips the pagination process and save lots on resources on huge db’s

This is just meant as some kind of guideline to speed up the query. There are still some other things to speed up queries.

Does using filter for query arguments have any drawbacks? Performance? Something else?

I cannot see why there might be issues. If you are creating a commercial theme, you are definitely doing is correctly. Making something filterable makes the lives of child theme authors much easier. It might cost a milli of a milli of a milli second, but it is definitely time well used. It is like sanitation. Sanitation costs time and resources (although it is very very little), but spending a millisecond more on something can save your site from being hacked and destroyed

IMHO, you would need to look into other ways to speed up a query and not compromise usability and maintainability. Option 2 is definitely something that you should do for commercial themes

IDEA (Might be a bit overboard 😉)

You can also use pre_get_posts to filter your custom query and make it filterable. It is as simple as setting your own custom parameter in your query and them use that parameter to target your query

In the following example, we will use a custom parameter query_no which we will give numerical values

The Queries

$q1 = new WP_Query( ['query_no' => 1] );    
$q2 = new WP_Query( ['query_no' => 2] );    
$q3 = new WP_Query( ['query_no' => 3] );    

pre_get_posts

add_action( 'pre_get_posts', function( $q ) 
{
    if ( $q->get( 'query_no' ) == 1 ) {
        $q->set( 'posts_per_page', -1 );
        // Add any other extra arguments to set
    }

    if ( $q->get( 'query_no' ) == 2 ) {
        $q->set( 'post_type', ['post', 'page'] );
        // Add any other extra arguments to set
    }

    if ( $q->get( 'query_no' ) == 3 ) {
        $q->set( 'post_status', 'trash' );
        // Add any other extra arguments to set
    }
} );

The user can now add additional arguments or change the one passed

add_action( 'pre_get_posts', function( $q ) 
{
    if ( $q->get( 'query_no' ) == 2 ) {
        // Lets add another post type
        $post_types = $q->get( 'post_type' );
        $post_types = array_merge( $post_types, ['my_post_type'] );

        $q->set( 'post_type'     , $post_types );
        $q->set( 'posts_per_page', -1          );
        // Add any other extra arguments to set
    }

}, 
11 // Make sure this runs after the default action
); 

Leave a Comment