I have a problem where I’m trying to build a calendar plugin for a client. I’m having trouble getting a date based archive for the custom post type I’m using. I’m not too well versed in how the wordpress system for handling permalinks is set up on a low level, and I’ve hit a wall.
Background:
The plugin registers a custom post type, event
. Each event has a meta value field called kultkal_date
, holds a date in the form of 2011-09-28
. (Events are limited in the sense that each event’s date is unique as well, by validation on the save_post
action).
I’ve defined a custom permalink for the post type as /kalendarie/%kultkal_year%/%kultkal_month%/%kultkal_day%
, so the finished URL might look like /kalendarie/2011/09/28/my-slug
. I’ve added rewrite tags for the custom permalink using the init
action like so:
add_rewrite_tag('%kultkal_year%','([0-9]{4})');
add_rewrite_tag('%kultkal_month%','([0-9]{2})');
add_rewrite_tag('%kultkal_day%','([0-9]{2})');
I have a function to fix the permalink that runs on the post_type_link
filter:
function filter_post_type_link($link, $post){
if ($post->post_type != 'event')
return $link;
if ($date = get_post_meta($post->ID, 'kultkal_date', true)) {
$dates = explode('-', $date);
$year = $dates[0];
$month = $dates[1];
$day = $dates[2];
} else {
return $link;
}
$link = str_replace('%kultkal_year%', $year, $link);
$link = str_replace('%kultkal_month%', $month, $link);
$link = str_replace('%kultkal_day%', $day, $link);
return $link;
}
Viewing individual posts works. So does the archive page (located at the /kalendarium/
URL: has_archive
is set to kalendarium
when I register the post type).
The trouble starts when I want to filter the posts by year – for instance, /kalendarium/2011/
or /kalendarium/2011/09/28/
etc. I’ve found an answer on how to filter based on meta value for date on built-in posts here: Archive Listings Filtered by Date Values in a Custom Field/Post Meta? – but it doesn’t seem to work on custom post types. As soon as I add /year/month/day-parameters to test it, I get the archives for the built-in post type, not even a 404. (So far, I’ve only tried the first version in the answer above, with all the parameters (year/month/date), not the one with all the combinations + hook for posts_where
etc.
Here’s what the (broken) function I run on pre_get_posts
looks like:
function event_pre_get_posts($query) {
global $wp_the_query;
if ($query === $wp_the_query && $query->is_archive()) {
$qv = &$query->query_vars;
if (isset($qv['kultkal_year']) && isset($qv['kultkal_month']) && isset($qv['kultkal_day'])) {
$date = mktime(0,0,0,$qv['kultkal_month'],$qv['kultkal_day'],$qv['kultkal_year']);
$qv['meta_key'] = 'kultkal_date';
$qv['meta_value'] = date("Y-m-d", $date);
}
}
}
Any ideas on how to achieve the solution I’m looking for?
1 Answer
Like Bainternet said in comments, you’ll need to mess with add_query_var
as well as add_rewrite_rule
.
We usually do something similar to:
global $wp;
$wp->add_query_var( 'some_var' );
add_rewrite_rule( 'some/path/([^/]+)/?$', 'index.php?some_var=$matches[1]' );
See this WordPress Trac ticket, as well as documentation on add_query_var
and add_rewrite_rule