For a plugin I was creating I needed Yearly and Monthly archives with my own slug. Even after setting the rewrite rules it was not working. After much debugging and several hours later I finally figured it out. I’ll explain how you could do the same bellow.
Spoiler Alert: For the impatient, it was as simple as removing the old rules that are not setting the post type before adding the new rules :)
I’m going to assume that you have already familiar with Custom Post types. If you are not read http://codex.wordpress.org/Post_Types and then come back. Most important are Step 5 and Step 6. Other steps are typical for any plugin or theme using custom post types.
Step 1: Register the post type
Read more about registering custom post types at
register_post_type( ‘my_class’,
array(
‘public’ => true,
…
‘has_archive’ => true,
)
);
Step 2: Add rewrite tags and permalink structure
$event_structure = ‘/events/%year%/%monthnum%/%my_class%’;
$wp_rewrite->add_rewrite_tag(“%my_class%”, ‘(.+?)’, “my_class=”);
$wp_rewrite->add_permastruct(‘my_class’, $event_structure, false);
Step 3: Add post_type_link and rewrite_rules_array filters
add_filter(‘rewrite_rules_array’, ‘my_class_add_rewrite_rules’);
add_filter(‘post_type_link’, ‘my_class_post_type_link’, 10, 3);
Step 4: Return a proper permalink
function my_class_post_type_link($permalink, $post_id, $leavename) {
$post = get_post($post_id);
$rewritecode = array( ‘%my_class%’, ‘%year%’, ‘%monthnum%’ );
if ($post->post_type == ‘my_class’ && ‘’ != $permalink) {
$ptype = get_post_type_object($post->post_type);
$start = time(); $end = time();
$meta = get_post_custom($post->ID); // This is where I store when the class starts if (isset($meta[“my_class_start”]) && isset($meta[“my_class_start”])) { $start = strtotime($meta[“my_class_start”]); }
$year = date(‘Y’, $start); $month = date(‘m’, $end);
$rewritereplace = array( ($post->post_name == “”)?$post->id:$post->post_name, $year, $month, ); $permalink = str_replace($rewritecode, $rewritereplace, $permalink); } else { // if they’re not using the fancy permalink option }
return $permalink; } Step 5: Add rewrite rules function my_class_add_rewrite_rules($rules){ $new_rules = array();
// This is the important bit, unsetting the rules unset($rules[‘classes/({4})/({1,2})/?$’]); unset($rules[‘classes/({4})/?$’]);
$new_rules[‘classes/({4})/?$’] = ‘index.php?year=$matches&post_type=incsub_event’; $new_rules[‘classes/({4})/({1,2})/?$’] = ‘index.php?year=$matches&monthnum=$matches&post_type=incsub_event’; $new_rules[‘classes/({4})/({2})/(.+?)/?$’] = ‘index.php?year=$matches&monthnum=$matches&incsub_event=$matches’;
return array_merge($new_rules, $rules); } Step 6: Don’t forget to flush add_action(‘option_rewrite_rules’, ‘my_class_check_rewrite_rules’); function my_class_check_rewrite_rules($value) { global $wp_rewrite;
//prevent an infinite loop if ( ! post_type_exists( ‘incsub_event’ ) ) return;
if (!is_array($value)) $value = array();
$array_key = ‘events/({4})/?$’; if ( !array_key_exists($array_key, $value) ) { $wp_rewrite->flush_rules(); } $array_key = ‘events/({4})/({1,2})/?$’; if ( !array_key_exists($array_key, $value) ) { $wp_rewrite->flush_rules(); } $array_key = ‘events/({4})/({1,2})/(.+?)/?$’; if ( !array_key_exists($array_key, $value) ) { $wp_rewrite->flush_rules(); } } That’s it. Most important steps are Step 5 and Step 6