Cómo crear un blogroll organizado por categorías y subcategorías con todos los posts

15 may 2013, 02:41:37
Vistas: 13.6K
Votos: 0

Me gustaría ayuda para mostrar todos los posts de mi sitio web en un blogroll organizado por categorías y subcategorías.

El resultado HTML que me gustaría ver sería algo como esto:

<div id="content">

    <div id="category1">

        <ul id="posts">
            <li>post1</li>
            <li>post2</li>
            <li>post3</li>
        </ul><!-- #posts -->

    </div><!-- #category1 -->

    <div id="category2">

        <div id="sub-category1">

            <ul id="posts">
                <li>post4</li>
                <li>post5</li>
                <li>post6</li>
            </ul><!-- #posts -->

        </div><!-- #sub-category1 -->

        <div id="sub-category2">

            <ul id="posts">
                <li>post7</li>
                <li>post8</li>
                <li>post9</li>
            </ul><!-- #posts -->

        </div><!-- #sub-category2 -->

    </div><!-- #category2 -->

</div><!-- #content -->

La estructura de archivos que imaginé para esto sería algo como:

custom-category.php //este archivo obtendría las categorías, las ordenaría y crearía los divs contenedores para #category y #sub-category y llamaría a la información de los posts desde su loop/query con get_template_part( 'content', get_post_format() );

content.php //este archivo ordenaría el ul#posts y todo tipo de información que quiera añadir respecto al post en sí

Ahora los principales problemas que tengo ahora mismo son no saber realmente por dónde empezar a buscar para intentar resolver esto por mí mismo. Sigo mirando el archivo por defecto category.php y siento que no se parecerá en nada.

He intentado buscar plugins pero algunos solo ordenan las categorías en las barras laterales, otros permiten crear campos personalizados para categorías pero las reseñas mencionan que no puedes llamar a esos valores. He probado la función wp_list_categories(); para intentar empezar por algún lado, pero ni siquiera lista las subcategorías.

He leído sobre crear tus propios query_posts(); o get_posts(); pero realmente no sé por dónde empezar con ellos.

Como esto no es realmente una sola pregunta, me gustaría intentar señalar las preguntas para mayor claridad, pero siéntete libre de añadir otra información que sientas que resolvería el problema, porque podría estar haciendo las preguntas equivocadas xD

1- ¿Cómo inicio "the Loop" para obtener las categorías/subcategorías?
2- ¿Cómo ordeno las categorías y mantengo las subcategorías anidadas?
3- ¿Cómo me aseguro de que los posts caigan en los divs correctos? Por si WP hace algo raro.

Gracias por la ayuda.

--- Actualización ---

He estado investigando en internet intentando encontrar soluciones y estoy empezando a llegar a algún lado, pero todavía no estoy del todo allí. Esto es lo que tengo hasta ahora:

<?php
        // obtener todas las categorías de la base de datos
        $args1 = array(
          'orderby' => 'ID',
          'order' => 'ASC',
          'hierarchical' => true,
          );
        $cats = get_categories( $args1 ); 


            // recorrer las categorías
            foreach ($cats as $cat) {
                // configurar el ID de la categoría
                $cat_id= $cat->term_id;
                // Crear un encabezado para la categoría
                echo "<h2>".$cat->name."</h2><p>".$cat->term_id."</p>";
                // crear una consulta personalizada de WordPress
                $args2 = 'cat=' . $cat_id . '&orderby=date&order=DESC&post_per_page=-1';
                query_posts( $args2 );
                // ¡iniciar el loop de WordPress!
                if (have_posts()) : while (have_posts()) : the_post(); ?>

                    <?php // crear nuestro enlace ahora que el post está configurado ?>
                    <a href="<?php the_permalink();?>"><?php the_title(); ?></a>
                    <?php echo '<hr/>'; ?>

                <?php endwhile; endif; // terminar nuestro loop de WordPress. Se reiniciará para cada categoría ?>
            <?php } // terminar la declaración foreach ?>

Encontré este código en este sitio web. Muestra todas las categorías y coloca los posts debajo de ellas, pero replica los posts para la categoría padre así:

<h2>Category1</h2><p>2</p> 
    <a href="http://localhost/wordpress/2013/05/06/test0/">test0</a>
                    <hr> 
<h2>Category2</h2><p>3</p>
    <a href="http://localhost/wordpress/2013/05/15/test2/">test2</a>
                    <hr> 
    <a href="http://localhost/wordpress/2013/05/14/test1/">test1</a>
                    <hr> 
<h2>Sub-category1</h2><p>4</p>
    <a href="http://localhost/wordpress/2013/05/14/test1/">test1</a>
                    <hr> 
<h2>Sub-category2</h2><p>5</p>
    <a href="http://localhost/wordpress/2013/05/15/test2/">test2</a>
                    <hr> 

Como puedes ver los posts, test1 y test2 se muestran en Category2 y eso no es exactamente lo que quería, como se describe en la pregunta inicial (resultado HTML final).

Creo que necesito añadir una declaración condicional para verificar si la categoría actual tiene hijos y si los tiene saltar a las categorías hijas, si no poblarla. Pero todavía estoy tratando de averiguar cómo hacer eso. No he llegado a un punto en el que me sienta lo suficientemente cómodo como para empezar a intentar implementar los divs que pretendo tener en el resultado HTML final pero tengo la sensación de que también tendré un problema con eso. En este punto básicamente estoy tratando de aprender un poco más sobre este "asunto de los loops" hasta obtener un resultado decente que me permita entender todo el asunto.

Soy consciente de estos 2 enlaces A y B pero todavía soy un novato y realmente no puedo llegar allí todavía, así que básicamente estoy trabajando con código que veo que funciona y trataré de mejorarlo a medida que avance.

--- Actualización ---

Esto parece mostrar los posts en el orden correcto y sin repetirse para las categorías padre.

<?php
        // obtener todas las categorías de la base de datos
        $args1 = array(
          'orderby' => 'ID',
          'order' => 'ASC',
          'hierarchical' => true
          );
        $cats = get_categories( $args1 ); 

            // recorrer las categorías
            foreach ($cats as $cat) {
                $cat_id= $cat->term_id;// configurar el ID de categoría
                $cat_name= $cat->name;// configurar el nombre de categoría
                $parent= $cat->category_parent;// configurar el padre de categoría
                $cat_child= get_term_children( $cat_id, 'category' ); //la función get_category_children() está obsoleta... corregido eso

                $has_child=bool; //
                if( empty($cat_child)) { $has_child= false; }
                else { $has_child= true; }

                if ( $parent == 0 && $has_child == true ) { //es padre && tiene hijo -> título del post
                    echo "<h2>".$cat_name."</h2>";
                    echo '<hr/>'; }
                elseif ( $parent == 0 && $has_child == false ) { //es padre && no tiene hijo -> loop de posts
                    echo "<h2>".$cat_name."</h2>";
                    // crear una consulta personalizada de WordPress
                    $args2 = 'cat=' . $cat_id . '&orderby=date&order=DESC&post_per_page=-1';
                    query_posts( $args2 );
                    // iniciar el loop de WordPress!
                    if (have_posts()) : while (have_posts()) : the_post(); ?>
                        <?php the_title(); ?>
                        <?php echo '<hr/>'; ?>
                    <?php endwhile; endif; }
                else { //es hijo -> loop de posts
                    echo "<h2>".$cat_name."</h2>";
                    // crear una consulta personalizada de WordPress
                    $args2 = 'cat=' . $cat_id . '&orderby=date&order=DESC&post_per_page=-1';
                    query_posts( $args2 );
                    // iniciar el loop de WordPress!
                    if (have_posts()) : while (have_posts()) : the_post(); ?>
                        <?php the_title(); ?>
                        <?php echo '<hr/>'; ?>
                    <?php endwhile; endif;   // terminar nuestro loop de WordPress. Se reiniciará para cada categoría ?>
            <?php }} // terminar la declaración foreach ?>

Dividí esto en 3 condiciones: es padre y tiene hijo, es padre pero no tiene hijo y es hijo. La función que me permitió llegar aquí es get_category_children();.

Al leer el código ahora me hace pensar que podría haber simplemente verificado si $cat_child estaba vacío directamente en las declaraciones if/elseif principales, evitando el rodeo de $has_child.

0
Todas las respuestas a la pregunta 1
0

Después de mucho investigar, llegué a un código que hace exactamente lo que necesitaba. Sin embargo, no creo que este código sea bonito/eficiente/reutilizable de ninguna manera. Solo lo publico porque ejecuta lo esperado. Agradecería una respuesta que me señale la forma de codificación de "mejores prácticas" para poder aprender de ella, por lo que no marcaré mi pregunta como respondida durante una semana más o menos para esperar algún código mejor.

Este es el resultado al que llegué:

<?php
        $isOdd = true; // configura un booleano para determinar el id del div padre para CSS
        $args1 = array(
          'orderby' => 'ID',
          'order' => 'ASC',
          'hierarchical' => true
          );
        $cats = get_categories( $args1 ); // obtiene todas las categorías de la base de datos

            // recorre las categorías
            foreach ($cats as $cat) {
                $cat_id= $cat->term_id;// configura el ID de la categoría
                $cat_name= $cat->name;// configura el nombre de la categoría
                $parent= $cat->category_parent;// configura el padre de la categoría
                $cat_child= get_term_children( $cat_id, 'category' ); // genera una cadena con categorías hijas de la taxonomía


                $has_child=bool; // crea una variable que permitirá verificar si una categoría tiene hijos
                if( empty($cat_child)) { $has_child= false; }
                else { $has_child= true; }

                if ( $parent == 0 && $has_child == false ) { //es padre && sin hijos -> recorre posts
                    echo "<div class=\"parent-wrap\" id=\"". ( $isOdd ? 'odd' : 'even') . "\">";
                        echo "<h2>".$cat_name."</h2>";
                        echo "<div class=\"post-wrap\">";
                            echo "<ul class=\"post-list\">";
                                echo "<li class=\"back-button\"><</li>";

                                    // crea una consulta personalizada de WordPress
                                    $args2 = 'cat=' . $cat_id . '&orderby=date&order=DESC&post_per_page=-1';
                                    query_posts( $args2 );
                                    // inicia el loop de WordPress!
                                    if (have_posts()) : while (have_posts()) : the_post(); 
                                        get_template_part( 'content', get_post_format() ); //obtiene la plantilla del post desde content.php
                                    endwhile; endif;

                                echo "<li class=\"front-button\">></li>";
                            echo "</ul><!-- .post-list -->";
                        echo "</div><!-- .post-wrap -->";
                    echo "</div><!-- .parent-wrap -->";
                    $isOdd = !$isOdd;
                    }
                elseif ( $parent == 0 && $has_child == true ) { //es padre && tiene hijos -> título del post
                    echo "<div class=\"parent-wrap\" id=\"". ( $isOdd ? 'odd' : 'even') . "\">";
                        echo "<h2>".$cat_name."</h2>";

                        // recorre las categorías EN LA DECLARACIÓN ELSEIF
                        foreach ($cats as $cat) {
                            $cat_id_new= $cat->term_id;// configura el nuevo ID de categoría
                            $cat_name_new= $cat->name;// configura el nuevo nombre de categoría
                            $parent_new= $cat->category_parent;// configura el nuevo padre de categoría
                            $cat_child_new= get_term_children( $cat_id_new, 'category' ); // genera una cadena con categorías hijas de la taxonomía

                            $has_child_new=bool; // crea una nueva variable que permitirá verificar si una categoría tiene hijos
                            if( empty($cat_child_new)) { $has_child_new= false; }
                            else { $has_child_new= true; }

                            if ($parent_new != 0 && $has_child_new == false && cat_is_ancestor_of($cat_id, $cat_id_new) ) { //es hijo -> recorre posts
                                echo "<div class=\"child-wrap\">";
                                    echo "<h3>".$cat_name_new."</h3>";
                                    echo "<div class=\"post-wrap\">";
                                        echo "<ul class=\"post-list\">";
                                            echo "<li class=\"back-button\"><</li>";

                                                // crea una consulta personalizada de WordPress
                                                $args2 = 'cat=' . $cat_id_new . '&orderby=date&order=DESC&post_per_page=-1';
                                                query_posts( $args2 );
                                                // inicia el loop de WordPress!
                                                if (have_posts()) : while (have_posts()) : the_post(); 
                                                    get_template_part( 'content', get_post_format() ); //obtiene la plantilla del post desde content.php
                                                endwhile;
                                                endif; // termina nuestro loop de WordPress. Se reiniciará para cada categoría 

                                            echo "<li class=\"front-button\">></li>";
                                        echo "</ul><!-- .post-list -->";
                                    echo "</div><!-- .post-wrap -->";
                                echo "</div><!-- .child-wrap -->";
                            } // cierra if ($parent_new != 0...
                        } // cierra foreach en elseif
                    echo "</div><!-- .parent-wrap -->";
                    $isOdd = !$isOdd;
                } // cierra if ($parent == 0...
            } // cierra el primer foreach ?>

Siento que algunas cosas en este código podrían organizarse mejor si se crearan funciones y luego se reutilizaran en todo el código, y todavía estoy pensando en reemplazar query_posts(); con get_posts(); o pre_get_posts();.

17 may 2013 18:22:37