I have a page that loads a lot of featured items in a grid. There are up to 56 images loading, and it does have a bit of a delay.
This is the code as it runs now:
if( count( $postslist ) > 0 ) {
foreach ($postslist as $post) : setup_postdata($post);
?>
<div class='oneCell'>
<?php
$image = get_the_post_thumbnail($this_post->ID, 'full size');
$imageSrc = substr($image, strpos($image, "src") + 5);
$imageSrc = substr($imageSrc, 0, strPos($imageSrc, """));
$finalImage = "<img class='lazy' src='/images/grey.png' data-original='";
$finalImage .= $imageSrc . "' />";
$lastImage = "<a href='";
$lastImage .= catch_that_image();
$lastImage .= "'>";
$lastImage .= $finalImage;
$lastImage .= "</a>";
echo $lastImage;
?>
</div>
<?php
$currentCount = $currentCount + 1;
endforeach;
}
I understand there are issues with the code, basically hitting the database once for every image in a loop, which is causing the slowness.
Can anyone help me out with a solution to speed up the loading? My thought is grabbing everything from the database all at once and displaying it from there, but I have yet to figure out how to handle that.
Thanks!
Edit:
Sorry, I should have explained this a bit more:
The get_the_post_thumbnail is asking for the fullsize image because the fullsize image is what it needs (189×189). The featured image in the post is that image, and will always be 189×189.
catch_that_image() just grabs the first (and only) image in the post body to be displayed when the user clicks on the featured image (thumbnail) using a js library (magnific-popup.js).
Edit 2:
It looks like my issue is database related. The calls are too slow to do one at a time (since there are so many). Is there a way to get everything back in one call then process it from there?
The answer is eager loading or cache or both.
Eager loading
Have a look to this pseudo-code:
If the number of
$ids
isn
than this simple code runsn+1
queries, the first to load the ids, then one for each id.You code is even worse, it run 2 queries for every id, one to get attachment post object, one to get attachemnt url (is WordPress, not you, really)
So you run 2n+1 queries…
Eager loading, referred to a db query, is the way you solve the n+1 (or 2n+1) queries problem by querying in only one db request all the data you need (normally is done using proper
JOIN
+WHERE
)How do that in WordPress? You need two things:
WP_Query
to include meta table fieldsBoth can be done using query filters, here a class extending
WP_Query
that do that:This class extends
WP_Query
, so accepts same things of its parent but add some filters to change the eager loading thumnail post id, thumnail post name and thumbnail file path.So if your query returns 50 posts, to display thumbnails you run 101 (2n+1) queries, my class you runs only 1 query.
In addition before output the results, the class parse all the rows, and extract first image url from post content and remove the filter added.
How to use
Use the standard
WP_Query
arguments:But use
Thumb_Query
instead ofWP_Query
Then loop and output:
Inside the loop you have access to all standard post properties, but every post has additional 4 properties:
$post->thumb_id
the thumbnail attachment id$post->thumb_title
the thumbnail attachment title$post->thumb_file
the thumbnail file relative to uploads folder, something like'/2014/04/myfile.jpg'
$post->thumb_link
the full url of the first image in post content or ‘#’ if no image foundIt is quite difficult to understand what you have done. One of my concerns is using
get_the_post_thumbnail()
andcatch_that_image()
together in the same code as you have done. I have knowledge ofcatch_that_image()
function and have used it before. It is a nice-to-know-function that is usually used by coders to retrieve the first image to display it in the excerpt. How ever, there are better ways to get the same result withoutcatch_that_image()
. I do really think that it slows down your site as it is an outside function that runs separately from the loop, specially if you need to retrieve 56 images.catch_that_image()
needs to run on every post to retrieve the image, so it is executed 56 times. Correct me if I’m wrong here.I don’t know what your loop looks like, but that seems to be bit of a mess. I think the best way to go here is by using
WP_Query
in conjuction withget_posts
to construct your loop.In
WP_Query
you will only need to pass one argument to make this work,posts_per_page
. You will need to set this to1
, otherwise you will get the same image multiple times.Next is to run the loop, and filter out all the images attached to a post using
post_type
andpost_mime_type
. WordPress saves all attachments as apost type
. Not all attachments are images, so it needs to be specified that only attachments that are images should be returned. This is specified bypost_mime_type
.wp_get_attachment_image
will be used to return these images at the specified size, in your code this will be the full size featured image.This all done and dusted, the full loop will look something like this
You just need to change the arguments to suite your exact needs, but I hope this is a basic platform that you need and can work from and that this really helps a lot with speed. Enjoy.
Edit
Don’t forget to reset the query using
wp_reset_postdata();