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"][0])) {
$start = strtotime($meta["my_class_start"][0]);
}
$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/([0-9]{4})/([0-9]{1,2})/?$']);
unset($rules['classes/([0-9]{4})/?$']);
$new_rules['classes/([0-9]{4})/?$'] = 'index.php?year=$matches[1]&post_type=incsub_event';
$new_rules['classes/([0-9]{4})/([0-9]{1,2})/?$'] = 'index.php?year=$matches[1]&monthnum=$matches[2]&post_type=incsub_event';
$new_rules['classes/([0-9]{4})/([0-9]{2})/(.+?)/?$'] = 'index.php?year=$matches[1]&monthnum=$matches[2]&incsub_event=$matches[3]';
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/([0-9]{4})/?$';
if ( !array_key_exists($array_key, $value) ) {
$wp_rewrite->flush_rules();
}
$array_key = 'events/([0-9]{4})/([0-9]{1,2})/?$';
if ( !array_key_exists($array_key, $value) ) {
$wp_rewrite->flush_rules();
}
$array_key = 'events/([0-9]{4})/([0-9]{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