J'ai deux champs personnalisés:
meta_key1
est booléen (0
ou 1
).meta_key2
est une valeur de date - 20150623
par exemple.Tous les champs meta_key2
n'ont pas de valeur explicite. On dirait qu'ils sont traités comme une chaîne vide ''
.
J'aimerais trouver toutes les publications qui ont une valeur meta_key2
(date) supérieure à celle d'aujourd'hui ou une valeur meta_key1
qui est true.
C'est l'ordre que je voudrais qu'ils affichent.
key2.meta_value >= today ASC
key1.meta_value = TRUE ordered by date ASC
(ceux avec les dates données en premier).
Une partie du problème réside dans le fait que les champs avec un paramètre de date vide semblent être traités en tant que 0
et arrivent donc en premier dans l'ordre ASC
. J'ai essayé d'utiliser COALESCE
pour expliquer cela et j'ai eu du succès, mais je suis suspendu à une partie. Je ne parviens pas à afficher les articles key1.meta_value = FALSE
et key2.meta_value is >= today
dans l'ordre ASC
.
Voici ma requête:
$meta_key1 = 'prog_ongoing';
$meta_key2 = 'prog_date_start';
$start_date = date('Ymd');
$postids = $wpdb->get_col( $wpdb->prepare(
"
SELECT DISTINCT key1.post_id
FROM $wpdb->postmeta key1
INNER JOIN $wpdb->postmeta key2
ON key2.post_id = key1.post_id
AND key2.meta_key = %s
WHERE key1.meta_key = %s
AND key1.meta_value is TRUE
OR key2.meta_value >= %d
ORDER BY COALESCE(NULLIF(key1.meta_value, 0), 0) DESC, COALESCE(NULLIF(key2.meta_value, ''), $start_date) ASC, key2.meta_value ASC
",
$meta_key2,
$meta_key1,
$start_date
) );
Je ne suis pas sûr que ma déclaration COALESCE
sur key1.meta_value
fasse quoi que ce soit. Merci pour toute idée à ce sujet.
Un problème avec la requête est que la jointure automatique avec la WHERE
ambiguë vous donne un jeu de données croisé (masqué par la DISTINCT
), il serait donc plus simple d'utiliser wp_post
comme base pour attacher les jointures qui correspondent exactement aux clés, par exemple
SELECT p.ID, key1.meta_value as prog_ongoing, key2.meta_value as prog_date_start
FROM $wpdb->posts p
INNER JOIN $wpdb->postmeta key1
ON key1.post_id = p.ID
AND key1.meta_key = %s
INNER JOIN $wpdb->postmeta key2
ON key2.post_id = p.ID
AND key2.meta_key = %s
ce qui donne un jeu de données linéaire. Ensuite, vous pouvez ajouter (ou non) la clause WHERE
pour restreindre les données:
WHERE key1.meta_value IS TRUE OR key2.meta_value >= %d
et pour le ORDER BY
, utilisez un tri de champs uniques dans l'instruction CASE
:
ORDER BY CASE
WHEN key2.meta_value >= %d THEN CONCAT('A', key2.meta_value)
WHEN key1.meta_value AND key2.meta_value THEN CONCAT('B', key2.meta_value)
WHEN key1.meta_value THEN 'C'
ELSE 'D'
END ASC
ou quelque chose de similaire, ce qui précède a besoin de la variable prepare
pour être:
$meta_key1,
$meta_key2,
$start_date, $start_date
Vous pouvez utiliser le filtre posts_orderby
pour faire quelque chose de similaire avec WP_Query
(bien qu'il utilise une méthode qui produit des jeux de données croisés, obligeant celui-ci à utiliser un GROUP BY
, ce qui peut compliquer les choses). Par exemple
$args = array(
'posts_per_page' => -1,
'post_type' => 'cpt_program',
'meta_query' => array(
'ongoing' => array(
'key' => 'prog_ongoing',
),
'start_date' => array(
'key' => 'prog_date_start',
)
),
);
add_filter( 'posts_orderby', $func = function ( $orderby, $query ) {
$start_date = date('Ymd');
global $wpdb;
$orderby = $wpdb->prepare(
"
CASE
WHEN mt1.meta_value >= %d THEN CONCAT('A', mt1.meta_value)
WHEN {$wpdb->postmeta}.meta_value AND mt1.meta_value THEN CONCAT('B', mt1.meta_value)
WHEN {$wpdb->postmeta}.meta_value THEN 'C'
ELSE 'D'
END ASC
"
, $start_date
);
return $orderby;
}, 10, 2 );
$query = new WP_Query( $args );
remove_filter( 'posts_orderby', $func, 10, 2 );
Premier passage pour une solution. Il utilise le nouveau méta-tri introduit dans la version 4.2:
<?php
$args = array(
'posts_per_page' => -1,
'meta_query' => array(
'relation' => 'OR',
'ongoing' => array(
'key' => 'prog_ongoing',
'value' => 1
),
'start_date' => array(
array(
'key' => 'prog_date_start',
'value' => date('Ymd'),
'type' => 'numeric',
'compare' => '>='
)
)
),
'orderby' => 'start_date ongoing',
'order' => 'ASC',
);
$programs = new WP_Query($args);
?>
<?php while($programs->have_posts()): $programs->the_post(); ?>
<h1><?php the_title(); ?></h1>
<?php endwhile; ?>
Je pense que j'ai bien compris la logique, mais laissez-moi savoir si autrement
Vous pouvez vérifier la nouvelle syntaxe pour trier plusieurs champs personnalisés dans Wordpress 4.2 de la manière suivante:
Pourquoi ne pas utiliser WP_Query()
? Beaucoup plus simple de cette façon:
<?php
$args = array(
'posts_per_page' => -1,
'meta_query' => array(
'relation' => 'OR',
array(
'key' => 'prog_ongoing',
'value' => 1
),
array(
'relation' => 'AND',
array(
'key' => 'prog_date_start',
'value' => date('Ymd'),
'type' => 'numeric',
'compare' => '<='
),
array(
'key' => 'prog_date_start',
'value' => 1,
'type' => 'numeric',
'compare' => '>'
)
)
),
'orderby' => 'meta_value_num date',
'order' => 'ASC',
'meta_key' => 'prog_date_start'
);
$programs = new WP_Query($args);
?>
<?php while($programs->have_posts()): $programs->the_post(); ?>
<h1><?php the_title(); ?></h1>
<?php endwhile; ?>