web-dev-qa-db-ja.com

Meta_queryのcompare句でオプションの終了日を処理する方法

私はWordPressにカスタム投稿タイプeventを持っています、そして私は$current_dateを比較して今後のeventpostsを問い合わせる必要があります。

照会条件は以下のとおりです。

  • start_dateは常に有効なdateです
  • end_dateは、有効なdatenull、またはemptyの文字列です。
  • end_dateがdbレコード内の有効なdateである場合、end_date >= $current_dateを比較します。
  • ELSE IF end_datenullまたはemptyの場合、start_date >=$current_dateと比較してください。

end_dateがオプションではない場合は、以下のコードを使用して目的の結果を得ることができます。

$args= array();
$args['post_type'] = "event";
$args['meta_query'] = array(
      array(
           'key'        => 'end_date',
           'compare'    => '>=',
           'value'      => date("Ymd",$current_date),
       )
);
$post_query = new WP_Query();
$posts_list = $post_query->query($args);

私の問題は、上記のコードでオプションのend_dateをどのように処理するかです。

前もって感謝します。

編集:上記のコードとテキストを見やすくするために再フォーマット

5
Dashrath

これを達成するためにカスタムSQLクエリを作成する必要はありません。バージョン4.1以降、WordPressのクエリクラスは 複雑な/入れ子になったメタクエリをサポートしました だからあなたはこのようなクエリを作成することができます:

    $args['meta_query'] = array(
        // Use an OR relationship between the query in this array and the one in
        // the next array. (AND is the default.)
        'relation' => 'OR',
        // If an end_date exists, check that it is upcoming.
        array(
            'key'        => 'end_date',
            'compare'    => '>=',
            'value'      => date( 'Ymd', $current_date ),
        ),
        // OR!
        array(
            // A nested set of conditions for when the above condition is false.
            array(
                // We use another, nested set of conditions, for if the end_date
                // value is empty, OR if it is null/not set at all. 
                'relation' => 'OR',
                array(
                    'key'        => 'end_date',
                    'compare'    => '=',
                    'value'      => '',
                ),
                array(
                    'key'        => 'end_date',
                    'compare'    => 'NOT EXISTS',
                ),
            ),
            // AND, if the start date is upcoming.
            array(
                'key'        => 'start_date',
                'compare'    => '>=',
                'value'      => date( 'Ymd', $current_date ),
            ),
        ),
    );

私はこれをテストしました、そしてそれは完全に動作します。私のPHPUnitテストケース:

/**
 * Tests something.
 */
class My_Plugin_Test extends WP_UnitTestCase {

    public function test_wpse() {

        $current_time = current_time( 'timestamp' );
        $current_date = date( 'Ymd', $current_time );
        $yesterday_date = date( 'Ymd', strtotime( 'yesterday' ) );

        $post_ids = $this->factory->post->create_many( 6 );

        $post_with_end_past  = $post_ids[0];
        $post_with_end_now   = $post_ids[1];
        $post_empty_end_past = $post_ids[2];
        $post_empty_end_now  = $post_ids[3];
        $post_null_end_past  = $post_ids[4];
        $post_null_end_now   = $post_ids[5];

        // This post has an end date in the past.
        update_post_meta( $post_with_end_past, 'start_date', $yesterday_date );
        update_post_meta( $post_with_end_past, 'end_date', $yesterday_date );

        // This post has an end date in the present.
        update_post_meta( $post_with_end_now, 'start_date', $yesterday_date );
        update_post_meta( $post_with_end_now, 'end_date', $current_date );

        // This post has no end date, but a start date in the past.
        update_post_meta( $post_empty_end_past, 'start_date', $yesterday_date );
        update_post_meta( $post_empty_end_past, 'end_date', '' );

        // This post has an empty end date, but the start date is now.
        update_post_meta( $post_empty_end_now, 'start_date', $current_date );
        update_post_meta( $post_empty_end_now, 'end_date', '' );

        // This post has no end date set at all, and the start date is past.
        update_post_meta( $post_null_end_past, 'start_date', $yesterday_date );

        // This post has no end date set at all, but the start date is now.
        update_post_meta( $post_null_end_now, 'start_date', $current_date );

        $args = array();
        $args['fields'] = 'ids';
        $args['meta_query'] = array(
            // Use an OR relationship between the query in this array and the one in
            // the next array. (AND is the default.)
            'relation' => 'OR',
            // If an end_date exists, check that it is upcoming.
            array(
                'key'        => 'end_date',
                'compare'    => '>=',
                'value'      => $current_date,
            ),
            // OR!
            array(
                // If an end_date does not exist.
                array(
                    // We use another, nested set of conditions, for if the end_date
                    // value is empty, OR if it is null/not set at all.
                    'relation' => 'OR',
                    array(
                        'key'        => 'end_date',
                        'compare'    => '=',
                        'value'      => '',
                    ),
                    array(
                        'key'        => 'end_date',
                        'compare'    => 'NOT EXISTS',
                    ),
                ),
                // AND, if the start date is upcoming.
                array(
                    'key'        => 'start_date',
                    'compare'    => '>=',
                    'value'      => $current_date,
                ),
            ),
        );

        $post_query = new WP_Query();
        $posts_list = $post_query->query( $args );

        // Only the "now" posts should be returned.
        $this->assertSame(
            array( $post_with_end_now, $post_empty_end_now, $post_null_end_now )
            , $posts_list
        );
    }
}
6
J.D.

私はあなたが何を経験しているのか知っていると思います...私は最近私が(とりわけ)存在するかもしれないしないかもしれないメタ値を比較していた状況に対処しなければなりませんでした。

私が見つけた解決策は、WHERE IF句を含む非常に狂ったSQl文を含んでいました。

あなたの場合、それはこのように見えるでしょう(下記の説明):

global $wpdb;

// prepare SQL statement
$sql = $wpdb->prepare("
  SELECT * 
  FROM $wpdb->posts
  INNER JOIN $wpdb->postmeta
    ON $wpdb->posts.ID = $wpdb->postmeta.post_id
  WHERE post_type = 'event'
    AND post_status = 'publish'
    AND IF(
      (
        SELECT COUNT( post_id) 
        FROM $wpdb->postmeta 
        WHERE meta_key = 'end_date' 
        AND post_id = ID 
      ) > 0,
      meta_key = 'end_date',
      meta_key = 'start_date'
    )
    AND meta_value >= %s
  LIMIT %d
", date( 'Ymd'), 10 );

// get results
$results = $wpdb->get_results( $sql );

// iterate through results
foreach( $results as $result ) {
  setup_postdata( $result );

  // your loop
}

(これは同様の設定でテストされていますが、あなたの正確な投稿メタフィールドではテストされていません。ちょっとした調整が必要かもしれません)。

最初に、生のワードプレスデータベースにアクセスするためのグローバルなwpdb変数を取得します。

それから、投稿を取得し、それらを投稿メタ値と結合するSQLクエリを準備します(比較のために)

しかし。これがトリックです。 WHEREステートメントにはmeta_keymeta_valueの両方があります。

meta_valueは常に同じ、つまり現在の日付です。

meta_keyでは、現在の投稿IDのメタキーが 'end_date'に等しい場合に、投稿メタ行の数を確認するIFステートメントを実行します。

行数が0を超える場合はmeta_keyを 'end_date'(IF関数の2番目の引数)に設定し、それ以外の場合は 'start_date'(3番目の引数)に設定します。

また、投稿の種類を確認し、投稿が公開されていることを確認し、返品を10件(または希望するもの)に制限します。

最後に、結果を取り出して必要に応じて使用します。

ちょっとしたハックを知っていますが、うまくいきます。それはまた少し遅いので、結果をキャッシュする価値があるかもしれません

それがあなたが探しているものであることを願っています!そして、あなたがより良い解決策を見つけたら、私に知らせてください:)

1
Pedro Coitinho

私はあなたの問題に対してこの質問をします。ご確認ください。それがうまくいっているか教えてください。

$global $wpdb;

$qry = "SELECT * from $wpdb->posts t1 WHERE t1.post_type='event' and t1.ID IN (SELECT t2.post_id from $wpdb->postmeta t2 WHERE ( CASE WHEN t2.meta_key = 'end_date' AND t2.meta_value IS NULL THEN t2.meta_key = 'start_date' AND t2.meta_value >= '". $currentdate ."' ELSE t2.meta_key = 'end_date' AND t2.meta_key >= '". $currentdate ."' END ))"

$post_query = new WP_Query();
$posts_list = $post_query->query($qry);
0
Thilak

私はここでいくつかの素晴らしい解決策を見ています。しかし、私たちはそれを考え直すことができますか?

これでうまくいくでしょうか...

$args= array();
$args['post_type'] = "event";
$args['meta_query'] = array();

if (!empty($end_date) && strtotime($end_date)) {
    $args['meta_query'][] = array(
        'key'        => 'end_date',
        'compare'    => '>=',
        'value'      => date("Ymd",$current_date),
    );
} elseif (!empty($start_date) && strtotime($start_date)) {
    $args['meta_query'][] = array(
        'key'        => 'start_date ',
        'compare'    => '>=',
        'value'      => date("Ymd",$current_date),
    )
}

$post_query = new WP_Query();
$posts_list = $post_query->query($args);
0
PSD to Final
//  $startday, $endday - format YYYY-MM-DD and field format: YYYY-MM-DD      
        $args= array();    
        $args['post_type'] = "event";
        $args['meta_query'] = array(
              relation' => 'OR',   
              array(
                            'key'        => 'end_date',
                            'value' => array( $startday, $endday ),
                            'type' => 'DATE',
                            'compare' => 'BETWEEN'
               ),       
              array(
                            'key'        => 'start_date',
                            'value' => array( $startday, $endday ),
                            'type' => 'DATE',
                            'compare' => 'BETWEEN'
               )          
        );
        $post_query = new WP_Query();
        $posts_list = $post_query->query($args);

おそらくまた私はあなたを理解していませんでした

0
TrubinE