Unfortunately, it’s not exactly the most optimal query, as you suspected. The much more verbose code that follows is slightly better because it’s more specific about which rows in postmeta to look at. In my veryyyy informal speed tests, the following runs about 30% faster:
/**
* Joins fields from an array of objects, returning a string with the fields separated by the given separator.
*/
function joinKeys($toJoin, $key, $separator) {
for ($i = 0; $i < count($toJoin); ++$i)
$ids .= $toJoin[$i]->$key . ($i < count($toJoin) - 1 ? $separator : '');
return $ids;
}
// media inline with posts
$all_attachments = $wpdb->get_results( $wpdb->prepare( "
SELECT ID
FROM $wpdb->posts
WHERE post_author = %d
AND (post_type = 'attachment'
OR (post_type = 'post'
AND post_parent = '0'
AND post_status = 'publish')
)
ORDER BY post_date DESC",
$curauth->ID ));
$all_ids = joinKeys($all_attachments, 'ID', ',');
$freeform = $wpdb->get_results( "
SELECT post_id
FROM $wpdb->postmeta
WHERE meta_key = 'media-credit'
AND post_id IN ($all_ids)" );
$freeform_ids = joinKeys($freeform, 'post_id', ',');
$attachments = $wpdb->get_results( "
SELECT *
FROM $wpdb->posts
WHERE ID IN ($all_ids)
AND ID NOT IN ($freeform_ids)
ORDER BY post_date DESC" );
I then use this to display it:
<?php if ($attachments) : ?>
<div id="posts-and-media">
<h3>Posts and images by <?php echo $curauth->display_name; ?></h3>
<ul>
<?php foreach ($attachments as $post) : ?>
<li>
<?php setup_postdata($post);
if ( $post->post_type == 'attachment' )
echo wp_get_attachment_link($post->ID, 'thumbnail');
else
echo the_title();
?>
</li>
<?php endforeach; ?>
</ul>
</div>
<?php endif; ?>
A) Any suggested optimizations to the above?
B) Is there a way to take advantage of the Loop instead of my custom looping? I’m not that familiar with how the Loop is made, or thus how to make one myself…