• Resolved welcomebrand

    (@welcomebrand)


    I’m guessing it’s reasonably simple but I can’t find any instruction on how to work this so wondering if anyone could help out.

    I’ve created a custom page template (“Archive List”) and in that page I’d like to list every post from my site but split them out by year like this:

    2013
    |- A post title
    |- Another post here

    2012
    |- Older post here
    |- Some more
    |- Etc etc

    2011
    |- Etc etc etc

    Anyone able to chuck a snippet of code my way, would be very grateful ??

Viewing 11 replies - 1 through 11 (of 11 total)
  • Hi James,

    Here you go! (Adapted from this Stack Overflow thread to include a permalink):

    <?php
        // Get years that have posts
        $years = $wpdb->get_results( "SELECT YEAR(post_date) AS year FROM wp_posts WHERE post_type = 'post' AND post_status = 'publish' GROUP BY year DESC" );
    
        //  For each year, do the following
        foreach ( $years as $year ) {
    
            // Get all posts for the year
            $posts_this_year = $wpdb->get_results( "SELECT ID, post_title FROM wp_posts WHERE post_type = 'post' AND post_status = 'publish' AND YEAR(post_date) = '" . $year->year . "'" );
    
            // Display the year as a header
            echo '<h2>' . $year->year . '</h2>';
    
            // Start an unorder list
            echo '</ul>';
    
            // For each post for that year, do the following
            foreach ( $posts_this_year as $post ) {
                // Display the title as a hyperlinked list item
                echo '<li><a href="' . get_permalink($post->ID) . '">' . $post->post_title . '</a></li>';
            }
    
            // End the unordered list
            echo '</ul>';
        }
    ?>

    I’d have a function like this in my functions.php:

    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
      krsort($years);
    
      return $years;
    }

    Then do this within my template:

    <?php foreach(posts_by_year() as $year => $posts) : ?>
      <h2><?php echo $year; ?></h2>
    
      <ul>
        <?php foreach($posts as $post) : setup_postdata($post); ?>
          <li>
            <a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
          </li>
        <?php endforeach; ?>
      </ul>
    <?php endforeach; ?>

    This way you’re only hitting the database once instead of once to get the years, and then once again for each and every year.

    Thread Starter welcomebrand

    (@welcomebrand)

    Cheers Chris & Mike, both solutions output what I wanted but I went with Mike’s to save a DB call ??

    J.

    Good call. Mikos, I just bookmarked your code for future projects. Cheers!

    This is exactly what I was looking for! Thanks for sharing.

    Is it possible to collapse the years so only the most recent is open when the page loads?

    so at first it is:

    2013
    |- A post title
    |- Another post here

    2012

    2011

    and after clicking 2012 it is

    2013

    2012
    |- Older post here
    |- Some more
    |- Etc etc

    2011

    I’m using this code in a sidebar – it works great on the category archive page, but on the page of a single post it causes the wrong post to be displayed if it comes before the loop. When I put it after the loop, it works correctly. What am I missing?

    Moderator bcworkz

    (@bcworkz)

    get_post() takes over the main query object, which breaks your single post display when used first. To restore the original query object state call wp_reset_postdata() when you’re done with the sidebar output.

    The accordion effect you want with the various years is done mainly with javascript and the ‘display’ CSS property. In the loop listing the posts under each year, the first year is output normally. Then a flag is set so that all remaining <ul> blocks are output with the style attribute equal to display:none;.

    Then any click on a year executes a javascript function that first sets every <ul> in the group to have CSS display:none; which collapses any year that was expanded. Then the current year <ul> CSS is set to display:inline; to show the posts in that year.

    Thanks for your help bcworkz!

    hiteshranaut

    (@hiteshranaut)

    i want this for only one category with month
    pls help !! ??

    2014
    *jan
    |- Older post here
    |- Some more
    |- Etc etc
    *feb
    |- Older post here
    |- Some more
    |- Etc etc

    2013
    *mar
    |- Older post here
    |- Some more
    |- Etc etc
    *dec
    |- Older post here
    |- Some more
    |- Etc etc

    This code, more like me to return the post of each year regarding the category that I want?

    Moderator bcworkz

    (@bcworkz)

    @hiteshranaut, @rodrigo.mct

    This topic is 10 months old and the policy here is for each member to start a new topic instead of tagging on to someone else’s topic. This will also ensure more people will see your topic, in particular regular members using the “No Replies” filter that are in the best position to help you.

    Also refer to Template Tags/get posts, you can customize the query by using any argument valid for WP_Query to get posts in any category and ordered in any number of ways.

Viewing 11 replies - 1 through 11 (of 11 total)
  • The topic ‘List all posts on a page, split them by year’ is closed to new replies.