Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

I would like some help to post all the posts of my website into a blogroll sorted by categories and subcategories.

The end-result HTML I would like to see displayed would be something like this:

<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 -->

The file-structure I foresaw for this would be something like this:

custom-category.php //this file would pull out the categories, sort them and create the container divs for #category and #sub-category and call the post info from within it's loop/query with get_template_part( 'content', get_post_format() );

content.php //this file would sort the ul#posts and all sorts of info I might want to add regarding the post itself

Now the main issues I have right now, is not really knowing where to start looking to even try and figure this out by myself. I keep looking at the default category.php file and I feel it'll look nothing like it.

I've tried looking at plugins but some only sort the categories in side-bars, others allow creating custom fields for categories but reviews mention you can't call on those values. I've tried the wp_list_categories(); function to try and start somewhere, but it doesn't even list the sub-categories.

I've read about creating your own query_posts(); or get_posts(); but I don't really know where to start with those.

Since this isn't really a single question, I'd like to try and point the questions out for clarity, but feel free to add other info you might feel would take care of the issue, cause I might ask the wrong questions xD

1- How do I start "the Loop" to obtain the categories/sub-categories?
2- How do I sort the categories and keep the sub-categories nested?
3- How will I make sure the posts will fall into the right divs? Just in case WP does something funny.

Thank you for the help.

--- Update ---

I've been poking the internet trying to find solutions and I'm starting to get somewhere, but not quite there yet. This is what I've got so far:

<?php
        // get all the categories from the database
        $args1 = array(
          'orderby' => 'ID',
          'order' => 'ASC',
          'hierarchical' => true,
          );
        $cats = get_categories( $args1 ); 


            // loop through the categries
            foreach ($cats as $cat) {
                // setup the cateogory ID
                $cat_id= $cat->term_id;
                // Make a header for the cateogry
                echo "<h2>".$cat->name."</h2><p>".$cat->term_id."</p>";
                // create a custom wordpress query
                $args2 = 'cat=' . $cat_id . '&orderby=date&order=DESC&post_per_page=-1';
                query_posts( $args2 );
                // start the wordpress loop!
                if (have_posts()) : while (have_posts()) : the_post(); ?>

                    <?php // create our link now that the post is setup ?>
                    <a href="<?php the_permalink();?>"><?php the_title(); ?></a>
                    <?php echo '<hr/>'; ?>

                <?php endwhile; endif; // done our wordpress loop. Will start again for each category ?>
            <?php } // done the foreach statement ?>

I found this piece of code on this website. It outputs all the categories and puts the posts under them, but it replicates the posts for the parent category like this:

<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> 

As you can see the posts, test1 and test2 are displayed in Category2 and that isn't quite what I wanted, as described in the initial question (end-result HTML).

I believe I need to add a conditional statement to verify if the current category has children and if it does jump to the child categories, if not populate it. But I'm still trying to figure out how to do that. I haven't reached a point where I'm comfortable enough to start trying to implement the div's that I intend to have in the end-result HTML but I have a feeling I'll have an issue with that as well. At this point I'm basically trying to learn a bit more about this "loop stuff" till I get a decent result that will allow me to wrap my head around the whole thing.

I am aware of these 2 links A and B but I'm still a novice and can't really get there quite yet, so I'm basically working with code I see is working and will try to get it improved as I move along.

--- Update ---

This seems to output the posts in the correct order and without repeating themselves for parent categories.

<?php
        // get all the categories from the database
        $args1 = array(
          'orderby' => 'ID',
          'order' => 'ASC',
          'hierarchical' => true
          );
        $cats = get_categories( $args1 ); 

            // loop through the categries
            foreach ($cats as $cat) {
                $cat_id= $cat->term_id;// setup the cateogory ID
                $cat_name= $cat->name;// setup the category name
                $parent= $cat->category_parent;// setup the category parent
                $cat_child= get_term_children( $cat_id, 'category' ); //the function I had get_category_children(); was deprecated... fixed that

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

                if ( $parent == 0 && $has_child == true ) { //is parent && has child -> post title
                    echo "<h2>".$cat_name."</h2>";
                    echo '<hr/>'; }
                elseif ( $parent == 0 && $has_child == false ) { //is parent && no child -> loop posts
                    echo "<h2>".$cat_name."</h2>";
                    // create a custom wordpress query
                    $args2 = 'cat=' . $cat_id . '&orderby=date&order=DESC&post_per_page=-1';
                    query_posts( $args2 );
                    // start the wordpress loop!
                    if (have_posts()) : while (have_posts()) : the_post(); ?>
                        <?php the_title(); ?>
                        <?php echo '<hr/>'; ?>
                    <?php endwhile; endif; }
                else { //is child -> loop posts
                    echo "<h2>".$cat_name."</h2>";
                    // create a custom wordpress query
                    $args2 = 'cat=' . $cat_id . '&orderby=date&order=DESC&post_per_page=-1';
                    query_posts( $args2 );
                    // start the wordpress loop!
                    if (have_posts()) : while (have_posts()) : the_post(); ?>
                        <?php the_title(); ?>
                        <?php echo '<hr/>'; ?>
                    <?php endwhile; endif;   // done our wordpress loop. Will start again for each category ?>
            <?php }} // done the foreach statement ?>

I divided this into 3 conditions: is parent and has child, is parent but no child and is child. The function that allowed me to get here is get_category_children();.

Reading the code now makes me think I could've just checked if $cat_child was empty directly in the main if/elseif statements, avoiding the $has_child run-a-round.

share|improve this question
add comment

1 Answer

up vote 1 down vote accepted

Ok, so after a lot of digging around I came up with code that does exactly what I asked for. However I don't believe this code to be pretty/efficient/reusable in any way. I'm merely posting it since it executes what was expected. I would appreciate an answer that would point me to the "best practice" way of coding so I could learn from it, so I won't mark my question as answered for a week or so to wait for some better coding.

This is the result I came to:

<?php
        $isOdd = true; // setup boolean to determine parent div id for CSS
        $args1 = array(
          'orderby' => 'ID',
          'order' => 'ASC',
          'hierarchical' => true
          );
        $cats = get_categories( $args1 ); // get all the categories from the database

            // loop through the categries
            foreach ($cats as $cat) {
                $cat_id= $cat->term_id;// setup the cateogory ID
                $cat_name= $cat->name;// setup the category name
                $parent= $cat->category_parent;// setup the category parent
                $cat_child= get_term_children( $cat_id, 'category' ); // outputs a string with child categories from the taxonomy


                $has_child=bool; // create a variable that will allow to verify if a category has children
                if( empty($cat_child)) { $has_child= false; }
                else { $has_child= true; }

                if ( $parent == 0 && $has_child == false ) { //is parent && no child -> loop 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>";

                                    // create a custom wordpress query
                                    $args2 = 'cat=' . $cat_id . '&orderby=date&order=DESC&post_per_page=-1';
                                    query_posts( $args2 );
                                    // start the wordpress loop!
                                    if (have_posts()) : while (have_posts()) : the_post(); 
                                        get_template_part( 'content', get_post_format() ); //get post template from 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 ) { //is parent && has child -> post title
                    echo "<div class=\"parent-wrap\" id=\"". ( $isOdd ? 'odd' : 'even') . "\">";
                        echo "<h2>".$cat_name."</h2>";

                        // loop through the categries IN THE ELSEIF STATEMENT
                        foreach ($cats as $cat) {
                            $cat_id_new= $cat->term_id;// setup the new cateogory ID
                            $cat_name_new= $cat->name;// setup the new category name
                            $parent_new= $cat->category_parent;// setup the new category parent
                            $cat_child_new= get_term_children( $cat_id_new, 'category' ); // outputs a string with child categories from the taxonomy

                            $has_child_new=bool; // create a new variable that will allow to verify if a category has children
                            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) ) { //is child -> loop 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>";

                                                // create a custom wordpress query
                                                $args2 = 'cat=' . $cat_id_new . '&orderby=date&order=DESC&post_per_page=-1';
                                                query_posts( $args2 );
                                                // start the wordpress loop!
                                                if (have_posts()) : while (have_posts()) : the_post(); 
                                                    get_template_part( 'content', get_post_format() ); //get post template from content.php
                                                endwhile;
                                                endif; // done our wordpress loop. Will start again for each category 

                                            echo "<li class=\"front-button\">></li>";
                                        echo "</ul><!-- .post-list -->";
                                    echo "</div><!-- .post-wrap -->";
                                echo "</div><!-- .child-wrap -->";
                            } // close if ($parent_new != 0...
                        } // close foreach in elseif
                    echo "</div><!-- .parent-wrap -->";
                    $isOdd = !$isOdd;
                } // close if ($parent == 0...
            } // close the 1st foreach statement ?>

I feel some of the things in this code could be better organized if functions were created and then reused throughout the code and I'm still thinking about replacing query_posts(); with get_posts(); or pre_get_posts();.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.