web-dev-qa-db-fra.com

Comment gérer la date de fin facultative dans la clause de comparaison dans meta_query

J'ai un message personnalisé de type event dans WordPress, et je dois interroger la prochaine eventposts en comparant $current_date.

Les conditions de requête sont:

  • start_date est une date valide toujours
  • end_date peut être une chaîne date ou null ou empty valide.
  • SI end_date est une date valide dans l'enregistrement de la base de données, puis comparez end_date >= $current_date
  • ELSE SI end_date est null ou empty, puis comparez start_date >=$current_date.

Maintenant, si end_date n'était pas optionnel, je pourrais utiliser le code ci-dessous pour obtenir les résultats souhaités.

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

Mon problème est, comment puis-je gérer facultatif end_date dans le code ci-dessus.

Merci d'avance.

Edit: code reformaté et texte ci-dessus pour le rendre plus clair

5
Dashrath

Pour ce faire, il n'est pas nécessaire de créer une requête SQL personnalisée. Depuis la version 4.1, les classes de requêtes de WordPress ont pris en charge les méta-requêtes complexes/imbriquées . Vous pouvez donc créer une requête comme celle-ci:

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

J'ai testé cela et cela fonctionne parfaitement. Mon test 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.

Je pense que je sais ce que vous vivez ... J'ai récemment dû faire face à une situation dans laquelle je comparais (entre autres choses) une méta-valeur qui peut exister ou non.

La solution que j'ai trouvée impliquait une déclaration très folle SQl, avec une clause WHERE IF.

Dans votre cas, cela pourrait ressembler à ceci (explication ci-dessous):

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
}

(Notez que ceci a été testé sur une configuration similaire, mais pas avec vos champs de méta de post exacts. Peut nécessiter un peu de peaufinage).

Premièrement, nous obtenons la variable globale wpdb, pour accéder à la base de données brute wordpress.

Ensuite, nous préparons une requête SQL qui obtient des publications et les joint avec des méta-valeurs de publication (pour comparaison)

MAIS. Voici le truc. L'instruction WHERE a les deux meta_key, meta_value.

Nous savons que meta_value est toujours le même, c'est-à-dire la date actuelle.

Donc, pour meta_key, nous exécutons une instruction IF qui vérifie le nombre de lignes de méta de publication de l'ID de publication actuel lorsque sa clé de méta est égale à 'date_fin'.

S'il contient plus de 0 lignes, définissez meta_key sur 'end_date' (deuxième argument de la fonction IF), sinon définissez-le sur 'date_début' (troisième argument).

Nous vérifions également le type de message et nous nous assurons qu'il est publié et limitons le retour à 10 (ou celui que vous souhaitiez).

Enfin, nous récupérons les résultats pour les utiliser à notre guise.

Je sais que c'est un peu un bidouillage, mais ça marche. C'est aussi un peu lent, donc peut-être utile de mettre en cache les résultats

J'espère que c'est ce que vous recherchez! Et si vous trouvez une meilleure solution, merci de me le faire savoir :)

1
Pedro Coitinho

Je fais cette requête pour votre question. Veuillez le vérifier. Laissez-moi savoir que ça marche ?.

$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

Je vois des solutions géniales, ici; mais pourrions-nous trop y penser?

Cela fonctionnerait-il ...

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

Peut-être encore je ne vous ai pas compris

0
TrubinE