Perhaps there are better optimized ways, but this is how I would do it:
- Get all Events by using WP_Query, and sort them by your custom date field
- Loop through all of them and create a new multidimensional array
- In this array we are grouping all posts by their date (month and year)
- And lastly, loop through our new array, to get the dates and events we extracted
Here's the code:
<?php
// Edit these values
$custom_post_type = 'event';
$custom_date_field = 'event_date';
$order = 'ASC'; // from the oldest to the newest
// query
$the_query = new WP_Query( [
'post_type' => $custom_post_type,
'posts_per_page' => - 1,
'meta_key' => $custom_date_field,
'orderby' => 'meta_value',
'order' => $order,
] );
// We are creating new multidimensional array
$all_events = [];
while ( $the_query->have_posts() ) :
$the_query->the_post();
$date = strtotime( get_post_meta( get_the_ID(), $custom_date_field, true ) );
$month_year = date( "F Y", $date );
$all_events[ $month_year ][] = $the_query->post;
endwhile;
wp_reset_query();
// And to print this:
foreach ( $all_events as $month_year => $events ) : ?>
<h3><?php echo $month_year ?></h3>
<ul>
<?php
/** @var \WP_Post $event */
foreach ( $events as $event ) : ?>
<li><?php
// post title
echo $event->post_title;
// any custom field
the_field( 'acf_custom_field', $event->ID );
?></li>
<?php endforeach; ?>
</ul>
<?php endforeach; ?>
You can do whatever you want inside the second foreach
loop. Edit it as you need.