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 am looking for a solution that allows me to print the following:

Cat 1        Cat 2        Cat 3
 Post 1       Post 1       Post 1
 Post 2       Post 2       Post 2
 Post 3                    Post 3
                           Post 4

EDIT

I am looking for something that will only require one database query! So if you have a foreach in your code followed by a new WP_Query then that is not what I am looking for (I am planning to put this onto my website's homepage).

share|improve this question
    
downvoted as your requirement turns this from a WordPress question into a php sorting problem. –  Michael Feb 25 '12 at 11:29
    
Please see my answer. Extremely quick and efficient. See the stats I've added in my answer –  Pieter Goosen Sep 7 at 13:51

5 Answers 5

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->cat_ID ) . '">' . $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->cat_ID ) . '">' . $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->cat_ID ) . '">' . $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->cat_ID ) . '">' . $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>';
    }

?>
share|improve this answer

You can use this... Set the amount of posts you need...

Also I have put it all inside a div, so you can do the structure and design your looking for.

<?php  
    $allcats = get_categories('child_of=0'); 

    foreach ($allcats as $cat) :
        $args = array(
            'posts_per_page' => 3, // set number of post per category here
            'category__in' => array($cat->term_id)
        );

        $customInCatQuery = new WP_Query($args);

        if ($customInCatQuery->have_posts()) :
            echo '<div>';
            echo '<h3>'.$cat->name.'</h3>';
            echo '<ul>';
            while ($customInCatQuery->have_posts()) : $customInCatQuery->the_post(); ?>

            <li><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></li>
        <?php
            endwhile; 
            echo '</ul></div>'; 
        ?>

<?php
        else :
            echo 'No post published in:'.$cat->name;                
        endif; 
        wp_reset_query();
    endforeach; 
?>

Hope this helps. Cheers, Sagive

share|improve this answer
    
Thx, but take the example of say 10 categories. In that case your code causes 11 SQL queries. I am looking for 1 SQL query. The best thing would probably be to get all posts, ordered by category, but I don't know how to do that (I didn't find order_by = cat in the codex) !? –  Ben Feb 24 '12 at 23:12
    
i dont think it matters one bit if its 10 categories or 20... (tried it with 20) unless you are trying to load a huge number posts which in any case might slow the page load.. try it - you'll find it real breezy - trying to rearrange after loaded via categories would mean building a huge and mostly useless code (to my humble opinion :) ) –  Sagive SEO Feb 24 '12 at 23:33
    
No it doesn't, you just need to change the output slightly (i.e. end list for cat n, and start list for cat n+1) everytime a post has a category that is different from the previous post's category... A lot simpler than bombarding your poor database with 20+ queries per pageload... (to my humble opinion :) –  Ben Feb 25 '12 at 0:04
    
i think it would we asking the database the same question but just ordering stuff differently on the output end.. i dont see the difference... besides - its a logical query.. "give me the first * from this category"... give me the first * from that category" instead of give me that post, again, again, again.. its the same way but i am puling the data in the way i need it... unless i am mistaken.. –  Sagive SEO Feb 25 '12 at 0:37
    
The difference is the number of db queries. One big vs. many small... ;) –  Ben Feb 25 '12 at 1:11

Untested, yet one of the simplest approaches I would try is the following:

<?php
    $category_ids = get_all_category_ids();
    foreach ($category_ids as $values) {
        $args = array('category' => $value);
        $posts_array = get_posts( $args );
        foreach ($posts_array as $post) : setup_postdata($post);
?> 
    <li><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></li>
<?php
        endforeach;
        wp_reset_query();
    }
?>
share|improve this answer
    
Same problem as Sagive's code –  Ben Feb 24 '12 at 23:13
    
ok. There is no way to get a single query done. Loading any page for Wordpress has multiple queries as it is, before adding custom code. All built-in queries use the WPDB class. The only way to do it in a single query is with your own transact sql or by making WPDB a parent class to another class for this purpose and calling it that way. –  Neil Davidson Mar 4 '12 at 0:14

I've build something for me that I use quite alot, here is the code, you can use slugs, ids or the term object in the $categories array, if you want to get all the categories you can use get_terms(), and feed with a bunch of term objects, but be careful, there is no treatment for hierarchy on this code.

$categories = array( 1, 'slug', 3 );
echo '<ul>';
foreach($categories as $category) {
    $term = ( is_numeric($category) || is_object($category) ? get_term( $category, 'category' ) : get_term_by( 'slug', $category, 'category' ) );
    $args = array(
        'cat' => $term->term_id
        // Add any other arguments to fit your needs
    );
    $q = new WP_Query( $args );
    if( $q->have_posts() ) {
        echo '<li><a href="' . get_term_link( $term->term_id, 'category' ) . '">' . $term->name . '</a><ul>';
        while( $q->have_posts() ) {
            $q->the_post();
            echo '<li><a href="' . get_permalink() . '">' . get_the_title() . '</a></li>';
        }
        echo '</ul></li>';
    } else {

    }
}
echo '</ul>';
share|improve this answer

if you are looking for a plugin, List Category Posts might work for you.

Fore a query, take a look at:

share|improve this answer
    
    
Thx, but that doesn't help. –  Ben Feb 24 '12 at 22:09

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.