Come ottenere tutti i figli e nipoti di un custom post type gerarchico?

15 gen 2013, 14:33:57
Visualizzazioni: 18.8K
Voti: 9

Ho bisogno di ottenere tutti i sotto-post di un ID genitore specifico (root).

get_posts( array( 'numberposts' => -1, 'post_status' => 'publish', 'post_type' => 'microsite', 'post_parent' => $root_parent_id, 'suppress_filters' => false ) );

WP-Codex: la funzione get_post() ha il parametro post_parent ma non child_of.

Il vantaggio della funzione get_pages() in combinazione con il parametro child_of è "... Nota che il parametro child_of recupererà anche i 'nipoti' dell'ID dato, non solo i discendenti diretti."*

0
Tutte le risposte alla domanda 5
2
13

Dovrai iterare su quei post e poi eseguire più query per ogni post, ripetendo finché non trovi più post in una query.

Ad esempio:

function get_posts_children($parent_id){
    $children = array();
    // recupera i figli del post
    $posts = get_posts( array( 'numberposts' => -1, 'post_status' => 'publish', 'post_type' => 'microsite', 'post_parent' => $parent_id, 'suppress_filters' => false ));
    // ora recupera i nipoti
    foreach( $posts as $child ){
        // ricorsione!! evviva
        $gchildren = get_posts_children($child->ID);
        // unisci i nipoti nell'array dei figli
        if( !empty($gchildren) ) {
            $children = array_merge($children, $gchildren);
        }
    }
    // unisci i discendenti diretti trovati prima
    $children = array_merge($children,$posts);
    return $children;
}

// esempio di utilizzo, chiamiamola e stampiamo i risultati
$descendants = get_posts_children($post->ID);
echo '<pre>';
print_r($descendants);
echo '</pre>';

Sì, la funzione sopra richiama sé stessa, è una funzione ricorsiva. Continuerà a chiamarsi finché non raggiunge un punto in cui il post esaminato non ha figli, poi tornerà senza chiamarsi e l'intero stack risalirà costruendo l'array dei figli. Faresti bene a fare ulteriori ricerche in questo ambito.

Nota che c'è un costo intrinseco in ciò che vuoi fare, indipendentemente dal fatto che tu usi funzioni ricorsive o meno, legato a quanti livelli di post hai. 5 livelli di post saranno più costosi di 2, e la scalabilità non è lineare. Potresti voler usare i transient per memorizzare nella cache l'output a seconda di come lo implementi.

Un altro modo per ridurre il costo è limitare la profondità dell'albero dei post da esaminare, ad esempio solo fino ai nipoti ma non ai pronipoti. Questo può essere fatto passando un parametro di profondità e decrementandolo ad ogni chiamata ricorsiva, assicurandosi di restituire un array vuoto all'inizio se la profondità è 0 o inferiore. Molti tutorial sulle funzioni ricorsive usano questo come esempio.

15 gen 2013 15:00:37
Commenti

Il problema con questo codice è che non fornisce un ordinamento corretto; ottengo prima tutti gli elementi di primo livello, poi tutti quelli di secondo livello in un unico array appiattito. Qualche idea su come risolvere?

dama_do_bling dama_do_bling
9 apr 2015 00:23:12

Questo codice non è stato progettato per fare quello, hai un problema diverso che richiede una soluzione leggermente differente e una buona dose di contesto

Tom J Nowell Tom J Nowell
9 apr 2015 03:38:38
1

Avevo un requisito simile ma dovevo preservare la gerarchia, quindi la risposta di Tom mi ha dato un buon punto di partenza:

function get_post_offspring($post)
{
    // Funzione per scorrere programmaticamente i discendenti di un post

    // Ottieni i figli diretti del post corrente
    // e aggiungili a un nuovo elemento dell'oggetto chiamato children
    $post->children = get_children(array("post_parent" => $post->ID, "post_type" => "page", "post_status" => "publish"));
    
    // se il post non ha figli, restituisci semplicemente il post
    // con children come array vuoto
    if (empty($post->children)) {
        return $post;
    }
    foreach ($post->children as $child) {
        // Per ogni figlio di questo post...ottieni i figli
        $children = get_children(array("post_parent" => $child->ID, "post_type" => "page", "post_status" => "publish"));
        if (!empty($children)) {
            // se questo post ha figli...allora chiama nuovamente questa funzione
            // per assegnare l'elemento children a questo post e scendere ulteriormente
            // nella discendenza di questo post

            $child = get_post_offspring($child);
        }
    }

    return $post;
}

Ora avevo anche bisogno di attraversare la lista con un mantenendo l'ordine e il livello.

function render_list_items($children)
{
    foreach ($children as $child) {
        $has_children = !empty($child->children);

        echo "<li>";
        echo "<a href='" . get_permalink($child) . "'>" . $child->post_title . "</a";
        if ($has_children) {
            // Se il post ha figli, crea un nuovo <ul> dentro l'attuale
            // <li> e richiama la funzione nuovamente
            echo "<ul>";
            echo render_list_items($child->children);
            echo "</ul>";
        }

        echo "</li>";
    }

}

Quindi, per mettere tutto insieme ho qualcosa come:

global $post;

$post_id = $post->ID;

// Ottieni gli antenati del post corrente dove l'ultimo elemento dell'array
// è il genitore più in alto
$ancestors = get_post_ancestors($post->ID);

$root_id = array_pop($ancestors);
// Ora abbiamo il post radice di questo post e scendiamo per prendere tutta la sua discendenza
$root_post = get_post($root_id);

$root_children = get_post_offspring($root_post);
23 lug 2021 16:05:53
Commenti

echo "<a href='" . get_permalink($child) . "'>" . $child->post_title . "</a";

manca il tag di chiusura > nell'ahref

Ma per il resto risposta brillante, grazie!

Lemon Bacon Lemon Bacon
25 set 2022 19:29:16
1

Basta usare get_page_children(). Funziona per ogni tipo di post (non solo per le pagine) ed è essenzialmente quello che @TomJNowell ha mostrato nell'altra domanda, ma già implementato nel core.

$children = get_page_children( $post->ID, $GLOBALS['wp_query'] );

L'esempio sopra è come nel Codex. Ecco perché puoi semplicemente prendere l'oggetto query globale (o qualsiasi altro oggetto query) da usare come base di ricerca.

23 set 2013 14:14:09
Commenti

Ma come si utilizza questo per un tipo di post diverso? Non riesco a farlo funzionare.

dama_do_bling dama_do_bling
9 apr 2015 00:18:30
0

Utilizza questo shortcode per visualizzare tutti i figli e nipoti in una vista gerarchica. Utilizzo: [my_children_list] oppure [my_children_list page_id=123]

function my_children_list_func($atts, $content = null) {
    global $post;

    $a = shortcode_atts( array(
            'page_id' => ''
    ), $atts );

    $args = array( 
            'numberposts' => -1, 
            'post_status' => 'publish', 
            'post_type' => 'microsite', 
            'post_parent' => (isset($a['page_id']) && $a['page_id']) ? $a['page_id'] : $post->ID,
            'suppress_filters' => false 
    );

    $parent = new WP_Query( $args );

    ob_start();

    if ( $parent->have_posts() ) :?>
            <ul>
            <?php while ( $parent->have_posts() ) : $parent->the_post(); ?>
                    <li><a href="<?php the_permalink(); ?>" title="<?php the_title(); ?>"><?php the_title(); ?></a>
                    <?php echo do_shortcode('[tadam_children_list page_id='.get_the_ID().']') ?>
                    </li>
            <?php endwhile;?>
            </ul>
    <?php endif; wp_reset_postdata();

    return ob_get_clean();
}
add_shortcode( 'my_children_list', 'my_children_list_func' );
31 dic 2018 11:22:10
0

Nel caso qualcuno si imbatta in questo articolo e decida di implementare la risposta scelta, get_pages() funziona con le pagine e i tipi di post gerarchici. Pertanto, puoi semplicemente usare get_pages() con il parametro child_of.

8 giu 2020 14:53:26