web-dev-qa-db-ja.com

メタ値でソートしますが、持っていない投稿を含めます

私はpre_get_postsフィルターを使用して組み込みのWP検索を変更して、ユーザーがさまざまなフィールドで投稿(多数のカスタム投稿タイプを含む)をソートできるようにしました。

しかし、私が抱えている問題は、WPにメタ値でソートするように指示すると、そのメタ値が設定されていないすべての投稿が除外されることです。 「投稿」には「価格」が設定されていないが「アイテム」に設定されているため、「価格」から「日付」にソートを変更すると、結果の数が変わります。

これは私が望んでいることではないので、すべての投稿を含める方法があるかどうか - 私がソートしているメタ値を欠いているものでも - そして値のないものを最後に置くかどうか知りたい.

複数のフィールドを並べ替える方法を知っていますが、それは役に立ちません。

ありがとう

私はこの質問で唯一のものではないようです: wp_queryの引数に特定のmeta_keyがある場合とない場合の両方で投稿を含める方法? しかし解決策はありません。

更新

私は答えを試しましたが、私が正しく理解したかどうかわからない、これが私が今持っているものです:

<?php
function my_stuff ($qry) {
    $qry->set('meta_query', array(array(
        'key' => 'item_price', 
        'value' => '', 
        'compare' => 'NOT EXISTS'
    )));

    $qry->set('orderby', 'meta_value date'); # Sorting works with meta_value as well as meta_value_num - I've tried both
    $qry->set('order', 'ASC DESC');
    $qry->set('meta_key', 'item_price');
}

メタ値は数値です(名前が示すとおり、価格を格納するために使用されます)。

更新2

私は注文のものをコメントアウトしました、そして私が今持っているのはこれだけです:

<?php
$qry->set('meta_query', array(array(
    'key' => 'item_price', 
    'value' => '', 
    'compare' => 'NOT EXISTS'
)));

このコードでは、クエリはitem_priceキーを持たないすべての投稿を返し、それを持つ投稿は返しません。 I.E.問題は今反転されます。

注文コードを追加した場合、結果は0になります。

編集:... 3年後...:P私は再びこの問題を抱えていた。私は与えられたすべての答えを試しましたが、うまくいきませんでした。何人かの人々が彼らが働いていると思うように見えるが、彼らは少なくとも私のために働いていない理由がわからない。

解決した解決策はsave_postフィルタを使用することです。すべての投稿に並べ替えたいカスタムフィールドがあることを確認してください。それは私がやらなければならない少し面倒ですが、あなたが早くそれをしさえすれば、おそらく問題はないでしょう。

この場合、私は投稿に「表示カウンター」を構築していて、ユーザーが最も読んだ投稿をソートできるようにしたいと考えていました。繰り返しますが、これまで一度も表示されたことのない投稿(これはほとんどありそうにないと思いますが、それでもまだ)は、表示件数でソートすると消えます。すべての投稿に表示回数があることを確認するために、このコードを追加しました。

add_action('save_post', function ($postId) {
    add_post_meta($postId, '_sleek_view_count', 0, true);
});
30
powerbuoy

これに対して2つの可能な解決策があります:

1.すべての投稿にメタがあります

私がここで見つけた最良の解決策は、残りの投稿/商品に0のアイテム価格を与えることです。あなたはこれを手動で行うことができますまたは価格が空の場合それを更新します。

将来これを管理しやすくするために、save_postにフックしてそれらが最初に追加されたときに値を与えることができます(空白の場合のみ)。

複数のクエリ

最初のクエリを実行中に実行し、返された投稿のIDを保存することができます。その後、すべての投稿とorderby dateに対して別のクエリを実行することができます。 除外する /最初のクエリから返されるID。

その後、2つの結果を別々に注文して印刷すると、目的の結果が得られます。

5
Steven Jones

Easy Peasy、2018年テスト済み、現在プロダクションで使用中。

$query->set( 'meta_query', array(
    'relation' => 'OR',
    array(
        'key' => 'custom_meta_key', 
        'compare' => 'EXISTS'
    ),
    array(
        'key' => 'custom_meta_key', 
        'compare' => 'NOT EXISTS'
    )
) );
$query->set( 'orderby', 'meta_value title' ); 

これは、値が指定されていない、メタキーの有無にかかわらずすべての項目をチェックします。メタクエリはオーダーバイのキーを確実に提供します。それはテストされています。ただし、メタクエリで複数のキーが使用されている場合にどのように機能するかはわかりません。

実例

/**
 * Modifies query before retrieving posts. Sets the 
 * `meta_query` and `orderby` param when no `orderby` 
 * param is set, (default ordering).
 * 
 * @param   WP_Query  $query  The full `WP_Query` object.
 * @return  void
 */
function example_post_ordering( $query ) {

    // if not in wp-admin, 
    // and the query is the main query, 
    // and the query is not a singular query, 
    // and the query does not have an orderby param set...
    // Note: check for post types, etc. here as desired.
    if ( ! is_admin() 
    && $query->is_main_query() 
    && ! $query->is_singular() 
    && empty( $query->get( 'orderby' ) ) ) {

        // Setting just `meta_key` is not sufficient, as this 
        // will ignore posts that do not yet, or never will have 
        // a value for the specified key. This meta query will 
        // register the `meta_key` for ordering, but will not 
        // ignore those posts without a value for this key.
        $query->set( 'meta_query', array(
            'relation' => 'OR',
            array(
                'key' => 'custom_meta_key', 
                'compare' => 'EXISTS'
            ),
            array(
                'key' => 'custom_meta_key', 
                'compare' => 'NOT EXISTS'
            )
        ) );

        // Order by the meta value, then by the title if multiple 
        // posts share the same value for the provided meta key.
        // Use `meta_value_num` if the meta values are numeric.
        $query->set( 'orderby', 'meta_value title' );
    }

}

add_action( 'pre_get_posts', 'example_post_ordering', 10 );

これはデフォルトで投稿をcustom_meta_keyで順序付けし、そのキーの値がない投稿を無視しません。

4
noahmason

私は解決策があると思います。

2つのmeta_keyを使用できます。1つはすべての投稿に(like "_thumbnail_id")があり、1つはフィルタとして使用するmeta_keyです。

だからあなたの引数:

$qry->set(
    'meta_query',
    array(
        'relation' => 'OR',
        array(
            'key' => 'item_price', 
            'value' => '', 
            'compare' => 'EXISTS'
        ),
        array(
            'key' => 'item_price', 
            'value' => '', 
            'compare' => 'EXISTS'
        )
    )
);

$qry->set('orderby', 'meta_value date'); # Sorting works with meta_value as well as meta_value_num - I've tried both
$qry->set('order', 'ASC DESC');
$qry->set('meta_key', 'item_price');
2
Rafael M31

適切な場合、投稿が保存または更新されるたびに、デフォルトのメタ値を追加できます(メタ値が存在しない場合)。

function addDefaultMetaValue($post_id) {
    add_post_meta($post_id, 'item_price', 0, true);
}
add_action('save_post', 'addDefaultMetaValue');

カスタム投稿タイプを使用している場合は、add_action('save_post', 'addDefaultMetaValue');add_action('save_post_{post_type}', 'addDefaultMetaValue');に置き換えます。 add_action('save_post_product', 'addDefaultMetaValue');

1
rjpedrosa

私は自分で数値メタ値の問題を抱えていて、それがクエリの順番も重要であることを指摘しました。私にとってはNOT EXISTSクエリは最初のものでなければなりません。

例:

$query->set( 'orderby', 'meta_value_num' );
$query->set( 'meta_query', [
    'relation' => 'OR',
    [ 'key' => 'your_meta_name', 'compare' => 'NOT EXISTS' ],
    [
        'key' => 'your_meta_name',
        'compare' => 'EXISTS',
    ],
] );

数値の正しい方向性を得るためにも重要なのは、一般的な’orderby’’meta_value_num’に設定することです。そうでなければ、あなたは数値に対して奇妙な結果を得るでしょう。 g .:

1、2、20、21、3、4、5…

の代わりに:

1、2、3、4、5…20、21

0
KittMedia

そのためのorderby値としてmeta_valueがあります。

$query = new WP_Query( array ( 
    'meta_key'   => 'your_keys_name',
    'orderby'    => 'meta_value',
    'order'      => 'DESC',
    'meta_query' => array( array(
         'key'     => 'your_meta_key',
         'value'   => '',
         'compare' => 'NOT EXISTS',
         // 'type'    => 'CHAR',
    ) )
) );

数値が得られた場合は、代わりにmeta_value_numを使用してください。

免責事項: これはテストされていませんが、 動作するはずです 。重要なのは、meta_keykeyの値を指定する必要があるということです。そうでなければ、存在しない値と比較することはできません。両方の種類の投稿をクエリすることが可能になるはずです。それはある種のハックっぽい方法ですが、うまくいく限りは...

0
kaiser

私はちょっとしたハック(IMHO)でこれを回避することになりました、しかしそれは私の場合私のために仕事をしました。

結合文字列と順序文字列を更新するには、フィルタ posts_join_paged および posts_orderby にフックします。これは、WP_Queryがその特定の投稿に対して存在しなければならないと仮定するのではなく、最初に参加する限り、あなたが望むものなら何でもで注文することを可能にします。その後、WP_Query引数からmeta_keyorderby、および `orderを削除できます。

以下は一例です。それはWP_Queryを使用するすべてのものにこれを追加するので、私は特定のケースのために脱出しなければならなかった各関数の一番上で。あなたはあなたの特定のニーズに合うようにそれを修正する必要があるかもしれません。

これら2つのフィルタに関するドキュメントは残念ながら欠けているので…幸運を祈ります! :)

add_filter('posts_join_paged', 'edit_join', 999, 2);
add_filter('posts_orderby', 'edit_orderby', 999, 2);

/**
 * Edit join
 *
 * @param string $join_paged_statement
 * @param WP_Query $wp_query
 * @return string
 */
function edit_join($join_paged_statement, $wp_query)
{
    global $wpdb;
    if (
        !isset($wp_query->query)
        || $wp_query->is_page
        || $wp_query->is_admin
        || (isset($wp_query->query['post_type']) && $wp_query->query['post_type'] != 'my_custom_post_type')
    ) {
        return $join_paged_statement;
    }

    $join_to_add = "
        LEFT JOIN {$wpdb->prefix}postmeta AS my_custom_meta_key
            ON ({$wpdb->prefix}posts.ID = my_custom_meta_key.post_id
                AND my_custom_meta_key.meta_key = 'my_custom_meta_key')
    ";

    // Only add if it's not already in there
    if (strpos($join_paged_statement, $join_to_add) === false) {
        $join_paged_statement = $join_paged_statement . $join_to_add;
    }

    return $join_paged_statement;
}

/** 
 * Edit orderby
 *
 * @param string $orderby_statement
 * @param WP_Query $wp_query
 * @return string
 */
function edit_orderby($orderby_statement, $wp_query)
{
    if (
        !isset($wp_query->query)
        || $wp_query->is_page
        || $wp_query->is_admin
        || (isset($wp_query->query['post_type']) && $wp_query->query['post_type'] != 'my_custom_post_type')
    ) {
        return $orderby_statement;
    }

    $orderby_statement = "my_custom_meta_key.meta_value DESC";

    return $orderby_statement;
}
0
Scruffy Paws

私も同様の問題に遭遇しました、そして、以下の解決策は私を助けました:

$args = array(
'post_type' => 'kosh_products',
'posts_per_page' => -1,
'meta_query' => array(
    'relation' => 'OR',
    'category_sort_order' => array(
        'key' => '_sort_order',
        'compare' => 'EXISTS'
    ),
    'category_sort_order_not_exists' => array(
        'key' => '_sort_order',
        'compare' => 'NOT EXISTS'
    ), 
),
'orderby' => array( 
    'category_sort_order' => 'ASC',
    'date' => 'ASC'
));
$query = new WP_Query( $args );

私はタイトルが "'orderby"、複数の' meta_key's "でWordPress Codexについての説明を見つけました: https://codex.wordpress.org/Class_Reference/WP_Query#Order_.26_Orderby_Parametersenter image description here

0
Ilya Kogan

@kaiserがやろうとしていたのは、疑似の where条件 to not を適用することによって、そのメタキーを持つすべての投稿を返すようにクエリに指示することだったと思います。もしあなたが all を知っていればあなたのカスタムフィールドが取ることができる値はx、y、zですあなたは "WHERE meta_key IN(x、y、z) "と言うことができます !=( '') と言うことで、この問題をまとめて解決できます。

$query = new WP_Query( array ( 
    'orderby'    => 'meta_value_num',
    'order'      => 'DESC',
    'meta_query' => array( array(
         'key'     => 'item_price',
         'value'   => '',
         'compare' => '!=',
    ) )
) );

テストもされていませんが、試してみる価値があるようです:-)。

0
Jon

ここにいるすべての人が抱えている問題は、メタクエリの順序に関係しています。正しくソートするためには、 "NOT EXISTS"クエリ の前に "EXISTS"クエリを追加する必要があります。

これは、WordPressが "ORDER BY"節の最後の "LEFT JOIN"ステートメントのmeta_valueを使用しているためです。

例えば:

$pageQuery = new WP_Query([
    'meta_query' => [
        'relation' => 'OR',
        ['key' => 'item_price', 'compare' => 'NOT EXISTS'], // this comes first!
        ['key' => 'item_price', 'compare' => 'EXISTS'],
    ],
    'order' => 'DESC',
    'orderby' => 'meta_value_num',
    'post_status' => 'publish',
    'post_type' => 'page',
    'posts_per_page' => 10,
]);
0
Paul