This function is useful when used with custom post types as it allows for automatic flushing of the WordPress rewrite rules (usually needs to be done manually for new custom post types). However, this is an expensive operation so it should only be used when necessary.
This is brilliant! I had to write a rewrite rule where I had to use wc_get_page_id( '' ), and then run a flush_rewrite_rules, but at the point register_activation_hook() is called, WC isn’t even initialized, so I used your code to run the flush_rewrite_rules delayed enough and still only call it once after my plugin’s installation! Thank you very much for the idea!
It doesn’t seems to work for me. I don’t know if someting changed and now you cannot call flush on the init but I use your code and it doesn’t updates while using the button on admin area it does :S
To make it easier to understand about important part. The flush have to be done **after** add rewrite rule. I have just added flush to activate plugin but it didn’t work until I read this code. Thanks.
A relatively simple way to flush rewrite rules on activation and deactivation hooks is not using flush_rewrite_rules() at all. Instead just clear the rewrite_rules option to force WordPress to recreate them at the right time.
Example:
register_activation_hook( __FILE__, 'wpdocs_wpdev_activate' );
function wpdocs_wpdev_activate() {
// force rewrite rules to be recreated at the right time
delete_option( 'rewrite_rules' );
}
This avoids having to do complicated stuff like registering your custom post types in the activation hook or throwing and catching dedicated db option or transients as suggested in other notes…
Not sure why this contribution gets down voted but maybe it needs a bit more explanation… There is one big problem with flush_rewrite_rules() when not called at the right time: it not only removes the old rewrite rules but also creates new ones, based on the (custom) post types and rewrite rules filters registered registered at that point in time. So if your plugin or theme calls flush_rewrite_rules() on an awkward moment where not everything is in place, wrong or incomplete rewrite rules will be generated. For example: when updating a plugin setting that warrants new rewrite rules, calling flush_rewrite_rules() from withing the option sanitization hook will likely cause problems. Or when calling it on a deactivation hook, without first removing your custom post type, flush_rewrite_rules() will likely not have the desired effect. Others like @nsrw0rk (up voted for good reason) have suggested an elegant solution: save an option to the database that will trigger flush_rewrite_rules() on the next init. But this will not always work, like in case of the deactivation hook (where the next init will be without your plugin) or in Multisite mode where rewrite rules can’t be flushed during switch to blog. So that is why I suggested the less elegant, but effective work-around: delete_option( 'rewrite_rules' ) :)
This is THE ONLY solution. …and works like a charm, thank you! When building a plugin with classes (like the one in the boilerplate) the activation class runs before the main class that contains the registration of the custom post types. Hence if you just flush_rewrite_rules() you rewrite the rules without your custom post types. You need to rewrite them AFTER having registered them, and you also want to rewrite them only once after activation, not every single time. So you just delete them upon activation, then your main code registers them, then wordpress notice the rules are empty and tries to rebuild them but your post have already been registered. Smooth, elegant, effective!
If you want to flush rules while updating posts based on post type:
function wpdoc_flush_rules_on_save_posts( $post_id ) {
// Check the correct post type.
// Example to check, if the post type isn't 'post' then don't flush, just return.
if ( ! empty( $_POST['post_type'] && $_POST['post_type'] != 'post' ) {
return;
}
flush_rewrite_rules();
}
add_action( 'save_post', 'wpdoc_flush_rules_on_save_posts', 20, 2);
flush_rewrite_rules() does not work on “save_post”, and instead of doing $_POST.. you can pass as a 2nd parameter like ($post_id, $post) and get $post->post_type
If you’re developing a theme, while building it you can use this snippet of code that will flush rewrite rules when the file containing it is changed, or every 48 hours:
// do not use on live/production servers
add_action( 'init','maybe_rewrite_rules' );
/**
* Flush rewrite rules if the current file has changed and at least every 48 hours.
*/
function maybe_rewrite_rules() {
if ( ! is_admin() ) {
return;
}
$ver = filemtime( __FILE__ ); // Get the file time for this file as the version number
$defaults = array( 'version' => 0, 'time' => time() );
$r = wp_parse_args( get_option( __CLASS__ . '_flush', array() ), $defaults );
if ( $r['version'] != $ver || $r['time'] + 172800 < time() ) { // Flush if ver changes or if 48hrs has passed.
flush_rewrite_rules();
// trace( 'flushed' );
$args = array( 'version' => $ver, 'time' => time() );
if ( ! update_option( __CLASS__ . '_flush', $args ) )
add_option( __CLASS__ . '_flush', $args );
}
}
“Flushing” the rewrite rules should only happen in wp-admin, see https://core.trac.wordpress.org/ticket/44142. It is possible to do from the front-end while developing a theme or a plugin, but is a pretty bad idea if ever done in production.In that terms I’d add: if ( ! is_admin() ) { return; } at the top of the above function.
This is how you would flush rewrite rules when a plugin is activated or deactivated:
register_deactivation_hook( __FILE__, 'flush_rewrite_rules' );
register_activation_hook( __FILE__, 'wpdocs_flush_rewrites' );
/**
* Flush rewrite rules on activation
*/
function wpdocs_flush_rewrites() {
// call your CPT registration function here (it should also be hooked into 'init')
wpdocs_custom_post_types_registration();
flush_rewrite_rules();
}
wc_get_page_id( '' )
, and then run a flush_rewrite_rules, but at the point register_activation_hook() is called, WC isn’t even initialized, so I used your code to run the flush_rewrite_rules delayed enough and still only call it once after my plugin’s installation! Thank you very much for the idea!A relatively simple way to flush rewrite rules on activation and deactivation hooks is not using flush_rewrite_rules() at all. Instead just clear the rewrite_rules option to force WordPress to recreate them at the right time.
Example:
This avoids having to do complicated stuff like registering your custom post types in the activation hook or throwing and catching dedicated db option or transients as suggested in other notes…
flush_rewrite_rules()
when not called at the right time: it not only removes the old rewrite rules but also creates new ones, based on the (custom) post types and rewrite rules filters registered registered at that point in time. So if your plugin or theme callsflush_rewrite_rules()
on an awkward moment where not everything is in place, wrong or incomplete rewrite rules will be generated. For example: when updating a plugin setting that warrants new rewrite rules, callingflush_rewrite_rules()
from withing the option sanitization hook will likely cause problems. Or when calling it on a deactivation hook, without first removing your custom post type,flush_rewrite_rules()
will likely not have the desired effect. Others like @nsrw0rk (up voted for good reason) have suggested an elegant solution: save an option to the database that will triggerflush_rewrite_rules()
on the next init. But this will not always work, like in case of the deactivation hook (where the next init will be without your plugin) or in Multisite mode where rewrite rules can’t be flushed during switch to blog. So that is why I suggested the less elegant, but effective work-around:delete_option( 'rewrite_rules' )
:)If you want to flush rules while updating posts based on post type:
This is how you would flush rules on theme activation:
If you’re developing a theme, while building it you can use this snippet of code that will flush rewrite rules when the file containing it is changed, or every 48 hours:
if ( ! is_admin() ) { return; }
at the top of the above function.This is how you would flush rewrite rules when a plugin is activated or deactivated: