Je dois commander les trois premiers articles par un champ personnalisé et les articles suivants par post_date
en une requête - par exemple:
field_order
: 1)field_order
: 2)field_order
: 3)field_order
: null)field_order
: null)Post 1
et Post 0
doivent être commandés par post_date
.
Je peux facilement commander par champ personnalisé, mais lorsque j'ajoute un article sans le champ personnalisé (Articles 1 et 0), il n'apparaît pas dans la requête.
Ci-dessous la requête que j'essaie actuellement:
$args = array(
'post_type' => 'insights',
'posts_per_page' => '9',
'meta_query' => array(
array(
'key' => 'field_order',
'value' => '0',
'compare' => '>'
)
),
'orderby' => array(
'field_order' => 'ASC',
'post_date' => 'ASC',
),
'order' => 'ASC'
);
meta_query
avec OR
Vous pouvez utiliser l'argument 'relation' => 'OR'
dans meta_query
avec deux jeux d'arguments field_order
: un avec meta_value >= '0'
et l'autre avec NOT EXISTS
pour générer la requête principale.
'meta_query' => array(
'relation' => 'OR',
field_order' => array(
'key' => 'field_order',
'value' => '0',
'compare' => '>=',
'type' => 'NUMERIC'
),
'field_order_withnulls' => array(
'key' => 'field_order',
'compare' => 'NOT EXISTS',
'type' => 'NUMERIC'
)
)
Nous pouvons utiliser 'field_order_withnulls' => 'ASC'
; cependant, en raison de la LEFT JOIN, il y aura des lignes avec des valeurs null
field_order
et celles précédant des valeurs numériques field_order
dans ASC
orderby.
Pour résoudre ce problème, nous allons utiliser l'astuce ORDER BY -field_order DESC
comme décrit ici .
Cela corrigera l'ordre en inversant DESC
en ASC
, mais en conservant les lignes avec les valeurs null
après les valeurs numériques.
-
(inverse) dans orderby
Le problème est que WordPress ne fournit aucun moyen direct de définir l'opérateur -
(inverse) dans orderby
. Nous allons donc introduire un attribut personnalisé WP_Query
nommé _inverse_order
, puis utiliser le filtre posts_orderby
pour le mettre en œuvre.
// posts_orderby filter callback function
// place this function in theme's functions.php file or in a custom plugin
function wpse311227_inverse_orderby( $orderby, $query ) {
remove_filter( 'posts_orderby', 'wpse311227_inverse_orderby', 10, 2 );
$idx = (int) $query->get( '_inverse_order' ) - 1;
if( $idx >= 0 ) {
$orders = preg_split( "/(?<=ASC|DESC),[\s]*/i", $orderby );
if( $idx < count( $orders ) ) {
$orders[$idx] = '-' . $orders[$idx];
}
return implode( $orders, ', ' );
}
return $orderby;
}
// adding the posts_orderby filter to implement the custom '_inverse_order' attribute
// this should be placed just before the WP_Query call
add_filter( 'posts_orderby', 'wpse311227_inverse_orderby', 10, 2 );
$args = array(
'post_type' => 'insights',
'posts_per_page' => '9',
'meta_query' => array(
'relation' => 'OR',
field_order' => array(
'key' => 'field_order',
'value' => '0',
'compare' => '>=',
'type' => 'NUMERIC'
),
'field_order_withnulls' => array(
'key' => 'field_order',
'compare' => 'NOT EXISTS',
'type' => 'NUMERIC'
)
),
'orderby' => array(
'field_order_withnulls' => 'DESC',
'post_date' => 'ASC'
),
// this custom attribute is implemented in wpse311227_inverse_orderby() function
// to correct the ordering by placing a '-' operator
// value of _inverse_order attribute is the position of the
// orderby attribute to be be inversed,
// (position starts with 1)
// in this case, since: 'field_order_withnulls' => 'DESC'
// is in position 1 of 'orderby' attribute array, so:
'_inverse_order' => 1
);
$query = new WP_Query( $args );
Cela produira toutes les publications avec field_order > 0
et les publications qui n'ont pas de métadonnées field_order
avec la commande attendue.
Remarque: _ Vous devrez passer une
value
non vide dansmeta_query
pour unNOT EXISTS
vérifier si la version de WordPress est inférieure à 3.9. Vérifiez cette note du codex :En raison du bogue n ° 23268, une valeur est requise pour que les comparaisons de NOT EXISTS fonctionnent correctement avant la version 3.9. Vous devez fournir une chaîne pour le paramètre value. Une chaîne vide ou NULL ne fonctionnera pas. Cependant, toute autre chaîne fera l'affaire et n'apparaîtra PAS dans votre code SQL lors de l'utilisation de NOT EXISTS.
Attention: _ Ce
WP_Query
utilisera deuxLEFT JOIN
, qui est pas très efficace. Bien que cela ne soit tolérable que pour quelques milliers de messages. J'ai testé avec plus de 15 000 messages et la requête prend environ 0,3 seconde en moyenne. Toutefois, si vous avez des millions, voire des centaines de milliers de messages, vous devrez alors optimiser la requête ou trouver une méthode plus efficace pour obtenir le même résultat.