Archives for custom post type based on a “date” meta value

I’ve got an “Event” custom post type. Each post has a meta field for the actual event date, which cannot be the posts’s publish date, as most all the event dates will be in the future.

With that, I’m trying to create an archive (year and month) for past and future events based on the meta field. Just can’t wrap my head around how I would create a query for this and have it display like url.com/post-type/2011/01

Read More

The meta field date value is set as YYYY-MM-DD.

Any help with this one is greatly appreciated! Thanks.

Related posts

Leave a Reply

2 comments

  1. 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.

  2. Your URL display won’t work like that unfortunately…not without a good amount of shoehorning at least.

    Here’s the portion of the query you’ll need, this is untested, but should work, worst case you can store event data as a unix timestamp and convert back out when you go to display.

    $args = array(
        'post_type'  => 'event',
        'meta_query' => array(
            'key'     => 'date',
            'value'   => array( 'date_1', 'date 2' ), // try formatting these as dates and see if it works, if not, Unix timestamps will do just fine
            'compare' => 'BETWEEN'
        )
    );
    $posts = new WP_Query( $args );
    

    You can do the URLs in a less pretty manner and have it be example.com/post_type/?month=february pretty easily though. Hope this helps some.