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

22

Je travaille sur un modèle de page de terme de taxonomie personnalisé où nous voulons que les éléments qui sont connectés au terme soient triés par date de publication (champ de date personnalisé) - et s'il y a plusieurs éléments le même jour (formaté comme AAAA-MM- DD) pour ensuite les trier par titre, et enfin trier par titre si le champ personnalisé n'a pas été rempli (anciens éléments).

Donc, je l'ai essayé de cent façons différentes avec un WP_query et il retourne la plupart des résultats comme je le veux - mais dans ce cas, il ne renvoie que les éléments qui ont la méta-clé de publication_date. Tous les autres éléments sont ignorés et ne s'affichent pas. J'ai essayé une méta-requête en utilisant une relation "ou" et j'ai comparé la date de publication comme EXISTE et NON EXISTE, mais cela a renvoyé 0 résultat pour moi.

En outre, le site exécute toujours la version 3.5.2 et ils ne souhaitent pas effectuer de mise à niveau.

Voici ma requête la plus récente qui m'obtient les articles dont le champ personnalisé publication_date s'affiche 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 d'exécuter une requête SQL, mais je ne sais vraiment pas comment accomplir ce que je veux faire. Si quelqu'un pouvait m'aider, ce serait génial!

Merci d'avance.

CSSgirl
la source
Surpris, l'approche meta_query n'a pas fonctionné, mais là encore, vous ne pouvez pas commander par méta-valeur avec un meta_query sans avoir l'ensemble meta_key.
sanchothefat
Je pense que c'est le problème que j'ai. J'ai finalement réussi à faire fonctionner une méta-requête: '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' ) ),mais la commande ne fonctionne pas: \
CSSgirl
oui, la commande repose malheureusement sur la définition de meta_key en dehors de tax_query. Ma réponse ci-dessous pourrait cependant aider.
sanchothefat

Réponses:

19

Merci à tous pour votre aide!

En fin de compte, la requête ci-dessous m'a donné les résultats que je souhaitais - qui était d'afficher et de trier les messages par un champ personnalisé de "publication_date" en premier - trier par la date et s'il y avait plusieurs de la même date (disons, 4 marqués Juin 2013), il les classerait par titre. Ensuite, après avoir parcouru tous les messages dont la date de publication est remplie, il parcourra à nouveau les messages restants, alphabétiquement par titre.

Cela m'obtient 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',
));
CSSgirl
la source
1
Agréable. Je n'ai jamais pensé à en exécuter deux meta_querysur la même touche!
GhostToast
5
Pour moi (en utilisant WordPress 4.1.1), si je le configure meta_keyautomatiquement, il ne l'inclut même pas avec NOT EXISTS. J'espère vraiment que je fais quelque chose de mal.
Ryan Taylor
1
@RyanTaylor idem ici - meta_key ne doit pas être défini dans la requête pour que cela fonctionne, mais il semble s'ordonner correctement par méta-valeur même lorsque la méta-clé n'est pas définie.
jammypeach
2
Comme ci-dessus, pour WP 4.1+, supprimez ou commentez 'meta_key' => 'publication_date',.
MikeiLL
7

Quelques années plus tard, le code publié par CSSGirl ne fonctionnait pas pour moi car il y avait des messages qui n'avaient pas la méta-clé ou la méta-clé était vide, c'est donc ce que je devais faire pour que tous les messages soient classés par date et montrez d'abord celles avec une méta-clé:

$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' ),
);
Ciprian Tepes
la source
1

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

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

Exécutez ensuite votre deuxième boucle.

GhostToast
la source
J'essaye maintenant, merci. Vous fera savoir si cela fonctionne!
CSSgirl du
1
cela a fonctionné - mais cela a brisé la pagination - une idée de comment faire fonctionner cela? Voici à quoi cela ressemble maintenant:echo paginate_links( array( 'base' => str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) ), 'format' => '?page=%#%', 'current' => max( 1, get_query_var('paged') ), 'total' => $publication_query->max_num_pages, 'prev_text' => __('Previous |'), 'next_text' => __('| Next'), ) );
CSSgirl
Hmm. Pas que je puisse penser.
GhostToast
1

Y a-t-il une raison pour laquelle vous ne pouviez pas appliquer la méta-clé publication_date pour chaque publication avec une valeur vide?

Donc, dans votre save_postaction, vous ajouteriez / mettriez à jour la méta-clé, que la $_POSTvaleur soit vide ou non.

Vous devrez exécuter un script de mise à jour pour parcourir vos anciens messages 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;
}

Exécutez-le en accédant à http://example.com/wp-admin/?update_old_posts

Ensuite, vous pouvez utiliser la même requête que vous. Vous voudrez peut-être ajouter un filtre supplémentaire pour vous permettre de trier par différentes colonnes dans différentes directions, cela me semblerait logique de trier par date en ordre décroissant et par titre en 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;
}
sanchothefat
la source
Hmm, je n'y ai pas pensé. Je vais essayer et voir comment ça se passe, merci!
CSSgirl
0

J'ai créé une clause where personnalisée. Je l'ai testé en utilisant $wp_query->requestjuste avant ma boucle principale, je ne connais pas vraiment bien SQL, mais cela semblait 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;
}

Sinon, vous pouvez définir compareà 'EXISTS'changer la ligne add_trending_where à $where .= " OR ($wpdb->postmeta.post_id IS NULL)";. Il vous suffirait alors de modifier la valeur de la clé en un seul endroit. Encore une fois, $wp_query->requestfaites écho et jouez si vous voulez mieux comprendre ou modifier.

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

EDIT 2: J'ai obtenu ce travail avec la méthode ci-dessus. Pour une raison quelconque, ce n'était pas au début (peut-être que meta_key a été 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'));
}
Ryan Taylor
la source