Right now I'm using the following code to display all posts by year:


<?php foreach(posts_by_year() as $year => $posts) : ?>
  <h2><?php echo $year; ?></h2>

    <?php foreach($posts as $post) : setup_postdata($post); ?>
        <a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
    <?php endforeach; ?>
<?php endforeach; ?>


function posts_by_year() {
  // array to use for results
  $years = array();

  // get posts from WP
  $posts = get_posts(array(
    'numberposts' => -1,
    'orderby' => 'post_date',
    'order' => 'ASC',
    'post_type' => 'post',
    'post_status' => 'publish'

  // loop through posts, populating $years arrays
  foreach($posts as $post) {
    $years[date('Y', strtotime($post->post_date))][] = $post;

  // reverse sort by year

  return $years;

And right now I have set at the reading options in the admin panel that I only want to show 3 posts per page. With this new code, the posts by year, it displays all posts and in the pagination buttons there are 3 pages. When switching to another page, it displays the same content all over again.

How can I include the pagination now that I have posts by year? My pagination code is:

<?php if(function_exists('wpex_pagination')) { wpex_pagination(); } ?>

Which calls the function:

if ( !function_exists( 'wpex_pagination' ) ) {

  function wpex_pagination() {

    $prev_arrow = is_rtl() ? '&rarr;' : '&larr;';
    $next_arrow = is_rtl() ? '&larr;' : '&rarr;';

    global $wp_query;
    $total = $wp_query->max_num_pages;
    $big = 999999999; // need an unlikely integer
    if( $total > 1 )  {
       if( !$current_page = get_query_var('paged') )
         $current_page = 1;
       if( get_option('permalink_structure') ) {
         $format = 'page/%#%/';
       } else {
         $format = '&paged=%#%';
      echo paginate_links(array(
        'base'      => str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) ),
        'format'    => $format,
        'current'   => max( 1, get_query_var('paged') ),
        'total'     => $total,
        'mid_size'    => 3,
        'type'      => 'list',
        'prev_text'   => $prev_arrow,
        'next_text'   => $next_arrow,
       ) );

The idea is that I'm able to set a number of posts to be displayed. Not by year, but by posts. So if I have 30 from 2014 and 20 from 2013 and have the limit set to 5, it'll only show the first 5 from 2014.

Thanks in advance!

EDIT: @Pieter

    $date = 0;
    $newDate = true;
    if (have_posts()) : while (have_posts()) :


    if ($date == 0)
        $date = the_date('Y');
    else if ($date != the_date('Y')) {
        $date = the_date('Y');
        $newDate = true;

    if ($newDate)
        echo $date . ' ';

    $newDate = false; ?>
    <?php get_template_part('content'); ?> 
<?php endwhile; endif; ?>
  • I don't understand your questions, because by default, posts are sorted from newest to oldest. The code above just retrieves a list of all posts displayed under a year title. The default loop with default sorting should be enough. BTW, if you are using copied code, please reveal the source. If I'm not mistaken, this is code posted by @s_ha_dum Sep 18, 2014 at 17:35
  • That's exactly what I want - a year title ONLY on the first post. If there's a way to do it through the default loop, I'd like to hear about how it's done. I've got the code from wordpress.org/support/topic/… which was posted by mikos one year ago, not sure if he got it from somewhere else too but that's from where I got it. Sep 18, 2014 at 18:49
  • Check out this answer Sep 19, 2014 at 6:06
  • @Pieter Check my edit. Tried that and in the first page it shows the year only once, but in the next pages it shows the year of each post. Sep 19, 2014 at 15:10

1 Answer 1


Here is my approach. What I interpreted and accepted is that you need to display the year on each and every first post on each page, and also you only need to display the year on subsequent posts if the year is different than that of the first year.

I did not want to use extra function which made extra db calls, also I tried to use the post objects which are available through the $wp_query global. This is what I came up with


Get the date in year form from the current post in the loop. I have used get_the_date() here.


You need to get the post date from the previous post, except when the current post is not the first post. To do this, you need to access the $wp_query->posts array, and get the post_date object from the previous WP_Post object. To get that, I've used the $wp_query->current_post counter, subtracted one and used that as the array key to access the array.


Covert the post_date with mysql2date to get the year in which the previous post was published.


If the current post is the first post, display the year the post was published in. If the current post is not the first post, you need to compare the current post's year with the year from the previous post. If these values match, the date should not be printed, and when these values don't match, print the date


You can now put this code together, and display it inside the loop where you need to display it

$current_year = get_the_date('Y');

if( 0 != $wp_query->current_post ) {        
    $f = $wp_query->current_post - 1;       
    $old_date =   mysql2date( 'Y', $wp_query->posts[$f]->post_date ); 

    if($current_year != $old_date) {
        echo $current_year;
    echo $current_year;


To remove the date from all first posts from subsequent pages if the year match the last post from the previous page, you can do the following

$current_year = get_the_date('Y');

if( 0 != $wp_query->current_post ) {        
    $f = $wp_query->current_post - 1;       
    $old_date = mysql2date( 'Y', $wp_query->posts[$f]->post_date ); 

    if($current_year != $old_date) {
        echo $current_year;
}elseif( is_paged() && 0 == $wp_query->current_post ) {
    $old_date =   get_the_date( 'Y', get_next_post()->ID );

    if($current_year != $old_date) {
        echo $current_year;
    echo $current_year;
  • This seems to work just fine! Just one correction - when switching to second page and if posts continue to be from the same date(year) as the first page, it shows the date again. Any way to avoid this? Sep 21, 2014 at 16:22
  • OK, will post soon, have to rework my code then. Sep 21, 2014 at 16:24
  • Posted an update. It should work now Sep 21, 2014 at 16:46
  • 1
    I can't thank you enough! It works perfectly! Cheers mate. Sep 21, 2014 at 17:04
  • 1
    My pleasure, enjoy :-) Sep 21, 2014 at 17:05

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.