Get all categories and posts in those categories

EDIT REVISIT NO 2

I have never touched the Transient API, until today when I saw @MikeSchinkel answer in this post. This inspired me to revisit this post once again. After some testing, I came up with the following:

  • Time to execute went down from ~0.07 seconds to ~0.002seconds

  • Database query time went down by about halve

  • With the transient, only 2 db queries are executed

How the code works (Just going to discuss changes from the original code from REVISIT):

STEP 1

We need to save the value of $q to a transient, this is the value that holds the category list with post titles.

STEP 2

We first need to check if a transient exists, and if none exists, create the transient. If the transient exists, retrieve its info

STEP 3

This info is now be passed through a foreach loop to print the list with category names and post titles.

STEP 4

As it stands, the transient will be updated every twelve hours. This can be set to suite your needs. However, the transient will need to be deleted and recreated every time a post’s status changes. This might be from draft to publish, a new post being published or a post that’s being trashed. To do this, you need to make use of delete_transient which will be hooked to transition_post_status which will be triggered each time a post’s status changes

Here is the complete code:

In your functions.php

add_action( 'transition_post_status', 'publish_new_post', 10, 3 );

function publish_new_post() {
   delete_transient( 'category_list' );
}

In your template where you need to display your list

<?php
if ( false === ( $q = get_transient( 'category_list' ) ) ) {

    $args = array( 
        'posts_per_page' => -1
    );

    $query = new WP_Query($args); 

    $q = array();

    while ( $query->have_posts() ) { 

        $query->the_post(); 

        $a="<a href="". get_permalink() .'">' . get_the_title() .'</a>';

        $categories = get_the_category();

        foreach ( $categories as $key=>$category ) {

            $b = '<a href="' . get_category_link( $category ) . '">' . $category->name . '</a>';    

        }

        $q[$b][] = $a; // Create an array with the category names and post titles
    }


    /* Restore original Post Data */
    wp_reset_postdata();

set_transient( 'category_list', $q, 12 * HOUR_IN_SECONDS );
}

foreach ($q as $key=>$values) {
        echo $key;

        echo '<ul>';
            foreach ($values as $value){
                echo '<li>' . $value . '</li>';
            }
        echo '</ul>';
    }


?>

REVISIT

I recently came up with a very lightweight solution that is way much faster than the other possible solutions given. On my test site I get a total generation time of only ~0.07 seconds and only 6 db queries according to Query Monitor while the other methods give me a generation time of ~0.35 seconds and 50 extra db queries.

Here is a breakdown of my method

STEP 1

You first need to create a custom query with WP_Query to retrieve all published posts

$args = array( 
        'posts_per_page' => -1
    );

    $query = new WP_Query($args);   
    $q = array();

    while ( $query->have_posts() ) { 

    }

    /* Restore original Post Data */
    wp_reset_postdata();

Step 2

Using get_the_category, retrieve a list of all categories a post belongs to.

$categories = get_the_category();

        foreach ( $categories as $key=>$category ) {

            $b = '<a href="' . get_category_link( $category ) . '">' . $category->name . '</a>';    

        }

STEP 3

Assign variables to the post title and the categories of the post

$a="<a href="". get_permalink() .'">' . get_the_title() .'</a>';

and

$b = '<a href="' . get_category_link( $category ) . '">' . $category->name . '</a>';    

STEP 4

Combine these two variables to form a multidimensional array

$q[$b][] = $a;

To see what is happening in the array, simply do a var_dump

?><pre><?php var_dump($q); ?></pre><?php

STEP 5

Using foreach loops, create your post list sorted by category

foreach ($q as $key=>$values) {
    echo $key;

    echo '<ul>';
        foreach ($values as $value){
            echo '<li>' . $value . '</li>';
        }
    echo '</ul>';
}

ALL TOGETHER NOW!

Here is the complete code

<?php

    $args = array( 
        'posts_per_page' => -1
    );

    $query = new WP_Query($args);   
    $q = array();

    while ( $query->have_posts() ) { 

        $query->the_post(); 

        $a="<a href="". get_permalink() .'">' . get_the_title() .'</a>';

        $categories = get_the_category();

        foreach ( $categories as $key=>$category ) {

            $b = '<a href="' . get_category_link( $category ) . '">' . $category->name . '</a>';    

        }

        $q[$b][] = $a; // Create an array with the category names and post titles
    }

    /* Restore original Post Data */
    wp_reset_postdata();

    foreach ($q as $key=>$values) {
        echo $key;

        echo '<ul>';
            foreach ($values as $value){
                echo '<li>' . $value . '</li>';
            }
        echo '</ul>';
    }

?>

Leave a Comment