Returnează postarea părinte cu copiii săi folosind WP_Query?
În anumite cazuri poate fi util să utilizezi mai mulți parametri pentru posturi și pagini în obiectul tău WP_Query
. În cazul meu, aș dori să afișez copiii unei pagini părinte inclusiv pagina părinte în sine.
Vizualizarea a ceea ce vreau să obțin. Imaginează-ți următoarele pagini sortate ierarhic astfel:
- pagina A
- pagina B
- Pagina copil A
- Pagina copil B
- Pagina copil C
- pagina C
Elementele din listă îngroșate sunt postările/paginile pe care vreau să le preiau.
Primele mele gânduri se îndreaptă spre utilizarea acestor doi parametri pentru WP_Query
:
$args = array(
'post_id' => $parent->ID,
'post_parent' => $parent->ID,
);
Din păcate, aici va folosi doar un parametru. Cu $args
de mai sus (corectați-mă dacă greșesc) va afișa toate postările copil ale postării părinte și nu va include și postarea părinte în sine.
Această problemă ar putea fi rezolvată prin colectarea tuturor postărilor necesare și punerea lor în parametrul post__in
astfel:
$args = array(
'post__in' => $children_and_parent_ids,
);
Totuși există wp_list_pages()
care îți permite să include
o postare/postări și să specifici postarea de la care vrei să incluzi copiii (child_of
). De ce nu este posibil acest lucru cu WP_Query
?
Un exemplu a ceea ce încerc să realizez folosind wp_list_pages()
:
wp_list_pages(array(
'include' => $parent->ID,
'child_of' => $parent->ID,
));
Aruncă o privire la documentația pentru WP_Query
.

Dacă tot ce doriți sunt rezultate din post_type "page", atunci procedați așa cum a sugerat @birgire.
Alternativ, puteți adapta următorul cod pentru a obține un rezultat similar nu doar pentru page
post_type
ci și pentru orice alt tip de postare personalizată.
$parent = 2; //schimbați după necesități
$type = 'page'; //schimbați după necesități
$child_args = array(
'post_type' => $type,
'post_parent' => $parent
);
$ids = array( $parent );
$ids = array_merge( $ids, array_keys( get_children( $child_args ) ));
$query = new WP_Query(
array(
'post_type' => 'page',
'post_status' => 'publish',
'post__in' => $ids,
'posts_per_page' => -1
)
);
Codul de mai sus este în esență același lucru cu conectarea la filtrul posts_where
și parsarea clauzei SQL, însă acest lucru obține exact același rezultat.

Putem filtra clauza posts_where
din SQL-ul generat pentru a returna și postul/pagina părinte, nu doar copiii acestuia. Aici vom seta un argument personalizat numit wpse_include_parent
, care, când este setat la true
, va modifica SQL-ul generat în consecință.
Tot ce trebuie să facem în interiorul filtrului nostru posts_where
este să verificăm dacă argumentul nostru personalizat este setat și dacă argumentul post_parent
este setat. Apoi obținem acea valoare și o transmitem filtrului pentru a extinde interogarea noastră SQL. Ceea ce este frumos aici este că post_parent
acceptă o singură valoare întreagă, așa că trebuie doar să validăm valoarea ca întreg.
INTEROGAREA
$args = [
'wpse_include_parent' => true,
'post_parent' => 256,
'post_type' => 'page'
// Adaugă argumente suplimentare
];
$q = new WP_Query( $args );
După cum puteți vedea, am setat 'wpse_include_parent' => true
pentru a "activa" filtrul nostru.
FILTRUL
add_filter( 'posts_where', function ( $where, \WP_Query $q ) use ( &$wpdb )
{
if ( true !== $q->get( 'wpse_include_parent' ) )
return $where;
/**
* Obține valoarea transmisă pentru post_parent și o validează
* post_parent acceptă doar o valoare întreagă, așa că trebuie doar să validăm
* valoarea ca întreg
*/
$post_parent = filter_var( $q->get( 'post_parent' ), FILTER_VALIDATE_INT );
if ( !$post_parent )
return $where;
/**
* Să includem și părintele în interogarea noastră
*
* Deoarece am validat deja valoarea $post_parent, nu este nevoie
* să folosim metoda prepare() aici
*/
$where .= " OR $wpdb->posts.ID = $post_parent";
return $where;
}, 10, 2 );
Puteți extinde acest lucru după cum aveți nevoie și considerați potrivit, dar aceasta este ideea de bază. Acest lucru va returna părintele transmis la post_parent
și copiii acestuia.

Codul funcționează, dar din păcate returnează de două ori același post părinte. Când rulez un WP_Query
cu atributul personalizat.

uită-te la codul și rezultatul meu. Sper că asta te va ajuta să înțelegi mai bine problema. Încearcă să pui interogarea direct pe pagina părinte sau copil.

Am analizat var_dump()
. Sunt returnate două postări în $q->posts
, cu ID-urile 2126 și 2116, ceea ce pare corect, fără duplicate. Cred că ceea ce vezi este postarea 2116 disponibilă și în $q->post
, ceea ce este de asemenea corect. Aceasta este valoarea globală $post
pentru acea interogare specifică și va fi întotdeauna prima postare din $q->posts
în mod implicit.

Bine, dar întotdeauna returnează două postări părinte, chiar și când vizualizezi postarea copil cu acest cod al părintelui (deci global $post
conține obiectul postării copil). Întrebarea este de ce iterează de 3 ori când există doar 2 postări prin care să itereze?

de ce iterează de 3 ori când există doar 2 postări prin care să itereze Atunci nu are nicio legătură cu interogarea. În obiectul de interogare, există două postări. Dacă există o a treia postare, aceasta este injectată în această interogare prin intermediul unui filtru personalizat. Totul în interogarea ta pare OK, deși interogarea SQL arată ciudat din cauza altor filtre care acționează asupra interogării. Ar trebui să depanezi această problemă, să te asiguri că $post
este ceea ce te aștepți să fie, dacă bucla ta este corectă, dacă celelalte filtre sunt folosite corect în context. Pe o instalare vanilla, totul funcționează conform așteptărilor pe partea mea.

$args = array(
'post_type' => 'tribe_events', // Tipul postării - evenimente
'posts_per_page' => '-1', // Toate postările
'orderby' => 'ID', // Sortează după ID
'order' => 'ASC', // Ordine crescătoare
'post_parent' => $postID, // ID-ul părintelui
);
$children = new WP_Query($args); // Interogare pentru postările copil
$parent[] = get_post($postID); // Obține postarea părinte
$family = array_merge($parent, $children->get_posts()); // Combină părintele cu copiii
Acest cod pare să funcționeze. Comentarii?

Adevărat, dar nu va fi la fel de eficient ca răspunsul acceptat. Abordarea din răspunsul acceptat necesită doar o singură interogare, în timp ce abordarea ta va rezulta în două interogări (dacă nu sunt deja în cache).

Cred că răspunsul tău este mult mai bun!!! mult mai simplu/lizibil!!! Și pentru a economisi ce... o interogare? din sutele din contextul WordPress... iar asta a fost cache-uită de 30 de ori până a ajuns la codul tău...
pe deasupra, interogarea economisită este una WHERE ID=123
.... 0.0001s

Utilizarea global $wpdb
combinată cu [get_results()][1]
este de asemenea o opțiune. Din punct de vedere al performanței, cred că aceasta este cea mai bună soluție, deoarece rulează doar o singură interogare.
Iată codul meu final.
<ul class="tabs"><?php
global $wpdb, $post;
$parent = count(get_post_ancestors($post->ID))-1 > 0 ? $post->post_parent : $post->ID;
$sql = "SELECT ID FROM `{$wpdb->prefix}posts`";
$sql.= " WHERE ID='{$parent}' OR post_parent='{$parent}' AND post_type='page'";
$sql.= " ORDER BY `menu_order` ASC";
$tabs = $wpdb->get_results($sql);
$output = '';
foreach ($tabs as $tab) {
$current = $post->ID == $tab->ID ? ' class="active"' : '';
$output .= '<li'.$current.'>';
$output .= empty($current) ? '<a href="'.get_permalink($tab->ID).'">' : '';
$output .= get_the_post_thumbnail($tab->ID, 'menu-24x24');
$output .= '<span>'.get_the_title($tab->ID).'</span>';
$output .= empty($current) ? '</a>' : '';
$output .= '</li>';
}
print $output;
?></ul>

S-ar putea crede că așa stau lucrurile, însă WP_Query
în spate stochează în cache rezultatele interogărilor, așadar de exemplu, un apel către get_children()
sau get_post_ancestors()
în plus față de WP_Query
nu ar trebui să aducă nicio penalizare suplimentară de performanță.

Dacă te înțeleg corect, vrei să obții ID-urile atât ale paginilor părinte, cât și ale oricăror pagini copil ulterioare. WordPress are funcții care preiau copiii paginilor, cum ar fi aceasta:
https://codex.wordpress.org/Function_Reference/get_page_children
Din câte înțeleg, deoarece efectuezi o interogare WP_Query, deja preiei ID-urile paginilor părinte, deci tot ce trebuie să faci este să transmiți ID-ul relevant funcției menționate mai sus pentru a obține ceea ce dorești.
Notă: Trebuie să menționez că această funcție nu efectuează o interogare în baza de date, deci este mai eficientă din punct de vedere al performanței, deoarece faci o singură interogare în baza de date.

Înțeleg de ce menționezi această funcție, dar acest răspuns este mai degrabă un comentariu decât un răspuns. Oricum, nu găsesc un motiv pentru care această funcție ar putea fi utilă, deoarece WP_Query
deja îți permite să specifici o listă de articole și copiii acestora cu argumentul: post_parent
. Deci, de ce nu este învechită această funcție?

Nu asta încerc să obțin, nu vreau să folosesc wp_list_pages
deoarece rezultatul nu îmi satisface nevoile.

Mulțumesc pentru actualizare, din păcate acest lucru nu include o explicație despre cum să includ postarea părinte.

puteți consulta https://codex.wordpress.org/Function_Reference/get_pages pentru o explicație detaliată
