I wonder if you aren't looking for something different than I have originally answered. After rereading your post trying to make proper sense, I think your images are actually attachments and not thumbnails, if I read this correctly. If, so, these attachments are still not saved in db, only the info about the attachment as you correctly pointed out
In this case, loading attachment can be very expensive if not done correctly. It is quite frustrating that WordPress does not allow you to directly query attachments without passing a post parent ID.
To get attached images for your posts, you can try the following, it will be a bit faster doing it this way
/**
* Because we really just need post ID's and nothing more like
* custom fields, postdata, and post terms, we will not be updating
* the post cache. This saves a lot of time and resources. If you are
* going to need custom fields or post data or terms, then you should remove
* cache_results because this will cause huge increase in db queries when you
* try to get post terms or custom fields
*
* Also, we will only get post ID's as we do not need anything else
*/
$args = [
'fields' => 'ids', // Get only post ID's
'cache_results' => false, // Do not update post caches
// Add any extra arguments
];
$q = get_posts( $args );
if ( $q ) {
foreach ( $q as $id ) {
/**
* Get all attached images
*
* We will be doing what get_attached_media does, but because we only
* have post ID's and have not updated the post cache, we will not be
* using get_attached_media() as it will lead to a large number of db hits
* because get_attached_media() will use get_post() to get the complete post object
*/
$image_args = [
'post_parent' => $id,
'post_type' => 'attachment',
'post_mime_type' => 'image',
'posts_per_page' => -1,
'orderby' => 'menu_order',
'order' => 'ASC',
];
$images = get_children( $image_args );
if ( !$images )
continue;
// Loop throught the images
foreach ( $images as $image ) {
// Output the images as needed
// For debugging, see the var_dump for values
var_dump( $image );
}
}
}
ORIGINAL ANSWER
Post thumbnails aren't explicitely saved in the db, only the ID of that particular thumbnail is saved as post meta in the wp_postmeta
table. The particular meta key is _thumbnail_id
.
You can specifiy which thumbnail size to return for each post via the second parameter of the get_the_post_thumbnail()
function. You can alternatively set a string or an array of custom attributes as third parameter
It should be noted, get_the_post_thumbnail()
does not display the thumbnail, but simply returns it. Inside the loop, you would want to use the_post_thumbnail()
to display the thumbnail, in which case the parameters as discussed above will be the first and second parameters respectively.
Loading thumbnails in a custom loop is expensive as thumbnails aren't cached for custom queries. Only the main query is covered. You need to explicitely set caching for thumbnails in a custom loop.
You can try the following as a probable solution: (NOTE: Everything is untested and might be buggy)
(Lets say you want to use the medium
size thumbnail and only want to display thumbnails, nothing else, if need any other post properties, remove the filter)
Lets first look at the filter which should go into functions.php
/**
* Custom filter to retrieve only post ID's.
*
* We cannot set the fields arguments to ID in our query because
* we need to update the thumbnail cache, and if you look at
* update_post_thumbnail_cache(), we need the post as an object
* so we can use $post->ID, if we set the fields parameter, we only
* get an array of ID's, not post objects with only ID's
*/
add_filter( 'posts_fields', function ( $fields, \WP_Query $q ) use ( &$wpdb )
{
remove_filter( current_filter(), __FUNCTION__ );
// Only target a query where the new wpse_fields parameter is set with a value of ID
if ( 'ID' === $q->get( 'wpse_fields' ) ) {
// Only get the post ID field to reduce server load
$fields = "$wpdb->posts.ID";
}
return $fields;
}, 10, 2);
This filter will reduce server load by a big margin as we only get post ID's, but still maintain the post object.
Your custom query can look something like the following:
/**
* Because we only need to display the post thumbnails, we will not be
* updating the term cache. If you need post term info, remove the
* update_post_term_cache argument. This will increase performance if you
* do not need post term info
*/
$args = [
'meta_key' => '_thumbnail_id', // Only get posts with thumbnails
'wpse_fields' => 'ID', // Our custom argument to get only post ID's
'update_post_term_cache' => false, // Do not update the post caches to make the query faster
// Any other arguments
];
$q = new WP_Query( $args );
if ( $q->have_posts() ) {
// Update the post thumbnail cache
update_post_thumbnail_cache( $q );
while ( $q->have_posts() ) {
$q->the_post();
// Display the post thumbnail, medium size
if ( has_post_thumbnail() ) // Not really necessary in current context
the_post_thumbnail( 'medium' ); // Get medium size post thumbnail
}
wp_reset_postdata();
}
EDIT
VERY IMPORTANT NOTE
The use of short PHP tags are highly discouraged, it is actually not allowed in WordPress. It is really bad coding practice. You should make a habit of it to use proper PHP tags (*<?php
and ?>