Requête pour trier une liste par clé méta en premier (si elle existe), et afficher les postes restants sans clé méta classés par titre

19

Je travaille sur un modèle de page de terme de taxonomie personnalisée dans lequel nous voulons que les éléments connectés au terme soient triés par date de publication (champ de date personnalisé) - et s’il existe plusieurs éléments le même jour (au format AAAA). -MM-DD) pour ensuite les trier par titre et enfin par titre si le champ personnalisé n'a pas été renseigné (éléments précédents).

Ainsi, j'ai essayé 100 méthodes différentes avec un WP_query et il renvoie la plupart des résultats tels que je les veux - mais dans ce cas, il ne renvoie que les éléments qui ont la méta_key de publication_date. Tous les autres éléments sont ignorés et ne sont pas affichés. J'ai essayé une méta_query en utilisant une relation "ou" et comparé la publication_date avec EXISTS et NOT EXISTS, mais cela n'a donné aucun résultat.

De plus, le site exécute toujours la version 3.5.2 et ne souhaite pas effectuer de mise à niveau.

Voici ma requête la plus récente qui m'obtient les publications pour lesquelles le champ personnalisé publication_date est affiché dans le bon ordre:

$term = get_queried_object(); // find the term of the taxonomy page we are on
$wp_query = new WP_Query( array(
'post_type' => 'resource',
'tax_query' => array(
    array(
        'taxonomy' => 'resource_types',
        'field' => 'slug',
        'terms' => $term->name,
    )), 

'meta_key' => 'publication_date',
'orderby' => 'meta_value_num',
'order' => 'DESC',
'paged' => $paged,
'posts_per_page' => '10',
));

J'ai également essayé d'utiliser wpdb et de lancer une requête SQL, mais je ne suis vraiment pas sûr de la manière dont je vais accomplir cela. Si quelqu'un pouvait m'aider, ce serait génial!

Merci d'avance.

    
posée CSSgirl 17.12.2013 - 17:06

5 réponses

16

Merci à tous pour votre aide!

En fin de compte, la requête ci-dessous m'a permis d'obtenir les résultats souhaités, à savoir afficher et trier les publications en fonction d'un champ personnalisé intitulé "date_publication" - en triant par date et par type, s'il y en avait plusieurs de la même date (par exemple, , 4 juin 2013), il trierait ceux-ci par titre. Ensuite, après avoir parcouru tous les articles auxquels la date de publication est renseignée, il parcourra à nouveau les articles restants, en ordre alphabétique par titre.

Cela me donne les résultats définis dans la même requête et conserve ma pagination:

$term = get_queried_object();
the_post();
$wp_query = new WP_Query( array(
'post_type' => 'resource',
    'tax_query' => array(
        array(
            'taxonomy' => 'resource_types',
            'field' => 'slug',
            'terms' => $term->name,
        )),
 'meta_query' => array(
       'relation' => 'OR',
        array( //check to see if date has been filled out
                'key' => 'publication_date',
                'compare' => '=',
                'value' => date('Y-m-d')
            ),
          array( //if no date has been added show these posts too
                'key' => 'publication_date',
                'value' => date('Y-m-d'),
                'compare' => 'NOT EXISTS'
            )
        ),
'meta_key' => 'publication_date',
'orderby' => 'meta_value title',
'order' => 'ASC',
'paged' => $paged,
'posts_per_page' => '10',
));
    
réponse donnée CSSgirl 18.12.2013 - 18:00
6

Quelques années plus tard, le code publié par CSSGirl ne fonctionnait pas pour moi car certains messages ne contenaient pas de clé méta ou la clé méta était vide. C’est ce que j’ai dû faire pour que tous les messages classés par date et affichez ceux qui ont une valeur de clé méta:

$args          = array(
'post_type'   => $type,
'post_status' => 'publish',
'nopaging'    => TRUE,
'meta_query'  => array(
    'relation' => 'OR',
    array(
        'key'     => $meta_key,
        'compare' => 'NOT EXISTS',
    ),
    array(
        'relation' => 'OR',
        array(
            'key'   => $meta_key,
            'value' => 'on',
        ),
        array(
            'key'     => $meta_key,
            'value'   => 'on',
            'compare' => '!=',
        ),
    ),
),
'orderby'     => array( 'meta_value' => 'DESC', 'date' => 'DESC' ),
);
    
réponse donnée Ciprian Tepes 26.02.2016 - 17:27
1

Je pense que vous auriez besoin de faire 2 boucles séparées. Vous pouvez capturer tous les articles trouvés dans la première boucle et les exclure assez facilement de la boucle secondaire:

$found_posts = array();
while($loop->have_posts()): $loop->the_post();
    // loop stuff
    $found_posts[] = get_the_id();
endwhile;

wp_reset_query();

$args = array(
    // other args
    'post__not_in' => $found_posts,
);

Ensuite, lancez votre deuxième boucle.

    
réponse donnée GhostToast 17.12.2013 - 17:16
0

Existe-t-il une raison pour laquelle vous ne pouvez pas imposer la clé méta publication_date à chaque poste ayant simplement une valeur vide?

Ainsi, dans votre action save_post , vous ajouteriez / mettriez à jour la clé méta, que la valeur $_POST soit vide ou non.

Il vous faudrait exécuter un script de mise à jour pour lire en boucle vos publications plus anciennes et ajouter la clé avec une valeur vide, par exemple:

add_action( 'admin_init', 'update_old_posts' );
function update_old_posts() {
    if ( ! isset( $_GET[ 'update_old_posts' ] ) )
         return;

    foreach( get_posts() as $post ) {
        if ( false === get_post_meta( $post->ID, 'publication_date', true ) ) {
             update_post_meta( $post->ID, 'publication_date', '' );
             echo "Updated {$post->post_title} <br />";
        }
    }

    die;
}

Lancez-le en naviguant jusqu'à enlace

.

Ensuite, vous pouvez utiliser la même requête que vous avez. Vous voudrez peut-être ajouter un filtre supplémentaire pour vous permettre de trier par colonnes différentes dans des directions différentes; il me semblerait logique de trier par date dans l'ordre décroissant et par titre dans l'ordre croissant.

add_filter( 'posts_orderby', 'multicolumn_orderby', 10, 2 );
function multicolumn_orderby( $orderby, $query ) {
    global $wpdb;

    // check it's the right query
    if ( $query->get( 'meta_key' ) == 'publication_date' ) {
         $orderby = "$wpdb->postmeta.meta_value+0 DESC, $wpdb->posts.post_title ASC";
    }

    return $orderby;
}
    
réponse donnée sanchothefat 17.12.2013 - 18:25
0

J'ai créé une clause where personnalisée. Je l'ai testé avec $wp_query->request juste avant ma boucle principale. Je ne connais pas très bien SQL, mais cela a semblé faire fonctionner les choses.

add_action('pre_get_posts', 'add_trending_sort', 11, 1);
function add_trending_sort($query){
  if(!$query->is_main_query())
    return;

  //Overwrite query arguments
  $query->set('meta_query', array(
    array(
      'key' => 'TRENDING',
      //'value' => 'asdfasdf',//may need a value for older versions of WordPress
      'compare' => 'NOT EXISTS',
    )
  ));
  $query->set('orderby', 'meta_value_num date');
  $query->set('order', 'DESC');
}

add_filter('posts_where', 'add_trending_where');
function add_trending_where($where = ''){
  global $wpdb, $wp_query;
  if(!$wp_query->is_main_query())//Not sure if this really works.  Should be OK
    return $where;

  $where .= " OR ( $wpdb->postmeta.meta_key = 'TRENDING' )";

  // Don't run this twice
  remove_filter('posts_where', 'add_trending_where');

  return $where;
}

Vous pouvez également définir compare sur 'EXISTS' et modifier la ligne de add_trending_where en $where .= " OR ($wpdb->postmeta.post_id IS NULL)"; . Ensuite, il vous suffira de changer la valeur de la clé en un seul endroit. Encore une fois, echo $wp_query->request et jouez si vous voulez mieux comprendre ceci ou le modifier.

EDIT: Je viens de remarquer que cela ne fonctionne pas si meta_key est défini sur la requête. Vous pouvez utiliser $query->set('meta_key', NULL); si vous devez.

EDIT 2: Je travaille avec la méthode ci-dessus. Pour une raison quelconque, ce n'était pas au début (peut-être que meta_key était défini ... je ne sais pas).

add_action('pre_get_posts', 'add_trending_sort', 11, 1);
function add_trending_sort($query){
  // Bail if not the main "hidden" query, as opposed to a 'new WP_Query()' call
  if(!$query->is_main_query())
    return;

  // Set meta_query to get shares for orderby, and also get non-shared content.
  $query->set('meta_query', array(
    'relation' => 'OR',
    array(
      'key' => 'TRENDING',
      'compare' => 'NOT EXISTS',
    ),
    array(
      'key' => 'TRENDING',
      'compare' => 'EXISTS',
    )
  ));
  //$query->set('meta_key', NULL);
  $query->set('orderby', array('meta_value_num' => 'DESC', 'date' => 'DESC'));
}
    
réponse donnée Ryan Taylor 25.03.2015 - 01:08

Lire d'autres questions sur les étiquettes