it-swarm.com.de

Behandlung des optionalen Enddatums in der compare-Klausel in meta_query

Ich habe einen benutzerdefinierten Beitragstyp event in WordPress und ich muss anstehende eventposts abfragen, um den $current_date zu vergleichen.

Abfragebedingungen sind:

  • start_date ist immer eine gültige date
  • end_date kann eine gültige date oder null oder empty Zeichenfolge sein.
  • WENN end_date eine gültige date in db record ist, dann vergleiche end_date >= $current_date
  • ELSE WENN end_datenull oder empty ist, dann vergleiche start_date >=$current_date.

Wenn end_date nicht optional war, konnte ich den folgenden Code verwenden, um die gewünschten Ergebnisse zu erzielen.

$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);

Mein Problem ist, wie gehe ich mit optionalem end_date im obigen Code um.

Danke im Voraus.

Bearbeiten: Code und Text oben neu formatiert, um es klarer zu machen

5
Dashrath

Es ist nicht erforderlich, eine benutzerdefinierte SQL-Abfrage zu erstellen, um dies zu erreichen. Seit Version 4.1 unterstützen die Abfrageklassen von WordPress komplexe/verschachtelte Metaabfragen . So können Sie eine Abfrage wie folgt erstellen:

    $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 ),
            ),
        ),
    );

Ich habe das getestet und es funktioniert einwandfrei. Mein PHPUnit-Testfall:

/**
 * 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.

Ich glaube, ich weiß, was Sie gerade durchmachen ... Ich musste mich kürzlich mit einer Situation auseinandersetzen, in der ich (unter anderem) einen Metawert verglichen habe, der möglicherweise existiert oder nicht existiert.

Die Lösung, die ich fand, beinhaltete eine sehr verrückte SQL-Anweisung mit einer WHERE IF-Klausel.

In Ihrem Fall könnte es ungefähr so ​​aussehen (Erklärung unten):

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
}

(Beachten Sie, dass dies mit einem ähnlichen Setup getestet wurde, jedoch nicht mit Ihren exakten Post-Meta-Feldern. Möglicherweise sind einige Anpassungen erforderlich.).

Zuerst erhalten wir die globale Variable wpdb, um auf die rohe WordPress-Datenbank zuzugreifen.

Dann bereiten wir eine SQL-Abfrage vor, die Posts abruft und mit Post-Meta-Werten verknüpft (zum Vergleich).

ABER. Hier ist der Trick. Die WHERE-Anweisung enthält sowohl meta_key als auch meta_value.

Wir wissen, dass der meta_value immer derselbe ist, also das aktuelle Datum.

Also führen wir für meta_key eine IF-Anweisung aus, die überprüft, wie viele Post-Meta-Zeilen die aktuelle Post-ID hat, deren Metaschlüssel gleich 'end_date' ist.

Wenn es mehr als 0 Zeilen hat, setzen Sie meta_key auf 'end_date' (zweites Argument in der IF-Funktion), andernfalls setzen Sie es auf 'start_date' (drittes Argument).

Wir überprüfen auch den Post-Typ und stellen sicher, dass diese veröffentlicht werden und begrenzen die Rückgabe auf 10 (oder was auch immer Sie möchten).

Schließlich holen wir die Ergebnisse, um sie nach Belieben zu verwenden.

Ich weiß, es ist ein bisschen hacken, aber es funktioniert. Es ist auch etwas langsam, es könnte sich also lohnen, die Ergebnisse zwischenzuspeichern

Hoffe das ist was du suchst! Und wenn Sie eine bessere Lösung finden, lassen Sie es mich bitte wissen :)

1
Pedro Coitinho

Ich mache diese Abfrage für Ihr Problem. Bitte überprüfen Sie es. Lassen Sie mich wissen, dass es funktioniert ?.

$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

Ich sehe hier einige großartige Lösungen. aber könnten wir es überdenken?

Würde das funktionieren ...

$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);

Vielleicht habe ich dich wieder nicht verstanden

0
TrubinE