Cum să returnezi rezultatele funcției get_posts() într-o ordine explicit definită
Î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
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 );
?>
Te rog să adaugi o explicație la răspunsul tău: de ce ar putea aceasta rezolva problema?
fuxia
Explică în răspunsul tău care este diferența față de răspunsul acceptat care folosește și el post__in.
fuxia
Î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
@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
răspuns excelent - vot în jos greșit - 3.6.1 - simplu și ușor - Mulțumesc!
Q Studio
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";
}
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?
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
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
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
Ș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: 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
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
Î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
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ă.
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
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