Come restituire i risultati di get_posts() in un ordine esplicitamente definito

3 mar 2011, 19:59:57
Visualizzazioni: 10K
Voti: 6

Sto cercando di creare un loop di post con un ordine esplicito, ad esempio:

<?php $args = array(
    'include'         => '1,3,8,4,12' ); ?>

<?php get_posts( $args ); ?>

I risultati sono ordinati per data per impostazione predefinita, e non esiste un'opzione orderby per restituire i post nell'ordine in cui sono stati inseriti. Ci sono state diverse segnalazioni di bug/feature request su Trac riguardo questo problema, ma finora senza successo. Ho provato a modificare i file core ma non sono riuscito a risolverlo.

Qualcuno può suggerire una soluzione alternativa per questo comportamento?

Saluti, Dalton

7
Commenti

@Dalton, un plugin per l'ordinamento dei post è fuori discussione? Potresti poi usare 'orderby' => 'menu_order', 'order' => 'ASC'

eileencodes eileencodes
3 mar 2011 20:12:47

In questo caso non funzionerebbe - sto effettivamente restituendo allegati, ciascuno con genitori diversi, quindi menu_order diventa irrilevante. Grazie mille per la risposta!

Dalton Rooney Dalton Rooney
3 mar 2011 20:20:09

@Dalton, forse ho frainteso il tuo problema, ma nel box di caricamento media, se vai su "galleria" puoi riordinare le immagini assegnando loro numeri e poi di nuovo come suggerito sopra usare 'orderby' => 'menu_order, 'order' => 'ASC'

eileencodes eileencodes
3 mar 2011 20:43:19

Solo una nota a margine: puoi usare più argomenti con orderby separati da spazio: &order_by=date ID per esempio.

kaiser kaiser
3 mar 2011 22:57:22

@eileen.carpenter: Il problema nel mio caso è che ogni allegato potrebbe teoricamente avere un genitore diverso, rendendo menu_order irrilevante. Ognuno degli ID degli allegati nella mia query potrebbe potenzialmente avere lo stesso menu order. Sto passando i post inclusi tramite uno shortcode, quindi ho bisogno di restituire gli allegati nell'ordine dato.

Dalton Rooney Dalton Rooney
4 mar 2011 01:02:39

@kaiser: Non penso che questo risolverà il mio problema qui, ma è davvero fantastico e non lo sapevo!

Dalton Rooney Dalton Rooney
4 mar 2011 01:03:08

Potresti fare qualcosa di simile a quello che ho fatto qui, dovresti solo usare un array di ID invece degli strumenti (e senza tutte le altre cose che non sono applicabili al tuo caso).

t31os t31os
4 mar 2011 01:58:40
Mostra i restanti 2 commenti
Tutte le risposte alla domanda 5
7
11

Penso che questo sia il modo più veloce per restituire i risultati di un get_posts in un ordine definito. E oltre a ciò, è una soluzione nativa, senza hack

<?php

$posts_order = array('1,3,8,4,12');
$args = array(
    'post__in' => $posts_order,
    'orderby' => 'post__in'
); 
get_posts( $args ); 

?> 
4 ago 2013 00:09:24
Commenti

Per favore aggiungi una spiegazione alla tua risposta: perché potrebbe risolvere il problema?

fuxia fuxia
4 ago 2013 00:53:18

È una soluzione nativa, senza hack

Pablo S G Pacheco Pablo S G Pacheco
5 ago 2013 18:01:28

Spiega nella tua risposta qual è la differenza con la risposta accettata che usa anche post__in.

fuxia fuxia
5 ago 2013 19:39:47

Nella risposta accettata, @dougal ha suggerito di creare due funzioni: set_include_order() e menu_order_sort(). Non ce n'è bisogno. Inoltre, ha suggerito di usare WP_Query invece di get_posts, come voleva l'autore della domanda.

E post__in funziona solo se includi anche il parametro 'orderby', come ho suggerito io

Pablo S G Pacheco Pablo S G Pacheco
5 ago 2013 21:26:42

@PabloKarzin: se guardi la data della domanda originale, questo tipo di ordinamento non era possibile in WP_Query fino a WordPress 3.5. Il tuo aggiornamento è corretto, ma non era possibile nel 2011.

Dalton Rooney Dalton Rooney
15 ago 2013 20:36:32

ottima risposta - voto negativo sbagliato - 3.6.1 - semplice e facile - Grazie!

Q Studio Q Studio
17 ott 2013 20:32:54

migliore risposta finora.

RafaSashi RafaSashi
19 ago 2016 15:43:32
Mostra i restanti 2 commenti
0
10

Puoi provare questo:

add_filter('posts_orderby', 'enforce_specific_order');
$posts = get_posts($args);
remove_filter( current_filter(), __FUNCTION__ );

function enforce_specific_order($orderby) {
    global $wpdb;
    return "FIND_IN_SET(".$wpdb->posts.".ID, '1,3,8,4,12') ASC";
}
4 mar 2011 07:23:46
6

Ok, ero determinato a trovare un modo per fare questo e penso di averlo trovato. Speravo di trovare una soluzione più semplice ed evitare di dover usare un nuovo oggetto WP_Query, ma è troppo radicato nel funzionamento del loop. Prima, abbiamo un paio di funzioni di utilità:

// Imposta l'ordine del menu dei post basato sulla nostra lista  
function set_include_order(&$query, $list) {
    // Mappa l'ID del post alla sua posizione nella lista:
    $map = array_flip($list);

    // Imposta menu_order secondo la lista     
    foreach ($query->posts as &$post) {
      if (isset($map[$post->ID])) {
        $post->menu_order = $map[$post->ID];
      }
    }  
}

// Ordina i post per $post->menu_order.                                 
function menu_order_sort($a, $b) {
  if ($a->menu_order == $b->menu_order) {
    return 0;
  }
  return ($a->menu_order < $b->menu_order) ? -1 : 1;
}

Queste ci permetteranno di impostare la proprietà menu_order basandoci sulla nostra lista, e poi ordinare i post in un oggetto query basandoci su quella.

Ecco come eseguiamo la query e ordiniamo i post:

$plist = array(21, 43, 8, 44, 12);
$args = array(
  'post_type' => 'attachment',
  'post_status' => 'any',
  'post__in' => $plist 
);

// Crea una nuova query  
$myquery = new WP_Query($args);

// imposta il menu_order
set_include_order($myquery, $plist);

// e ordina effettivamente i post nella nostra query
usort($myquery->posts, 'menu_order_sort');

Quindi ora abbiamo il nostro oggetto query, e $myquery->posts è ordinato secondo la nostra funzione personalizzata menu_order_sort. L'unica parte complicata ora è che dobbiamo costruire il nostro loop usando il nostro oggetto query personalizzato:

while($myquery->have_posts()) : $myquery->the_post();
  ?>
    <div><a id="post_id_<?php the_ID(); ?>" class="nb" href="<?php the_permalink(); ?>"><?php the_title(); ?></a> Post ID: <?php the_ID(); ?>
    </div>
  <?php

endwhile;
wp_reset_postdata();

Ovviamente, dovresti sistemare il codice del template del loop lì.

Speravo di trovare una soluzione che non richiedesse l'uso di un oggetto query personalizzato, magari usando query_posts() e sostituendo la proprietà posts sulla globale $wp_query, ma non sono riuscito a farlo funzionare correttamente. Con un po' più di tempo per lavorarci, avrei potuto farcela.

Ad ogni modo, vedi se questo ti può aiutare a raggiungere il tuo obiettivo?

4 mar 2011 19:09:41
Commenti

Bouy... sembra un po' eccessivo e non funziona con l'impaginazione (dal momento che ordini dopo la query), ma +1 per il grande sforzo nel risolverlo senza iniettare qualcosa a livello SQL.

wyrfel wyrfel
4 mar 2011 20:28:30

Fantastico! Funziona sicuramente per i post e risponde alla domanda originale. C'è solo un intoppo, ovvero che ho bisogno di restituire allegati, non post. Non mi ero reso conto che WP-Query() non funziona con gli allegati, ho sempre usato get_posts()... c'è un modo semplice per farlo funzionare con get_posts()? Continuerò a lavorarci e vedrò cosa riesco a ottenere.

Dalton Rooney Dalton Rooney
4 mar 2011 20:42:24

Ho aggiornato il codice per recuperare gli allegati. :) Con gli allegati, devi specificare post_status come 'any', perché normalmente usano lo stato inherit invece di publish, per riflettere lo stato del genitore.

Dougal Campbell Dougal Campbell
4 mar 2011 21:24:59

Oh, e per le persone future che leggeranno questo, si prega di notare il commento di @wyrfel: questo non funzionerà bene se avete bisogno di impaginare i risultati, poiché l'ordinamento non avviene all'interno di MySQL.

Dougal Campbell Dougal Campbell
4 mar 2011 21:41:47

@Dougal: Mille grazie, le tue modifiche hanno funzionato alla perfezione. Fortunatamente non devo impaginare questi risultati, quindi sono a posto al 100%.

Dalton Rooney Dalton Rooney
4 mar 2011 22:33:11

Un'ultima nota -- se avete un numero elevato di ID da recuperare, potreste anche voler aggiungere 'posts_per_page' => -1 all'array $args, per evitare di scontrarvi con i limiti di impaginazione. In realtà, potreste volerlo fare comunque, nel caso in cui il sito in questione abbia impostato un valore predefinito di posts_per_page molto basso.

Dougal Campbell Dougal Campbell
5 mar 2011 00:30:31
Mostra i restanti 1 commenti
0

A partire da WordPress 3.5, questa funzionalità è ora integrata nel core. Puoi ordinare esplicitamente i post utilizzando il parametro "post__in". http://core.trac.wordpress.org/ticket/13729

14 dic 2012 14:18:03
3

E se invece cancellassimo semplicemente il orderby con un filtro? Appena prima di eseguire la query sui tuoi post, inserisci:

add_filter('posts_orderby', '__return_false');

Poi, una volta completato il tuo loop:

remove_filter('posts_orderby', '__return_false');

Il motivo per rimuovere nuovamente il filtro è nel caso in cui tu abbia altri loop nella pagina (come quelli dei widget) che necessitino del loro ordinamento esplicito normale.

3 mar 2011 22:48:29
Commenti

Dougal: In realtà esiste un'opzione orderby=none, ma questa restituisce l'ordine naturale dei post nel database, essenzialmente ordinandoli per ID. Quello che sto cercando è un modo per ottenere i miei post nell'ordine specificato nella query. Non è supportato da WP_Query, quindi suppongo che sto cercando una soluzione alternativa o un hack.

Dalton Rooney Dalton Rooney
4 mar 2011 01:09:23

Beh, accidenti. Pensavo che una query 'include' avrebbe restituito i risultati nell'ordine dato se si eliminava il orderby. Ma ora che ci penso, ha senso che MySQL restituisca i risultati in ordine naturale (sta cercando di essere efficiente).

Dougal Campbell Dougal Campbell
4 mar 2011 16:18:40

Stavo per eliminare questa mia risposta, ma ho pensato che potesse essere utile mantenerla per documentare il comportamento dell'ordine naturale del database quando si elimina l'orderby.

Dougal Campbell Dougal Campbell
4 mar 2011 21:45:13