web-dev-qa-db-ja.com

WP_Query orderbyカスタムフィールド、1つのクエリでpost_date

最初の3つの投稿をカスタムフィールドで並べ、その後の投稿をpost_dateで1回のクエリで並べる必要があります。

  • 投稿4(field_order:1)
  • 投稿3(field_order:2)
  • 投稿2(field_order:3)
  • 投稿1(field_order:null)
  • 投稿0(field_order:null)

Post 1Post 0post_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'
    );
5
londonfed

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のため、nullfield_order値を持つ行があり、それらはASC orderbyの数値field_order値の前にあります。

これを修正するために、 here に記述されているようにORDER BY -field_order DESCトリックを使用します。

これはDESCASCに反転することによって順序を修正しますが、数値の後に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秒かかります。ただし、数百万、さらには数十万の投稿がある場合は、クエリを最適化するか、同じ結果を得るためのより効率的な方法を見つける必要があります。

5
Fayaz