Tipuri personalizate de postări, WP_Query și 'orderby'
Am un tip personalizat de postare cu următoarea configurație:
$supports = array(
'title'
, 'editor'
, 'thumbnail'
, 'revisions'
, 'page-attributes'
);
$args = array(
'hierarchical' => true
, 'supports' => $supports
[...]
);
register_post_type('myType', $args);
Doresc să afișez toate postările sortate exact ca în zona de admin (indentarea este pentru lizibilitate):
1,
2,
3,
1, (părinte 3)
2, (părinte 3)
4
Am încercat următoarea interogare cu orderby setat la 'menu_order':
$loop = new WP_Query( array(
'post_type' => 'myType'
, 'posts_per_page' => 50
, 'orderby' => 'menu_order'
, 'order' => 'ASC'
));
Din păcate, toate postările sunt sortate doar după menu_order
, ignorând relația de părinte (post_parent
). Rezultatul este:
1,
1, (părinte 3)
2,
2, (părinte 3)
3,
4
Modificând interogarea la 'orderby' => 'parent menu_order'
se obține:
1,
2,
3,
4
1, (părinte 3)
2, (părinte 3)
Se pare că totul funcționează conform design-ului, iar valoarea orderby este tradusă direct în clauza SQL 'Order By'.
Întrebare
Care este cea mai simplă metodă de a obține ordinea dorită?
SQL
Presupun că aceasta este interogarea SQL principală generată de WordPress:
SELECT SQL_CALC_FOUND_ROWS wp_2_posts.ID
FROM wp_2_posts
WHERE 1=1 AND wp_2_posts.post_type = 'inhalt' AND (wp_2_posts.post_status = 'publish' OR wp_2_posts.post_status = 'private')
ORDER BY wp_2_posts.post_parent, wp_2_posts.menu_order ASC LIMIT 0, 50
Urmată de:
SELECT wp_2_posts.*
FROM wp_2_posts
WHERE ID IN (40,42,44,46,48,50,52,54,56,58,60,76,62,65,69,71,74)
SELECT post_id, meta_key, meta_value
FROM wp_2_postmeta
WHERE post_id IN (40,42,44,46,48,50,52,54,56,58,60,62,65,74,69,71,76)
Soluție alternativă
O soluție alternativă, dar nu o răspuns, este să atribuiți postărilor valori mai mari și mai "spațiate" pentru ordine:
100,
200,
300,
310,
320,
400

Consultați codex pentru alte opțiuni, dar se pare că în acest caz ați dori să utilizați 'parent' ca sortare principală.
$loop = new WP_Query( array(
'post_type' => 'myType'
, 'posts_per_page' => 50
, 'orderby' => 'parent menu_order'
, 'order' => 'ASC'
));
Aceasta va sorta în primul rând după părinte, cu o sortare secundară după ordinea din meniu. Acest lucru ar trebui să vă ofere rezultatul dorit.

Mulțumesc Eric, dar din păcate asta duce la 1, 2, 3, 4, 1(părinte 3), 2 (părinte 3).

Hmm, bizar. Încearcă să le schimbi? Sau să folosești doar părintele? Nu am testat asta, mă bazez doar pe codex.

+1 În sfârșit cineva care a înțeles că un spațiu permite argumente multiple.

@SunnyRed Poți să postezi exact șirul de interogare care iese din asta? (Indiciu: Debug Bar Plugin + Extensions).

Mulțumesc, Kaiser. Sugestia ta cu Debug Bar a făcut deja ca întrebarea mea să merite pusă. Am adăugat sql - sper că e corect, pentru că la prima vedere e destul de mult.

După cum arată instrucțiunea SQL, ordinea ar trebui inversată la:
'orderby' => 'parent menu_order'
, deoarece instrucțiunea sql le inversează deja.

Salut, Erik. Scuze, asta s-a întâmplat pentru că am încercat diferite abordări. WP și ordinea SQL sunt sincronizate.

Din câte văd, nu există o soluție la nivel de bază de date pentru această problemă. Aceasta este o situație întâlnită destul de des, atunci când este nevoie să transformi o listă cu referințe de structură într-un array ordonat, unde elementele copil apar imediat după părinții lor. Acest lucru poate fi realizat în PHP, dar deși soluția este destul de compactă, nu este foarte simplă de înțeles.
Următoarea soluție adaugă un filtru la filtrul the_posts
, care structurează și apoi aplatizează setul de rezultate cu o funcție recursivă.
// Adaugă postările copil ale fiecărui nivel în lista de rezultate, în ordine
function recursively_flatten_list( $list, &$result ) {
foreach( $list as $node ) {
$result[] = $node['post'];
if( isset( $node['children'] ) )
recursively_flatten_list( $node['children'], $result );
}
}
function my_sort_posts( $posts, $query ) {
// Nu face nimic în afara administrării. Acționează doar pe interogarea principală. Doar pentru postări de tip 'page'.
if( is_admin() || !$query->is_main_query() || $query->get( 'post_type' ) != 'page' )
return;
$refs = $list = array();
// Creează structura ierarhică într-un singur pas.
// Mulțumiri lui Nate Weiner:
// http://blog.ideashower.com/post/15147134343/create-a-parent-child-array-structure-in-one-pass
foreach( $posts as $post ) {
$thisref = &$refs[$post->ID];
$thisref['post'] = $post;
if( $post->post_parent == 0)
$list[$post->ID] = &$thisref;
else
$refs[$post->post_parent]['children'][$post->ID] = &$thisref;
}
// Creează o listă simplă și sortată
$result = array();
recursively_flatten_list( $list, $result );
return $result;
}
add_filter( 'the_posts', 'my_sort_posts', 10, 2 );
Am testat această soluție și este suficient de generală pentru ierarhii arbitrare de pagini.
Acest cod presupune că postările sunt deja ordonate după menu_order
. Dacă folosești această soluție, asigură-te că modifici parametrul orderby
la doar "menu_order"
acolo unde faci apelul la new WP_Query
.
