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">
  <h2 id="post-<?php the_ID(); ?>">
  <a href="<?php the_permalink(the_title()) ?>"><?php the_title(); ?></a></h2>



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

   echo '</ul>';



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!


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">   
            <?php while (have_posts()) : the_post();

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


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
  • 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
    Commented Oct 11, 2010 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. :-) Commented Oct 12, 2010 at 7:57
  • 9 years later I'm horrified at what I wrote. Must have been a really bad day. Updating it now so your comments won't make sense but the original version had me complaining about the grammar in the question.
    – jerclarke
    Commented Sep 16, 2019 at 15:21

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.