Before I fire away, just one note, NEVER (my emphasis) make use of query_posts
to create custom queries
Note: This function isn’t meant to be used by plugins or themes. As explained later, there are better, more performant options to alter the main query. query_posts() is overly simplistic and problematic way to modify main query of a page by replacing it with new instance of the query. It is inefficient (re-runs SQL queries) and will outright fail in some circumstances (especially often when dealing with posts pagination).
Rather make use of WP_Query
or get_posts
to create custom queries, but ONLY if you can’t modify the main query with pre_get_posts
. For more info, check out this post
Assuming that there are only two values for your meta_key
(PLEASE NOTE: For testing purposes, I have used my own meta key, you should replace this with your own), namely pro
and free
, you can just retrieve posts that has this specific meta_key
. Your query will then look something like this:
$args = [
'meta_key' => 'packages',
'orderby' => 'rand',
'posts_per_page' => 5,
];
$the_query = new WP_Query( $args );
If you however have more values than just these two, then you will need to adjust your query to include the meta_value
and then make use of the meta_compare
parameter. Your adjusted query will then become:
$args = [
'meta_key' => 'packages',
'meta_value' => 'free, pro',
'orderby' => 'rand',
'meta_compare' => 'IN',
'posts_per_page' => 5,
];
(PS! Before I go on, you should note that the orderby
parameter has changed in version 4.0, but this will not work in this instance.
Great, you will now have 5 posts that was retrieved randomly which has either a meta_value
of pro
or free
Now we need to sort them. The best possible solution is to make use of usort
to sort the returned array of posts in $the_query->posts
according to the value of the posts meta_value
. You will then need to unset $the_query->posts
and then reset it with the reordered post array.
Here is the complete code:
<?php
$args = [
'meta_key' => 'packages',
'meta_value' => 'free, pro',
'orderby' => 'rand',
'meta_compare' => 'IN',
'posts_per_page' => 5,
];
$the_query = new WP_Query( $args );
$post_metas = $the_query->posts;
usort( $post_metas, function( $a, $b ){
$a = get_post_meta( $a->ID , 'packages', true ) ;
$b = get_post_meta( $b->ID, 'packages', true ) ;
if ( $a == $b ) {
return 0;
}
return ( $a > $b ) ? -1 : 1;
}
);
unset($the_query->posts);
$the_query->posts = $post_metas;
if ( $the_query->have_posts() ) {
echo '<ul>';
while ( $the_query->have_posts() ) {
$the_query->the_post();
echo '<li>' . get_post_meta( get_the_ID(), 'packages', true ). '</br>' . get_the_title() . '</li>';
}
echo '</ul>';
}
wp_reset_postdata();
?>
You will just need to adjust the query variables to suit your needs and also adjust the loop to display what is needed
This is not the only way to achieve it though, you can also move your sorting function to your functions.php and specifically target this custom query