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>';
}
?>