Changing the meta_query of the main query based on custom query_vars and using pre_get_posts

I’ve registered custom rewrite rules and query_vars to use for displaying a list of events based on ISO date format. For example when a user requests the URL, http://site.com/by-date/2013-04-04/, my query_var is the date portion and I’d like to display a list of events who’s meta_key of _event_scheduled_date equals the ISO date value in the query_var.

Whenever I try the following code to modify the $query in pre_get_posts WordPress initiates a 404 and no posts are queried. I’ve been able to use pre_get_posts to manipulate other taxonomy listings and archive pages, but have yet been able to get it to work correctly with the custom query_var I’ve created.

function rewrite_rule_by_date() {
    add_rewrite_rule('(by-date)/([0-9]{4}-[0-9]{2}-[0-9]{2})$', 'index.php?pagename=$matches[1]&event_date=$matches[2]', 'top');
}
add_action( 'init', 'rewrite_rule_by_date' );

function query_var_by_date() {
    add_rewrite_tag( '%event_date%', '([0-9]{4}-[0-9]{2}-[0-9]{2})');
}
add_action( 'init', 'query_var_by_date' );

function custom_event_query( $query ) {
    if (  is_page( 'by-date' ) && get_query_var( 'event_date' ) && is_main_query() ) {
        $query->set( 'post_type', 'event' );
        $query->set( 'post_status', 'publish' );
        $query->set( 'meta_key', '_event_scheduled_date' );
        $query->set( 'orderby', 'meta_value' );
        $query->set( 'order', 'ASC' );
        $query->set( 'post_per_page', -1 );

        $meta_query = array(
            array(
                'key' => '_event_scheduled_date',
                'value' => get_query_var( 'event_date' ),
                'type' => 'DATE',
                'compare' => '='
            )
        );

        $query->set( 'meta_query', $meta_query );
    }

    return $query;
}
add_filter( 'pre_get_posts', 'custom_event_query' );

Related posts

Leave a Reply

1 comment

  1. Instead of trying to display all the matching events on your by-date page, you could try to display through ?post_type=event like this:

    function rewrite_rule_by_date() {
        add_rewrite_rule('by-date/([0-9]{4}-[0-9]{2}-[0-9]{2})$', 'index.php?post_type=event&event_date=$matches[1]', 'top');
    }
    add_action( 'init', 'rewrite_rule_by_date' );
    
    function query_var_by_date() {
        add_rewrite_tag( '%event_date%', '([0-9]{4}-[0-9]{2}-[0-9]{2})');
    }
    add_action( 'init', 'query_var_by_date' );
    
    function custom_event_query( $query ) {
        if ( get_query_var( 'event_date' ) && is_main_query() ) {
            $query->set( 'post_type', 'event' );
            $query->set( 'post_status', 'publish' );
            $query->set( 'meta_key', '_event_scheduled_date' );
            $query->set( 'orderby', 'meta_value' );
            $query->set( 'order', 'ASC' );
            $query->set( 'post_per_page', -1 );
    
            $meta_query = array(
                array(
                    'key' => '_event_scheduled_date',
                    'value' => get_query_var( 'event_date' ),
                    'type' => 'DATE',
                    'compare' => '='
                )
            );
    
            $query->set( 'meta_query', $meta_query );
        }
    
        return $query;
    }
    add_filter( 'pre_get_posts', 'custom_event_query' );
    

    This works on my WordPress 3.5.1 install with the default Twenty Twelve theme, with url like this one:

    http://example.com/by-date/2013-04-04/