WP_query を一度だけ使うという前提条件だと、ご希望の方法はありません。
強引な方法ですが、タームAが付いた投稿を取得して配列Aに入れ、タームBが付いたのを取得して配列Bに入れ、タームCのは配列Cに入れ、配列AとBとCを array_merge で一つにまとめる位しか思いつかないです。
データベースからの記事取得は、お示しのコードでやって、表示をするときに調整するというはどうでしょう。どのように表示したいかによりますが、同じページに表示するという前提で考えました。途中でページが変わると、データが入れ替わってしまうので、うまく動きません。add_filter の無名関数は、PHP 5.3 より前のバージョンではエラーになります。
考え方は、こうです。$wp_query は普通、ループの終わりに、ループポインタを最初に戻します。途中でループを抜けると、ポインタをそのまま保持するのですが、rewind_posts() メソッドで、ポインタを最初に戻すことができます。これを利用して、ひとつのデータを複数回のループで利用するというものです。それぞれのループの中でタームを判定できるように取得するデータを通常とは違ったものにしてあります。ループ1回ごとに投稿 ID からタームを得ると、結局毎回 WP_Query が実行されるようなことになるので、まとめてデータを取り、表示部分で調整をするという感じです。
ソートについては、すべて共通のフィールドを使うことになります。pre_get_posts フックの中で指定してください。デフォルトは投稿日順です。それぞれのタームでソートアルゴリズムが違う場合は、PHP を使う必要があります。
functions.php
function term_filtered_query($query) {
if (is_admin() && !$query->is_main_query()) return;
if (...ページの条件...) {
add_filter('posts_join_request', function($join) {
$join .= ' INNER JOIN wp_term_taxonomy AS tt ON wp_term_relationships.term_taxonomy_id = tt.term_taxonomy_id INNER JOIN wp_terms AS t ON tt.term_id = t.term_id';
return $join;
}, 10, 1);
add_filter('posts_fields_request', function($fields) {
$fields .= ', t.name AS term_name';
return $fields;
}, 10, 1);
$query->set('tax_query', array(
'relation' => 'OR',
array(
'taxonomy' => 'taxonomy',
'field' => 'slug',
'terms' => array('term1')
),
array(
....,
)));
}
}
add_action('pre_get_posts', 'term_filtered_query');
テンプレート
// 1回目の処理
global $wp_query; // 念のため
$counter = 0;
if (have_posts()) {
while (have_posts()) {
the_post();
if ($post->term_name == 'term1') { // term1 以外を読み飛ばす
term1 を処理;
if (++$counter > 3) break; // 投稿3つでループを抜ける
}
}
}
$wp_query->rewind_posts(); // ポインタを戻す
$counter = 0; // カウンタも戻す
while (have_posts()) {
the_post();
if ($post->term_name == 'term2') {
term2 を処理;
if (++$counter < 4) break; // 投稿4つで終了
}
}
// ここで再びリワインドとポンタのリセット
$wp_query->rewind_posts();
$counter = 0;
while (have_posts()) {
the_post();
if ($post->term_name == 'term3') {
term3 を処理;
if (++$counter < 5) break; // 投稿5つで終了
}
}
// まだ続くなら、同じ操作を繰り返す