web-dev-qa-db-ja.com

複数のキーでmeta_queryを使用して値を比較する

私はこれで棒で月を求めているかもしれないと思います、しかし:

showsカスタム投稿タイプ用のフィルタがあります。フィルタはshowsに添付された標準的な分類法を使用しますが、各番組のメタ値であるVenueによって、または各番組に開始日が添付されているので月ごとにフィルタすることもできます。

私が遭遇した問題はいくつかのショーが複数の月にまたがるかもしれないということです。そのため、2014年11月に実行を開始し、12月に終了します。このために、メタ値を次のように格納しています。

startdate   => 20141225
enddate     => 20141224

理想的には、誰かが2014年12月の番組にフィルタをかけた場合、両方とも12月中に始まる番組、または12月末までの番組を表示します。問題は、venue meta_valueもrelation => 'AND'でチェックしているため、[pseudocode]をチェックする方法がわからないことです。 WHERE venue == 'royal-playhouse' AND ((startdate BETWEEN array(20141201, 20141231)) OR (enddate BETWEEN array(20141201, 20141231)))

私は渡されたpre_get_posts引数を修正するために$queryフィルタを使用しています、そしてフィルタと共に使用されるさらに2つのmeta_valueフィールドがあることに注目する価値があります(show type、accessibilityなど)。これが私のコードを簡略化したものです(現在は完全に機能しますが、startdateに対してのみチェックされます)。

function showDates_orderQuery($query) {
    if ($query->is_main_query() && !is_admin() && is_post_type_archive('showdates')) {

        $queryVenue = $query->query_vars['venue'];
        $queryMonth = $query->query_vars['month'];

        $metaQuery = array();

        //  Venue meta

        if ($queryVenue) {
            $metaQuery[] = array(
                'key'       => 'venue',
                'value'     => array($queryVenue),
                'compare'   => 'IN',
            );
        }

        //  Month meta

        if ($queryMonth) {

            $monthEpoch = strtotime($queryMonth);
            $formattedQueryMonth = date('Ymd', $monthEpoch);
            $formattedEndOfQueryMonth = date('Ymt', $monthEpoch);

            $metaQuery['relation'] = 'AND'; //  Set because we want to check for shows from a venue AND by the given month

            $metaQuery[] = array(
                'key'       => 'startdate',
                'value'     => array($formattedQueryMonth, $formattedEndOfQueryMonth),
                'compare'   => 'BETWEEN',
                'type'      => 'DATE'
            );
        }

        if ($metaQuery) {
            $query->set('meta_query', $metaQuery);
        }

        $query->set('meta_key', 'startdate');
        $query->set('orderby', 'meta_value');
        $query->set('order', 'ASC');
    }
}

add_action('pre_get_posts', 'showDates_orderQuery');

私がこれを達成することができる方法についてのどんな考えでも感謝して受け取られるでしょう。

1
indextwo

私は完全な馬鹿なので、私は 基本的に1年以上前に私自身の質問に答えました を完全に忘れてしまったようです。

私はposts_joinフィルタを動作させるのに苦労していました(私は一般的にとにかくINNER JOINsに問題があります)ので、代わりにposts_whereフィルタを探しました。これに関する主な問題は、既存の$where条件以外に引数を渡すことができないということです。この例では、非グローバル変数を使用したいと思いました。

答えは、posts_whereフィルタにインラインの無名Lambda関数を使用することでした。

if ($queryMonth) {

    $monthEpoch = strtotime($queryMonth);
    $formattedQueryMonth = date('Ymd', $monthEpoch);
    $formattedEndOfQueryMonth = date('Ymt', $monthEpoch);

    $monthOptions = array(
        'monthstart' => $formattedQueryMonth,
        'monthend' => $formattedEndOfQueryMonth,
    );

    $monthFilter = function ($where = '') use ($monthOptions) {
        global $wpdb;
        $where .= " AND (($wpdb->postmeta.meta_key = 'startdate' AND $wpdb->postmeta.meta_value >= '" . $monthOptions['monthstart'] . "') AND ($wpdb->postmeta.meta_key = 'startdate' AND $wpdb->postmeta.meta_value <= '" . $monthOptions['monthend'] . "')) ";
        $where .= " OR (($wpdb->postmeta.meta_key = 'enddate' AND $wpdb->postmeta.meta_value >= '" . $monthOptions['monthstart'] . "') AND ($wpdb->postmeta.meta_key = 'enddate' AND $wpdb->postmeta.meta_value <= '" . $monthOptions['monthend'] . "')) ";
        return $where;
    };

    add_filter('posts_where', $monthFilter);
}

運が良ければ、 今後の4.1のリリース のおかげでこのメソッドは実際には次の数週間で完全に冗長になるはずです ヘッドアップ .

0
indextwo

あなたのタイムラインやあなたがEdgeでどれだけ生きたいかに応じて、4.1に導入されるように設定されているいくつかの大きな改善がありました。 Edgeを少し使いたい場合は、4.1ベータ版で開発して起動時にそのリリースに切り替えることができます(見つかった場合は必ずバグレポートを提出してください)。

これはもう少し詳しく説明するmake postへのリンクです: https://make.wordpress.org/core/2014/10/20/update-on-query-improvements -in-4-1 /

1
jmusal

そのような方法がないのでそれをする方法を把握できません。そのようなANDとORをmeta_queryと混在させることはできません。クエリシステムは素晴らしいですが、すべてを網羅しているわけではありません。複数のクエリを使用するか、SQLを自分でフィルタリングする必要があります。

0
Otto