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?

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

Î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

@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.

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

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.

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.

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.

Ș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: Mulțumesc mult, modificările tale au rezolvat problema. Din fericire, nu am nevoie să paginez aceste rezultate, așa că sunt 100% setat.

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.

Î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.

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).
