Cómo obtener todos los hijos y nietos de un tipo de contenido personalizado jerárquico

15 ene 2013, 14:33:57
Vistas: 18.8K
Votos: 9

Necesito obtener todos los sub-posts de un ID de padre (raíz) específico.

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

WP-Codex: la función get_post() tiene el parámetro post_parent pero no child_of.

La ventaja de la función get_pages() en combinación con el parámetro child_of es "... Ten en cuenta que el parámetro child_of también obtendrá los 'nietos' del ID dado, no solo los descendientes directos."*

0
Todas las respuestas a la pregunta 5
2
13

Necesitarás recorrer esas publicaciones y luego hacer más consultas para cada publicación, repitiendo hasta que no encuentres publicaciones en una consulta.

Por ejemplo:

function get_posts_children($parent_id){
    $children = array();
    // obtener los hijos de las publicaciones
    $posts = get_posts( array( 'numberposts' => -1, 'post_status' => 'publish', 'post_type' => 'microsite', 'post_parent' => $parent_id, 'suppress_filters' => false ));
    // ahora obtener los nietos
    foreach( $posts as $child ){
        // recursión!! hurra
        $gchildren = get_posts_children($child->ID);
        // fusionar los nietos en el array de hijos
        if( !empty($gchildren) ) {
            $children = array_merge($children, $gchildren);
        }
    }
    // fusionar los descendientes directos que encontramos antes
    $children = array_merge($children,$posts);
    return $children;
}

// ejemplo de uso de lo anterior, llamémoslo e imprimamos los resultados
$descendants = get_posts_children($post->ID);
echo '<pre>';
print_r($descendants);
echo '</pre>';

Sí, la función anterior se llama a sí misma, es una función recursiva. Seguirá llamándose a sí misma hasta que llegue a un punto donde la publicación que se está mirando no tenga hijos, luego retornará sin llamarse a sí misma, y toda la pila volverá hacia arriba construyendo el array de hijos. Sería bueno que investigaras más en esta área.

Ten en cuenta que hay un costo inherente en lo que quieres hacer, independientemente de si usas funciones recursivas o no, que está ligado a cuántos niveles de publicaciones tengas. 5 niveles de publicaciones serán más costosos que 2, y no es una escala lineal. Es posible que desees usar transients para almacenar en caché tu salida dependiendo de cómo lo hagas.

Otra forma de reducir el costo es mirando solo un cierto número de niveles hacia abajo en el árbol de publicaciones, por ejemplo, nietos pero no bisnietos. Esto se puede hacer pasando un parámetro de profundidad y decrementándolo en cada llamada recursiva, asegurándose de retornar un array vacío al inicio si la profundidad es 0 o menor. Muchos tutoriales sobre funciones recursivas usan esto como ejemplo.

15 ene 2013 15:00:37
Comentarios

El problema con este código es que no proporciona un orden correcto; obtengo todos los elementos del primer nivel primero, luego todos los del segundo nivel en un solo array aplanado. ¿Alguna pista sobre cómo solucionarlo?

dama_do_bling dama_do_bling
9 abr 2015 00:23:12

Este código no estaba diseñado para hacer eso, tienes un problema diferente que requiere una solución ligeramente distinta y una buena dosis de contexto

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

Tuve un requisito similar pero necesitaba preservar la jerarquía, así que la respuesta de Tom me dio un buen punto de partida:

function get_post_offspring($post)
{
    // Función para recorrer programáticamente los descendientes de un post

    // Obtener hijos directos del post actual
    // y agregarlos a un nuevo elemento del objeto llamado children
    $post->children = get_children(array("post_parent" => $post->ID, "post_type" => "page", "post_status" => "publish"));
    
    // si el post no tiene hijos, simplemente retornar el post con
    // children como un array vacío
    if (empty($post->children)) {
        return $post;
    }
    foreach ($post->children as $child) {
        // Por cada hijo de este post... obtener sus hijos
        $children = get_children(array("post_parent" => $child->ID, "post_type" => "page", "post_status" => "publish"));
        if (!empty($children)) {
            // si este post tiene hijos... entonces llamar esta función nuevamente
            // para asignar el elemento children a este post y seguir bajando
            // en la descendencia de este post

            $child = get_post_offspring($child);
        }
    }

    return $post;
}

También necesitaba recorrer la lista con un manteniendo el orden y nivel.

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) {
            // Si el post tiene hijos, crear un nuevo <ul> dentro del
            // <li> actual y llamar la función nuevamente
            echo "<ul>";
            echo render_list_items($child->children);
            echo "</ul>";
        }

        echo "</li>";
    }

}

Entonces, para unirlo todo, tengo algo como:

global $post;

$post_id = $post->ID;

// Obtener ancestros del post actual donde el último elemento del array
// es el padre superior
$ancestors = get_post_ancestors($post->ID);

$root_id = array_pop($ancestors);
// Ahora tenemos el post raíz de este post y descendemos para obtener toda su descendencia
$root_post = get_post($root_id);

$root_children = get_post_offspring($root_post);
23 jul 2021 16:05:53
Comentarios

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

falta el cierre > en el ahref

Pero por lo demás es una respuesta brillante, ¡gracias!

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

Simplemente usa get_page_children(). Funciona para cualquier tipo de publicación (no solo páginas) y es básicamente lo que @TomJNowell mostró en la otra pregunta, pero ya implementado por el núcleo de WordPress.

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

El ejemplo anterior es como aparece en el Codex. Por eso puedes simplemente tomar el objeto de consulta global (o cualquier otro objeto de consulta) para usarlo como base de búsqueda.

23 sept 2013 14:14:09
Comentarios

¿Pero cómo se usa esto para un tipo de publicación diferente? No logro que funcione.

dama_do_bling dama_do_bling
9 abr 2015 00:18:30
0

Utiliza el siguiente shortcode para mostrar todos los hijos y nietos en una vista jerárquica. Uso: [my_children_list] o [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

Por si alguien se encuentra con esto y decide implementar la respuesta elegida, get_pages() funciona con páginas y tipos de post jerárquicos. Por lo tanto, puedes usar get_pages() con el parámetro child_of.

8 jun 2020 14:53:26