5

The count of my files, templates, scripts, queries etc is getting big and I need a good system to maintain it all.

I've tried to keep everything organized:

  • No <script> tags in templates
  • Inline CSS only when it's PHP variable that could be changed dynamically from admin options
  • Single big files of JS and CSS to minimize requests etc

Now it's time to organize my queries because I've got at least 10 of them and it keeps rising.

  1. First option: use custom add_filter() with each query

    • I don't have to hunt down queries because they all are on one file or directory
    • If I need to change it, I only need to change it in one place, not in all my different templates
  2. Second option: write all queries into templates as usually is done

    • Basically every point is on the contrary of first option

Question:

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


Example:

  1. Usual:

    $args = array(
    
            'post_type'         => 'my-post',
            'posts_per_page'    => 8,
            'orderby'           => 'rand', 
        );
    
    }
    
    $results = new WP_Query( $args );
    
  2. Filter:

    //In one file -> easy to find and change
    add_filter( 'some_args', 'some_search_args' );
    
    function some_search_args( $search_args ) {
    
        $search_args['post_type'] = 'property';
        $search_args['posts_per_page'] = 8;
        $search_args['orderby'] = 'rand';
    
        //All kinds of logic and conditional code to here
    
        return $search_args;
    }
    
    
    //And
    
    
    //Just include like this to any template you want and as many as you want
    //To change the query, you'll just have to change to code above
    $search_args = array();
    $search_args = apply_filters( 'some_args', $search_args );
    
    $results = new WP_Query( $search_args );
    
4

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
); 
  • What do you think about transients when query results are the same? Lame example but still: query is made via ajax -> set transient -> and when user spams the button without changing input fields ( I've set spam protection to ajax buttons but still.. ) -> get results from transients? Im asking this because my huge query is tied with map and panning/zooming calls another exact same query because displaying e.g 100 000 markers kills every browser. – N00b Jan 2 '16 at 10:56
  • Just have a look at the linked posts under usort(). I create unique transient names by taking the arguments, then use md5() to create a unique key to add to the transient name. This way, if the query arguments change, a unique transient is created. Any other call after that with the same arguments simply loads the results from the transient. – Pieter Goosen Jan 2 '16 at 11:46
  • Sorry, I must be blind because I didn't see it before.. Thank you for very detailed answer. – N00b Jan 2 '16 at 11:49
  • 1
    No problem, we all still feeling the after effects of new year, hahahaha. Enjoy ;-) – Pieter Goosen Jan 2 '16 at 11:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.