3

More of a conceptual question here, than a strict code question:

Working on a site for a musician who wants to list concerts, both upcoming and past. These are custom post types that use a custom field for the date of the show (formatted as yyyymmdd). For queries and sorting, the date of the show is the critical bit of data, as opposed to the publish date of the post, which is kind of irrelevant.

Here's the page, which gives future and past shows for the current year: http://dev.bobpassaro.com/david/concerts/

The query to generate this (two queries and loops, actually):

<?php 
    //Query $args for upcoming concerts, ordered soonest to furthest in future
    $upcoming_args = array(
        'post_type' => 'concert',
        'meta_key' => 'date',
        'orderby' => 'meta_value_num',
        'order' => 'ASC',
        'posts_per_page' => -1,
        'meta_query' => array(
            array(
                'key' => 'date',
                'value' => date('Ymd'),
                'compare' => '>=',
            ),
        )
    );

    //Query $args for past concerts, ordered most recent to oldest
    $past_args = array(
        'post_type' => 'concert',
        'meta_key' => 'date',
        'orderby' => 'meta_value_num',
        'order' => 'DESC',
        'posts_per_page' => -1,
        'meta_query' => array(
            array(
                'key' => 'date',
                'value' => array(date('Y') . '0101',date('Ymd')),
                'compare' => 'BETWEEN',
            ),
        )
    );
?>

You'll see also (at the bottom of that page) that I sort of "paginated" the older concerts, grouping them by year. (Regular WP pagination with custom post types is a pain, but it's not what I want, anyway. I don't want pages with equal numbers of concerts, I want pages with concerts grouped by year.) So what I've done is create another template with a similar query:

<?php 
    //Query $args for past concerts, grouped by year
    $concert_year = substr($post->post_name,0,4);
    $year_args = array(
        'post_type' => 'concert',
        'meta_key' => 'date',
        'orderby' => 'meta_value_num',
        'order' => 'DESC',
        'posts_per_page' => -1,
        'meta_query' => array(
            array(
                'key' => 'date',
                'value' => array($concert_year . '0101', $concert_year . '1231'),
                'compare' => 'BETWEEN',
            ),
        )
    );
?>

This is used in a custom template that I assign to pages that I set up for each year. (The content of these pages is actually empty, but the page slug gets used to set the $concert_year variable above, which then allows the query to pull the proper set of concerts.) I then use a regular WP menu at the bottom of these pages that includes all these pages and allows people to look back at shows performed in previous years.

This all functions as I want, but it's a pretty kludgy solution. I mean, when we get to 2015, I'll have to create a new page for 2014, otherwise 2014 concerts won't be showing up anywhere. I'd like that to just happen dynamically. I also have all these essentially blank/empty pages (one for each past year), whose only function is to call the template and be used in the WP menu (that is, their only function is to allow users to select the url associated with each year and set $concert_year for use in the query.)

Thoughts on a better approach this problem?

1

This is a tough question because there are so many possible solutions. ;)

I think the easiest way is to create a custom taxonomy "year" and add it automatically to the CPT post on save using the save_post() hook and wp_set_object_terms().

You could then simply use get_terms() to get a list of years (you'll only get ones that have concerts by default) and just link to the terms archive by using get_term_link(). You could still use the default CPT archive to show the concerts from the current year.

| improve this answer | |
  • 1
    Yeah, a custom taxonomy had crossed my mind. Wasn't familiar with wp_set_object_terms(). That might help. I'll play with this. Thanks! – slashbob Jul 1 '14 at 13:07
1

You could add a custom query var and rewrite rule to handle year archives:

function wpd_concert_query_var( $query_vars ){
    $query_vars[] = 'concert_year';
    return $query_vars;
}
add_filter( 'query_vars', 'wpd_concert_query_var' );

function wpd_concert_rewrite(){
    add_rewrite_rule(
        'concerts/([0-9]+)/?$',
        'index.php?pagename=concerts&concert_year=$matches[1]',
        'top'
    );
}
add_action( 'init', 'wpd_concert_rewrite' );

Then in your concerts template you can check if a year was requested with:

get_query_var( 'concert_year' );

and query events from that year.

| improve this answer | |
  • Good idea. But I think to have it fully automatic you are still missing a way to build the year-navigation then. – s1lv3r Jun 30 '14 at 19:37
  • 1
    for that I'd probably do a raw sql query and select distinct year on the meta key directly from the meta table. – Milo Jun 30 '14 at 20:11
  • Thanks, Milo. I like this idea, too. Kind of like a GET variable. May play with this too -- another WP function I didn't know: get_query_var(). Nothing in WP_Query then that does basically SELECT DISTINCT, I take it? – slashbob Jul 1 '14 at 13:16
  • Unfortunately not possible with api functions. Another option would be to hook into post save / update / delete and maintain an array of unique years saved in an option. – Milo Jul 1 '14 at 14:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.