Move posts to top of WP_Query if in certain Taxonomy?

This is just a concept which you can try.

By default, you cannot sort within the loop. You have, according to my knowledge, have two choices

  • Create two loops and merging them. This, however, I would not recommend. Pagination and offsets are a nightmare if you are not completely comfortable with it

  • Run your loop as normal, and pushing the results into two separate arrays, merging the two arrays and from there extract and display the posts. You can paginate as normal

Example bases on the main query with a custom post type and default post type set with pre_get_posts. You can also do this on any custom query. For a list of member variable variable that you can use, see WP_Post. Note, this uses PHP 5.4 syntax

$post_type_posts = []; //change to $post_type_posts = array(); for pre 5.4
$other_posts = []; //change to $other_posts = array(); for pre 5.4

if(have_posts()) {
    while(have_posts()) {
       the_post();

       if( 'my_post_type' == $wp_query->post_type ) {
          $post_type_posts[] = get_the_title();
       }else{
          $other_posts[] = get_the_title();
       }
     }
}

$new_loop = array_merge($post_type_posts, $other_posts);

foreach ($new_loop as $loop) {
   var_dump( $loop );
}  

EDIT

Your idea will also work. Create a custom taxonomy, say tax and create two terms under the tax taxonomy, say term-a and term-b. OK, say term-a should display first.

Then alter the above code as follow:

$post_type_posts = []; //change to $post_type_posts = array(); for pre 5.4
$other_posts = []; //change to $other_posts = array(); for pre 5.4

if(have_posts()) {
    while(have_posts()) {
       the_post();

       if( has_term( 'term-a', 'tax' ) ) {
          $post_type_posts[] = get_the_title();
       }else{
          $other_posts[] = get_the_title();
       }
     }
}

$new_loop = array_merge($post_type_posts, $other_posts);

foreach ($new_loop as $loop) {
   var_dump( $loop );
}  

EDIT 2

For a custom query using tax_query, you can use the following:

$args = [
'post_type' => 'my-post-type',
'tax_query' => [
        [
            'taxonomy' => 'tax',
            'field'    => 'slug',
            'terms'    => [ 'term-a', 'term-b' ],
        ]
    ]
];

$query = new WP_Query( $args );

$post_type_posts = []; //change to $post_type_posts = array(); for pre 5.4
$other_posts = []; //change to $other_posts = array(); for pre 5.4

if($query->have_posts()) {
    while($query->have_posts()) {
       $query->the_post();

       if( has_term( 'term-a', 'tax' ) ) {
          $post_type_posts[] = get_the_title();
       }else{
          $other_posts[] = get_the_title();
       }
     }
}

wp_reset_postdata();

$new_loop = array_merge($post_type_posts, $other_posts);

foreach ($new_loop as $loop) {
   var_dump( $loop );
}  

For more info, check WP_Query

Leave a Comment