最初の3つの投稿をカスタムフィールドで並べ、その後の投稿をpost_date
で1回のクエリで並べる必要があります。
field_order
:1)field_order
:2)field_order
:3)field_order
:null)field_order
:null)Post 1
とPost 0
はpost_date
で並べる必要があります。
カスタムフィールドで簡単に注文できますが、カスタムフィールドなしの投稿(Post 1&0)を追加すると、クエリに表示されません。
以下は私が現在試みている質問です:
$args = array(
'post_type' => 'insights',
'posts_per_page' => '9',
'meta_query' => array(
array(
'key' => 'field_order',
'value' => '0',
'compare' => '>'
)
),
'orderby' => array(
'field_order' => 'ASC',
'post_date' => 'ASC',
),
'order' => 'ASC'
);
OR
を持つ複数のmeta_query
引数'relation' => 'OR'
のmeta_query
引数を2組のfield_order
引数と共に使用することができます。1つはmeta_value >= '0'
を含み、もう1つはNOT EXISTS
を持つメイン照会を生成します。
'meta_query' => array(
'relation' => 'OR',
field_order' => array(
'key' => 'field_order',
'value' => '0',
'compare' => '>=',
'type' => 'NUMERIC'
),
'field_order_withnulls' => array(
'key' => 'field_order',
'compare' => 'NOT EXISTS',
'type' => 'NUMERIC'
)
)
'field_order_withnulls' => 'ASC'
を使用できますが、LEFT JOINのため、null
field_order
値を持つ行があり、それらはASC
orderbyの数値field_order
値の前にあります。
これを修正するために、 here に記述されているようにORDER BY -field_order DESC
トリックを使用します。
これはDESC
をASC
に反転することによって順序を修正しますが、数値の後にnull
の値を持つ行を保持します。
orderby
で-
(inverse)演算子を実装する問題は、WordPressがorderby
に-
(inverse)演算子を直接設定する方法を提供していないことです。そこで、WP_Query
という名前のカスタム_inverse_order
属性を導入し、それを実装するためにposts_orderby
フィルタを使用します。
// posts_orderby filter callback function
// place this function in theme's functions.php file or in a custom plugin
function wpse311227_inverse_orderby( $orderby, $query ) {
remove_filter( 'posts_orderby', 'wpse311227_inverse_orderby', 10, 2 );
$idx = (int) $query->get( '_inverse_order' ) - 1;
if( $idx >= 0 ) {
$orders = preg_split( "/(?<=ASC|DESC),[\s]*/i", $orderby );
if( $idx < count( $orders ) ) {
$orders[$idx] = '-' . $orders[$idx];
}
return implode( $orders, ', ' );
}
return $orderby;
}
// adding the posts_orderby filter to implement the custom '_inverse_order' attribute
// this should be placed just before the WP_Query call
add_filter( 'posts_orderby', 'wpse311227_inverse_orderby', 10, 2 );
$args = array(
'post_type' => 'insights',
'posts_per_page' => '9',
'meta_query' => array(
'relation' => 'OR',
field_order' => array(
'key' => 'field_order',
'value' => '0',
'compare' => '>=',
'type' => 'NUMERIC'
),
'field_order_withnulls' => array(
'key' => 'field_order',
'compare' => 'NOT EXISTS',
'type' => 'NUMERIC'
)
),
'orderby' => array(
'field_order_withnulls' => 'DESC',
'post_date' => 'ASC'
),
// this custom attribute is implemented in wpse311227_inverse_orderby() function
// to correct the ordering by placing a '-' operator
// value of _inverse_order attribute is the position of the
// orderby attribute to be be inversed,
// (position starts with 1)
// in this case, since: 'field_order_withnulls' => 'DESC'
// is in position 1 of 'orderby' attribute array, so:
'_inverse_order' => 1
);
$query = new WP_Query( $args );
これにより、field_order > 0
を含むすべての投稿と、予想される順序でfield_order
メタデータを持たない投稿が作成されます。
注:WordPressのバージョンが3.9以下の場合は、
meta_query
チェックのためにNOT EXISTS
に空でないvalue
を渡す必要があります。これをチェックしてください codexからのメモ :バグ#23268のため、3.9より前ではNOT EXISTS比較が正しく機能するためには値が必要です。 valueパラメータには文字列を指定する必要があります。空の文字列またはNULLは機能しません。ただし、NOT EXISTSを使用した場合、他の文字列はうまくいき、SQLには表示されません。
警告:この
WP_Query
は2つのLEFT JOIN
を使用します。これはあまり効率的ではないです。しかし、数千の投稿でさえ、これは許容範囲です。私は15,000以上の投稿でテストしました。クエリは平均で約0.3秒かかります。ただし、数百万、さらには数十万の投稿がある場合は、クエリを最適化するか、同じ結果を得るためのより効率的な方法を見つける必要があります。