Question

I need help grouping posts by month+year (sorted by the date the posts were published a), when in result I'd have something like this:

November 2019
Event 1
Event 2
December 2019
Event 3
Event 4
January 2020
Event 5
...

I've been looking everywhere for a solution, but I still can't figure it out. I'm using a code, I found here, which I guess should do the job, but I'm not so fluent in php, so I can't figure out how to get the date at $current_year and $current_month. Right now it's looking like this:

        <?php
    $current_year = $current_month = '';

    while ( have_posts() ) :
        the_post();

        $last_year = $current_year;
        $last_month = $current_month;

        $current_year = date( 'Y', strtotime( get_post_meta( get_the_ID(), '_date', true ) ) );
        if ( $last_year != $current_year ) {
            $last_month = '';
        }
        $current_month = date( 'F', strtotime( get_post_meta( get_the_ID(), 'event_startdate', true ) ) );
?>
    <?php if ( $last_year != $current_year ) : ?><h2><?php echo $current_year; ?></h2><?php endif; ?>
    <?php if ( $last_month != $current_month ) : ?><h3><?php echo $current_month; ?></h3><?php endif; ?>
           <?php get_template_part( 'template-parts/content-pasakumi', get_post_type() ); ?>
<?php endwhile; ?>

with the functions.php containing this:

add_action( 'pre_get_posts', function ( $query ) {
    if ( is_post_type_archive( 'pasakumi' ) && $query->is_main_query() ) {
        $query->set( 'post_type', 'pasakumi' );
        $query->set( 'orderby', 'date' );
        $query->set( 'order', 'ASC' );
    }
} );

(the custom post type is pasakumi)

Any help would be appreciated!

EDIT: After lots of tinkering around, this is the final code for the archive page, which worked for me:

<?php
    $current_year = $current_month = '';

    while ( have_posts() ) :
        the_post();

        $last_year = $current_year;
        $last_month = $current_month;
        $current_year = get_post_time( 'Y', TRUE, get_the_ID(), TRUE );
        if ( $last_year != $current_year ) {
            $last_month = '';
        }
        $current_month = get_post_time( 'F', TRUE, get_the_ID(), TRUE );
?>
    <?php if ( $last_year != $current_year ) : ?><h2><?php echo $current_year; ?></h2><?php endif; ?>
    <?php if ( $last_month != $current_month ) : ?><h3><?php echo $current_month; ?></h3><?php endif; ?>
           <?php get_template_part( 'template-parts/content-pasakumi', get_post_type() ); ?>
<?php endwhile; ?>
Was it helpful?

Solution

The basic principle here is that you don't need to really 'group' posts, per se. So no query magic is required (it just needs to be sorted by date, which is the default). What you're doing is that as you go through the list of posts, you make note of the month that the post belongs to, then when that month is different to the previous posts' month, that means you've entered a new group of posts, and should output the heading.

In your context, when dealing with the post publication date, you want to use get_the_date(), but with the format set to F Y, which is "February 2019", for example, which is how the posts are being grouped. You could group posts by day by including the day in the date format.

So all together, you have:

// Initialize the current month as null, so that the first group's heading is output.
$current_month = null;

while ( have_posts() ) : the_post();
    // Compare month of this post, to the current month.
    $this_month = get_the_date( 'F J' );

    // If we're in a new month, output the month heading.
    if ( $this_month !== $current_month ) {
        echo '<h2>' . $this_month . '</h2>';
    }

    // Set the current month to the month of the current post.
    $current_month = $this_month;

    // Display post here.
endwhile;
Licensed under: CC-BY-SA with attribution
Not affiliated with wordpress.stackexchange
scroll top