Flushing Rewrite Rules on All Sites in a Multisite Network

TL;DR: Loop through all sites and delete_option( 'rewrite_rules' ). Don’t call flush_rewrite_rules(). Full example.


Every once in awhile I’ll run into a situation where something will break permalinks on all the sites in a WordPress Multisite network, like a plugin network-activation gone wrong.

On a single site, it’s easy enough to fix by manually visiting Settings > Permalinks, which will flush and rebuild the rewrite rules, but if you’ve got more than a couple dozen sites in a network, then that’s no longer practical. You need a way to do it automatically for all of the sites.

The Typical Approach

Most of the attempts I’ve seen to do that will work similar to this:

/*
 * This is an example of a FLAWED way to do it, don't use it.
 * Use the better way described at the end of the post instead.
 */
function _wrong_flush_rewrite_rules_everywhere() {
    global $wp_rewrite;
    $sites = wp_get_sites( array( 'limit' => false ) );

    foreach ( $sites as $site_id ) {
        switch_to_blog( $site_id );
        $wp_rewrite->init();

        flush_rewrite_rules(); // Don't call this inside `switch_to_blog()`, that will breaks things.

        restore_current_blog();
    }
    $wp_rewrite->init();
}Code language: PHP (php)

That works for the basic rules, but it breaks down when you’ve created custom post types, because switch_to_blog() doesn’t reinitialize everything in the context of the new site; there are a few things that aren’t switched at all, and plugins are one of those things.

So, if the plugins that create the custom post types aren’t running on the site that initially calls the function, then they won’t be loaded when flush_rewrite_rules() gets called, and the rewrite rules for the CPTs will never be generated, or they’ll be generated for the wrong CPTs.

A Better Way

What’s really needed is a way to call flush_rewrite_rules() within the context of each fully-loaded site. The easiest way to do that is to simply delete the rewrite_rules option, because it will be re-generated automatically the next time the site loads.

$sites = get_sites( array(
	'number'  => 10000,
	'public'  => 1,
	'deleted' => 0,
) );

foreach ( $sites as $site ) {
	switch_to_blog( $site->id );
	delete_option( 'rewrite_rules' );
	restore_current_blog();
}Code language: PHP (php)

For the complete WP-CLI command, check out WordCamp.org’s WP-CLI command.


Updated 2020-07-02, to use the delete_option() technique, rather than making an HTTP request to each site.

2 thoughts on “Flushing Rewrite Rules on All Sites in a Multisite Network

Leave a Reply

Your email address will not be published. Required fields are marked *