I did something similar for a client a while back, I’ll give you some of the code here as-is that you can possibly adapt to your needs. I’ll warn you, it’s quite a bit to parse through!
First, I set up some custom rewrite rules to get the year/month URL structure and some query vars to pass the year and month to my template. In this example I have a page set up with the slug event-calendar
that I use as my events list / archive page. This code would go in functions.php
:
<?php
add_action( 'init', 'wpse_rewrites_init' );
function wpse_rewrites_init(){
// after adding, visit settings > permalinks to flush rewrite rules!
add_rewrite_rule(
'event-calendar/([0-9]+)/([0-9]+)/?$',
'index.php?pagename=event-calendar&wpse_year=$matches[1]&wpse_month=$matches[2]',
'top' );
add_rewrite_rule(
'event-calendar/([0-9]+)/?$',
'index.php?pagename=event-calendar&wpse_year=$matches[1]',
'top' );
}
add_filter( 'query_vars', 'wpse_query_vars' );
function wpse_query_vars( $query_vars ){
$query_vars[] = 'wpse_year';
$query_vars[] = 'wpse_month';
return $query_vars;
}
This is the code in my page-event-calendar.php
template to query for events based on the year and month (if it’s set), otherwise I show just upcoming events:
<?php
// default args, upcoming events
$args = array(
'posts_per_page' => -1,
'meta_key' => 'event_date',
'meta_value' => date('Y-m-d'),
'meta_compare' => '>=',
'orderby' => 'meta_value',
'order' => 'ASC'
);
// get the year and month query vars
$wpse_year = get_query_var('wpse_year');
$wpse_month = get_query_var('wpse_month');
// if a month was set we query for the requested month/year (we assume year is set if month is)
if($wpse_month):
$estart = $wpse_year.'-'.$wpse_month.'-01';
$eend = $wpse_year.'-'.$wpse_month.'-31';
$args = array(
'posts_per_page' => -1,
'meta_query' => array(
array(
'key' => 'event_date',
'value' => array( $estart, $eend ),
'compare' => 'BETWEEN',
'type' => 'date',
)
),
'orderby' => 'meta_value',
'order' => 'ASC'
);
endif;
// if just a year is set, we query for the requested year
if($wpse_year&&!$wpse_month):
$estart = $wpse_year.'-01-01';
$eend = $wpse_year.'-12-31';
$args = array(
'posts_per_page' => -1,
'meta_query' => array(
array(
'key' => 'event_date',
'value' => array( $estart, $eend ),
'compare' => 'BETWEEN',
'type' => 'date',
)
),
'orderby' => 'meta_value',
'order' => 'ASC'
);
endif;
// query for our events
$events = new WP_Query($args);
while($events->have_posts()) : $events->the_post();
// do your normal loop stuff here
endwhile;
To output an archive list of years / months for my past events, I do some custom SQL to get all unique meta values for the event_date
key. It’s quicker than doing a join with the actual posts, but the downside is you’ll get meta values for possibly unpublished posts. This was ok for my client’s needs, but possibly not yours.
$query = "SELECT DISTINCT meta_value FROM $wpdb->postmeta WHERE meta_key = 'event_date' AND DATE(meta_value) < DATE(NOW()) ORDER BY meta_value DESC";
$all_unique_dates = $wpdb->get_results($query);
You could remove the AND DATE(meta_value) < DATE(NOW()
condition if you want future events in the list as well.
ok, that’s it! Hope you find some of this useful.