WordPress uses “the Loop” to create content it gets from the database. It’s used all over the place, be that within the standard theme files such as index.php, single.php, archive.php etc etc etc. Often as coders we use the loop to get information using WP_Query(); take the below example which is taken from a Widget that gets the latest 5 posts, excluding the current post (if there is one);
Yes you’ve seen it a million times, or something similar. But while you may think that this is a great use to your coding skill and gets the required result, there are in fact two simple things you can do to vastly improve the speed of the loop.
WP_Query is a class and creates an object. In the object it creates many things that are not always necessary. These are created automatically unless you tell it not to. The two quick things we can get it to not do is work out the total count of items that match the query, so not to workout the pagination, and to not do anything with the postmeta as its not going to be used.
By just adding two extra arguments it reduces the overheads on the database, so will reply with a faster query than the previous one.
‘no_found_rows’ => false is used to tell WP_Query not to look for all of the possible rows that meet the query, which is mostly used when doing pagination. ie. WP_Query finds 500 rows that meet the query, at 5 posts per page there would be 100 pages of posts in the possible pagination. However, by making this false, it tells WordPress not to make this secondary database query to get the row count.
‘update_post_meta_cache’ => false is used to tell WP_Query that it should not update the cache of the post meta of each post ID. Every time a post is called from the db WP_Query will try to cache the post meta so that it is much quicker to get when using get_post_meta(). But as in the loop example above, there is no need for this as it is does not use the post meta at all to display the information needed. So by setting it to false, it tells WordPress to ignore that activity, making the loop quicker.
Although I was always told that its always quicker to get data from the database with a query than it is to work out what is needed later in code, its not always true. In the case of post__not_in its actually quicker to ask for more posts and exclude the ones you have until you have the right number of posts in the loop to display.
The reason that this is quicker is that we’re only asking for the bottom X number of posts (5 + count of array of posts we don’t want), so in this example this will be just 6 (which is not quicker the php way all the time, it depends on the size of the db, number of posts etc. remember its just an example!), but of course this could be much higher if you’re using this as part of an ajax call to get the next set of posts, excluding the last ones. Its much more difficult for the database server to check for the last 5 posts, but make sure that it does not contain the ones we don’t want.
Putting this in to practice looks like this:
In the world where we are trying to return to the client in less than 200ms so that google gives us the thumbs up and thinks our site is fast, this can shave off many of those extra milliseconds. These tests were performed on a mac book pro 8GB mem, SSD and i5 processor, using Apache / php5.6.
|description||first run (in ms)||second run (in ms)|
|Excluding extras from WP_Query||5.2249431610107||5.3169727325439|
|Excluding extras and not using post__not_in||5.3231716156006||5.5720806121826|
please note, this was making an exclude of only 1 post, this may work better in some cases going direct to the db to make the query, sometimes it works better with the exclude. Depends on the db size, and number of posts you are excluding
There are some ways to shave off those milliseconds from the loop. Firstly reducing the amount of information that must be processed by WP_Query, and secondly by changing the way the loop works to perform the exclude of posts in it rather than with the database query.