As stated on WordPress Codex: Flushing the rewrite rules is an expensive operation. So it’s best to refresh your wp_rewrite rules by not using the init hook. Austin Passy chooses to Flush your rewrite rules on plugin/theme activation on checking $_GET parameters. I’ve tried it two different ways. The first option seemed to work for a while, but my added rule disappeared somehow and began sending requests to a 404 page so I started using the other option.
Option 1:
$custom_permalink_rules_exist = get_option( $this->permalink_rule_option_name );
if( $custom_permalink_rules_exist != "1") {
add_action( 'init', 'flush_rewrite_rules');
add_action( 'generate_rewrite_rules', array( &$this, 'add_rewrite_rules' ) );
update_option( $this->permalink_rule_option_name, '1');
}
Option 2:
/**
* Flushing the wp_rewrite rules is an expensive proceedure so check
* if the rules exist
*
* @global object $wp_rewrite
*/
function verify_rewrite_rule_exists() {
global $wp_rewrite;
if( empty($this->rewrite_rule_key) ||
!array_key_exists($this->rewrite_rule_key, $wp_rewrite->rules ) ) {
add_action( 'generate_rewrite_rules', array( &$this, 'add_rewrite_rules' ) );
}
}
function add_rewrite_rules( $wp_rewrite ) {
global $wp_rewrite;
$this->rewrite_rule_key = "^{$this->post_type_slug}/([^/]*)/([^/]*)/([^/]*)$";
// match a custom post_type with a parent and child taxonomy
$new_rules = array( "^{$this->post_type_slug}/([^/]*)/([^/]*)/([^/]*)$" => "index.php?{$this->post_type_slug}=" . $wp_rewrite->preg_index(3) );
// match a custom post_type with only one taxonomy; however, will break the archive page for two taxonomies
//$new_rules = array( "^{$this->post_type_slug}/([^/]*)/([^/]*)$" => "index.php?{$this->post_type_slug}=" . $wp_rewrite->preg_index(2) );
// Add the new rewrite rule into the top of the global rules array
$wp_rewrite->rules = $new_rules + $wp_rewrite->rules;
flush_rewrite_rules();
return $wp_rewrite->rules;
}