TweetFor 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