Cum să returnezi rezultatele funcției get_posts() într-o ordine explicit definită

3 mar. 2011, 19:59:57
Vizualizări: 10K
Voturi: 6

Încerc să creez o buclă de postări ordonate explicit, de exemplu:

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

<?php get_posts( $args ); ?> 

Rezultatele sunt ordonate după dată în mod implicit și nu există nicio opțiune orderby pentru a returna postările în ordinea în care au fost introduse. Au existat mai multe cereri de corectare/îmbunătățire despre acest lucru în Trac, dar până acum fără succes. Am încercat să modific fișierele de bază, dar nu am obținut niciun rezultat.

Poate cineva să sugereze o soluție alternativă pentru acest comportament?

Salutări, Dalton

7
Comentarii

@Dalton, este exclus un plugin pentru ordonarea postărilor? Ai putea folosi atunci 'orderby' => 'menu_order', 'order' => 'ASC'

eileencodes eileencodes
3 mar. 2011 20:12:47

În acest caz nu ar funcționa - de fapt returnez atașamente, fiecare cu părinți diferiți, așa că menu_order devine irelevant. Mulțumesc mult pentru răspuns!

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

@Dalton, poate că nu înțeleg corect problema ta, dar în caseta de încărcare media, dacă mergi la "galerie" poți reordona imaginile atribuindu-le numere și apoi din nou cum s-a sugerat mai sus folosește 'orderby' => 'menu_order, 'order' => 'ASC'

eileencodes eileencodes
3 mar. 2011 20:43:19

Doar o observație: Puteți folosi mai multe argumente cu orderby separate prin spațiu: &order_by=date ID de exemplu.

kaiser kaiser
3 mar. 2011 22:57:22

@eileen.carpenter: Problema în cazul meu este că fiecare atașament ar putea teoretic avea un părinte diferit, făcând menu_order irelevant. Fiecare dintre ID-urile atașamentelor din interogarea mea ar putea avea același menu_order. Trece atașamentele prin shortcode, așa că trebuie să returnez atașamentele în ordinea dată.

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

@kaiser: Nu cred că asta va rezolva problema mea aici, dar este foarte interesant și nu știam despre asta!

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

Ai putea face ceva similar cu ceea ce am făcut aici, doar că ai folosi un array de ID-uri în loc de instrumente (și fără toate celelalte lucruri care nu se aplică în cazul tău).

t31os t31os
4 mar. 2011 01:58:40
Arată celelalte 2 comentarii
Toate răspunsurile la întrebare 5
7
11

Cred că aceasta este cea mai rapidă metodă de a returna rezultatele unui get_posts într-o ordine definită. Și pe lângă asta, este o soluție nativă, fără hack-uri

<?php

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

?> 
4 aug. 2013 00:09:24
Comentarii

Te rog să adaugi o explicație la răspunsul tău: de ce ar putea aceasta rezolva problema?

fuxia fuxia
4 aug. 2013 00:53:18

Este o soluție nativă, fără hack-uri

Pablo S G Pacheco Pablo S G Pacheco
5 aug. 2013 18:01:28

Explică în răspunsul tău care este diferența față de răspunsul acceptat care folosește și el post__in.

fuxia fuxia
5 aug. 2013 19:39:47

În răspunsul acceptat, @dougal a sugerat să se creeze două funcții: set_include_order() și menu_order_sort(). Nu este nevoie de asta. În plus, el a sugerat să se folosească WP_Query în loc de get_posts, așa cum dorea autorul întrebării.

Și post__in funcționează doar dacă incluzi și parametrul 'orderby', așa cum am sugerat eu

Pablo S G Pacheco Pablo S G Pacheco
5 aug. 2013 21:26:42

@PabloKarzin: dacă te uiți la data întrebării originale, acest tip de sortare nu era posibil în WP_Query până la WordPress 3.5. Actualizarea ta este corectă, dar nu era posibilă în 2011.

Dalton Rooney Dalton Rooney
15 aug. 2013 20:36:32

răspuns excelent - vot în jos greșit - 3.6.1 - simplu și ușor - Mulțumesc!

Q Studio Q Studio
17 oct. 2013 20:32:54

cel mai bun răspuns până acum.

RafaSashi RafaSashi
19 aug. 2016 15:43:32
Arată celelalte 2 comentarii
0
10

Poți încerca asta:

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

Bine, am fost hotărât să găsesc o metodă de a face asta și cred că am reușit. Speram să găsesc o soluție mai simplă și să evit să folosesc un nou obiect WP_Query, dar este prea profund înrădăcinat în modul în care funcționează bucla. Mai întâi, avem câteva funcții utilitare:

// Setează ordinea meniului postărilor pe baza listei noastre  
function set_include_order(&$query, $list) {
    // Mapează ID-ul postării la poziția sa în listă:
    $map = array_flip($list);

    // Setează menu_order conform listei     
    foreach ($query->posts as &$post) {
      if (isset($map[$post->ID])) {
        $post->menu_order = $map[$post->ID];
      }
    }  
}

// Sortează postările după $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;
}

Acestea ne vor permite să setăm proprietatea menu_order pe baza listei noastre și apoi să sortăm postările într-un obiect de interogare bazat pe aceasta.

Iată cum interogăm și sortăm postările:

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

// Crează o nouă interogare  
$myquery = new WP_Query($args);

// setează menu_order
set_include_order($myquery, $plist);

// și sortează efectiv postările din interogarea noastră
usort($myquery->posts, 'menu_order_sort');

Acum avem propriul obiect de interogare, iar $myquery->posts este sortat conform funcției noastre personalizate menu_order_sort. Singura parte complicată acum este că trebuie să construim bucla folosind obiectul nostru de interogare:

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> ID Postare: <?php the_ID(); ?>
    </div>
  <?php

endwhile;
wp_reset_postdata();

Evident, ați ajusta codul șablonului buclei acolo.

Speram să găsesc o soluție care să nu necesite utilizarea unui obiect de interogare personalizat, poate prin folosirea query_posts() și înlocuirea proprietății posts pe globalul $wp_query, dar pur și simplu nu am reușit să o fac să funcționeze corect. Cu puțin mai mult timp de lucru, s-ar fi putut realiza.

Oricum, vedeți dacă asta vă ajută să ajungeți unde aveți nevoie?

4 mar. 2011 19:09:41
Comentarii

Bouy...pare un pic exagerat și nu funcționează cu paginarea (deoarece sortezi după interogare), dar +1 pentru un efort minunat de a o rezolva fără a injecta ceva la nivel de SQL.

wyrfel wyrfel
4 mar. 2011 20:28:30

Uimitor! Cu siguranță funcționează pentru postări și răspunde la întrebarea inițială. Există doar o mică problemă, și anume că trebuie să returnez atașamente, nu postări. Nu mi-am dat seama că WP-Query() nu funcționează cu atașamente, am folosit get_posts() ... există vreo modalitate ușoară de a face asta să funcționeze cu get_posts()? Voi continua să lucrez la asta și voi vedea ce pot realiza.

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

Am actualizat codul pentru a prelua atașamentele. :) Cu atașamentele, trebuie să specifici post_status ca 'any', deoarece ele folosesc în mod normal statusul inherit în loc de publish, pentru a reflecta starea părintelui lor.

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

Și pentru cei care vor citi asta în viitor, rețineți comentariul lui @wyrfel: această metodă nu va funcționa bine dacă aveți nevoie să paginați rezultatele, deoarece sortarea nu se întâmplă în MySQL.

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

@Dougal: Mulțumesc mult, modificările tale au rezolvat problema. Din fericire, nu am nevoie să paginez aceste rezultate, așa că sunt 100% setat.

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

O ultimă observație -- dacă aveți un număr mai mare de ID-uri de preluat, ați putea dori să adăugați 'posts_per_page' => -1 în array-ul $args, pentru a evita să vă loviți de limitele de paginare. De fapt, ați putea dori să faceți asta oricum, în cazul în care site-ul în cauză are setat un număr foarte mic de postări pe pagină implicit.

Dougal Campbell Dougal Campbell
5 mar. 2011 00:30:31
Arată celelalte 1 comentarii
0

Începând cu WordPress 3.5, această funcționalitate este acum inclusă în nucleu. Puteți ordona explicit articolele folosind parametrul "post__in". http://core.trac.wordpress.org/ticket/13729

14 dec. 2012 14:18:03
3

Cum ar fi să ștergem pur și simplu orderby cu un filtru? Chiar înainte de a interoga postările, adăugați:

add_filter('posts_orderby', '__return_false');

Apoi, după ce bucla dvs. este finalizată:

remove_filter('posts_orderby', '__return_false');

Motivul pentru eliminarea filtrului din nou este în cazul în care aveți alte bucle pe pagină (cum ar fi cele din widget-uri) care vor avea nevoie de ordonarea lor normală explicită.

3 mar. 2011 22:48:29
Comentarii

Dougal: Există de fapt o opțiune orderby=none, dar aceasta returnează ordinea naturală a postărilor în baza de date, practic ordonând după ID. Ceea ce caut eu este o metodă de a returna postările în ordinea specificată în interogare. Nu este suportat de WP_Query, așa că presupun că caut o soluție alternativă sau un hack.

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

Ei bine, nașpa. Am crezut că o interogare 'include' ar returna rezultatele în ordinea dată dacă elimini orderby. Dar acum că mă gândesc, are sens că MySQL ar returna rezultatele în ordine naturală (încearcă să fie eficient).

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

Eram pe punctul de a șterge acest răspuns al meu, dar am considerat că ar putea fi util să-l păstrez pentru a documenta comportamentul de ordine naturală a bazei de date când elimini orderby.

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