Take the 2-minute tour ×

I want to display posts links from a category group by year. Group by year becouse by default wordpress repeat the date for each post. I try use a code but I got all post in current year. How can I do it? Example I want to do:


  • post link 20
  • post link 19
  • post link 18
  • ...
  • post link 8


  • post link 7
  • post link 6
  • ...

The code:

query_posts(array('nopaging' => 1, /* desabilitar a paginacao pata obter todos os pots. O padrao e ordenado pela data */));
$prev_year = null;


if ( have_posts() ) {
   while ( have_posts() ) {
      $this_year = get_the_date('Y');
      if ($prev_year != $this_year) {
          // Year boundary
          if (!is_null($prev_year)) {
             // A list is already open, close it first
             echo '</ul>';
          echo '<h2 class="titulo-conteudo">'. $this_year . '</h2>';
   echo '<div class="barra-amarela-4"></div>';
              echo '<ul>';
      echo '<li>';

      // Imprimi o link do post.
  the_post(); ?>

                <div class="entry">
  <a href="<?php the_permalink(the_title()) ?>"><?php the_title(); ?></a></h2>



      echo '</li>';
      $prev_year = $this_year;

   echo '</ul>';


share|improve this question

4 Answers 4

I wrote that original code on Stack Overflow, but I didn't see your further replies because you posted them as answers and not as comments to my answer. I have tested the code now with a specific category and it works for me, but it needs one crucial change: the call to the_post() (which I completely forgot) must come right at the beginning of the while ( have_posts() ) loop, otherwise the year will always lag one post behind. I have corrected that in the original answer.

If you want to specify multiple criteria for your query, you must combine them in the same function call. So not query_posts('cat=27'); query_posts('nopaging=1');, but query_posts('cat=27&nopaging=1'). You can also use the array format (as in my original example), I prefer that for readability.

A last change: if this is not the main loop of your page (and I suspect this code will end up in a sidebar, so not the main loop), [it is better not to use query_posts()][2]. Instead, try get_posts() and use the result of that. I did not know this when I wrote the original answer, but hanging around on this site learns you a lot!

share|improve this answer

Your code got very broken when posted. From what I can see multiple query_posts() are bad idea in most cases. Please correct your code if you want better assessment.

Personally I would use plugin for this, there are plenty of excellent archive plugins around. I currently play with Smart Archives Reloaded. It allows easily to get posts by month/year in specific category:

smart_archives( array( 'format' => 'list', 'include_cat' => 27 ));

share|improve this answer

The details of your question are incoherent. You should read the question aloud to yourself before posting. Your code block is also totally broken.

That said the answer is fairly simple. You need to run a posts query that gives both the category and year values (as well as your nopaging, which is best done with posts_per_page=-1)

See the codex article for query_posts() for full details about prarameters you can pass into new WP_Query().

Here's the code for your question:

 * Run a query for a specific category (cat=$cat_id) and year (&y=2008)
 * Also turn off the paging by setting posts_per_page to -1
$year_and_category_query = new WP_Query("cat=$cat_id&year=2007&posts_per_page=-1");

 * Run the loop on your new query
while ($year_and_category_query->have_posts()) : $year_and_category_query->the_post();
    // Use the post with functions like the_title, or use the now global $post
share|improve this answer
When someone's in-line comments are in a non-English language and they're posting for support on an English-speaking forum, you should give them the benefit of the doubt and not start with a "read the question aloud" statement. That's just rude. –  EAMann Oct 11 '10 at 20:56
Jeremy Clarke - I have to agree with @EAMann; let's give non-English speakers some slack. This ain't wp-hackers, after all. :-) –  MikeSchinkel Oct 12 '10 at 7:57

What you have looks to work well.. Since I was on here looking for solutions to another question I posted and came across this one, I thought I'd add how I accomplished this in one of my sites:

            <?php query_posts('posts_per_page=-1&category_name=podcasts');
            $dates_array            = Array();
            $year_array             = Array();
            $i                      = 0;
            $prev_post_ts           = null;
            $prev_post_year         = null;
            $distance_multiplier    =  9;

        <div class="post">

            <!--h2 class="title">< ? php the_title(); ?></h2-->

            <div id="archives" class="entry">   

                $post_ts    =  strtotime($post->post_date);
                $post_year  =  get_the_date('Y');

                /* Handle the first year as a special case */
                if ( is_null( $prev_post_year ) ) {
                    <h3 class="archive_year"><?=$post_year?></h3>
                    <ul class="archives_list">
                else if ( $prev_post_year != $post_year ) {
                    /* Close off the OL */

                    $working_year  =  $prev_post_year;

                    /* Print year headings until we reach the post year */
                    while ( $working_year > $post_year ) {
                        <h3 class="archive_year"><?=$working_year?></h3>

                    /* Open a new ordered list */
                    <ul class="archives_list">

                /* Compute difference in days */
                if ( ! is_null( $prev_post_ts ) && $prev_post_year == $post_year ) {
                    $dates_diff  =  ( date( 'z', $prev_post_ts ) - date( 'z', $post_ts ) ) * $distance_multiplier;
                else {
                    $dates_diff  =  0;
                    <span class="date"><?php the_time('F j'); ?><sup><?php the_time('S') ?></sup></span> 
                    <span class="linked"><a href="<?php the_permalink() ?>"><?php the_title(); ?></a></span> 
                    <span class="comments"><?php comments_popup_link(__('0 comments', 'warp'), __('1 comment', 'warp'), __('% comments', 'warp')); ?></span> 
                /* For subsequent iterations */
                $prev_post_ts    =  $post_ts;
                $prev_post_year  =  $post_year;

            /* If we've processed at least *one* post, close the ordered list */
            if ( ! is_null( $prev_post_ts ) ) {
            <?php } ?>



This eliminates multiple query_posts calls and is really easy to control styling, etc.. hope this helps someone who may be wanted to see various solutions to this :)

Great work again, on your orig. solution.

share|improve this answer

Your Answer

