Query Loop blocks use the same WP_Query class most post queries use, so any such query can be modified through the “pre_get_posts” action hook. The difficulty comes in identifying which individual query should be modified. Hopefully the target query would have some unique set of query var values that would positively identify the correct query.
If it’s not possible to positively identify the right query through its query var values (or some other creative method) I think you’re stuck with needing a custom block for the purpose.
By creative method, one that comes to mind is somehow adding your pre_get_posts action callback just before it’s needed, then having the callback on entry remove itself from the call stack. This greatly minimizes how many different queries you’d need to differentiate from, making success more likely.
Thanks @bcworkz, that’s a good suggestion. I guess it doesn’t really matter what query vars I set on the block in the editor since I can adjust them to whatever I actually need through the hook. I’ll just set them to something I’m not going to use anywhere else.
Thanks!
Hey @itsviney !
There is also some guidance on this in developer.wordpress.org. You can set up your custom query by following the guidance in the documentation here. Specifically, check out this section.
Hope that also helps. π
Thank you both. If I was going to be handing this one off to a client I would probably create a variation and take that approach but for this, I’ve used the pre_get_posts hook. For anyone else trying to achieve something similar, here’s what I did…
function modify_related_query_loop_block($query) {
if (!is_admin()) {
// This is the specific query configured on the Query Loop block in the Related Messages section
if ($query->get('post_type') == 'page' && $query->get('orderby') == 'title' && $query->get('order') == 'DESC') {
global $post;
if ($post) {
$terms = wp_get_post_terms($post->ID, 'message-topic');
$term_ids = [];
foreach ($terms as $term) {
$term_ids[] = $term->term_id;
}
$query->set('post_type', 'location');
$query->set('orderby', 'rand');
// Exclude the current post
$query->set('post__not_in', array($post->ID));
if (!empty($term_ids)) {
add_filter('posts_clauses', function ($clauses, $wp_query) use ($term_ids) {
global $wpdb;
$term_ids_in = implode(',', array_map('intval', $term_ids));
$clauses['join'] .= "
LEFT JOIN (
SELECT object_id, COUNT(*) as term_count
FROM $wpdb->term_relationships
WHERE term_taxonomy_id IN ($term_ids_in)
GROUP BY object_id
) as term_matches
ON $wpdb->posts.ID = term_matches.object_id
";
$clauses['orderby'] = 'term_matches.term_count DESC, ' . $clauses['orderby'];
return $clauses;
}, 10, 2);
}
}
}
}
}
add_action('pre_get_posts', 'modify_related_query_loop_block');
Hey @itsviney !
If I was going to be handing this one off to a client I would probably create a variation and take that approach..
Yea, got you! That makes perfect sense, yes.
Thank you so much for sharing that, for posterity. It’ll help a lot of people. π
Thank you.