函数文档

flush_rewrite_rules()

💡 云策文档标注

概述

flush_rewrite_rules() 函数用于移除并重新创建 WordPress 的重写规则,常用于自定义文章类型或插件激活时更新永久链接。它支持软刷新(仅更新选项)和硬刷新(更新 .htaccess),但操作开销较大,应谨慎使用。

关键要点

  • 函数参数 $hard 控制刷新类型:true(默认,硬刷新)更新 .htaccess,false(软刷新)仅更新 rewrite_rules 选项。
  • 适用于自定义文章类型注册后自动刷新规则,避免手动操作,但因其性能消耗高,建议仅在必要时调用。
  • 内部调用 WP_Rewrite::flush_rules() 实现功能,自 WordPress 3.0.0 版本引入。
  • 相关用途包括 update_home_siteurl()、populate_network() 等函数在特定场景下触发规则刷新。

代码示例

// 示例:在插件激活时延迟刷新规则,避免过早调用
register_activation_hook( __FILE__, 'plugin_activation' );
function plugin_activation() {
    update_option('plugin_permalinks_flushed', 0);
}

add_action( 'init', 'custom_query_vars' );
function custom_query_vars() {
    global $wp;
    $wp->add_query_var( 'newfeed' );
    add_rewrite_rule( '^newfeed/([^/]*)/?', 'index.php?newfeed=$matches[1]', 'top' );
    if( !get_option('plugin_permalinks_flushed') ) {
        flush_rewrite_rules(false);
        update_option('plugin_permalinks_flushed', 1);
    }
}

注意事项

  • 避免在 save_post 钩子中直接调用 flush_rewrite_rules(),可能无效或导致问题。
  • 在插件或主题开发中,确保刷新规则在自定义文章类型或重写规则注册之后执行,否则可能生成不完整的规则。
  • 替代方案:使用 delete_option( 'rewrite_rules' ) 强制 WordPress 在适当时机重新生成规则,避免 flush_rewrite_rules() 的时机问题。
  • 生产环境中应限制刷新操作,避免在前端调用,建议通过 is_admin() 检查确保仅在管理后台执行。

📄 原文内容

Removes rewrite rules and then recreate rewrite rules.

Parameters

$hardbooloptional
Whether to update .htaccess (hard flush) or just update rewrite_rules option (soft flush). Default is true (hard).

Default:true

More Information

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.

Source

function flush_rewrite_rules( $hard = true ) {
	global $wp_rewrite;

	if ( is_callable( array( $wp_rewrite, 'flush_rules' ) ) ) {
		$wp_rewrite->flush_rules( $hard );
	}
}

Changelog

Version Description
3.0.0 Introduced.

User Contributed Notes

  1. Skip to note 8 content

    register_activation_hook( __FILE__, 'plugin_activation' );
    function plugin_activation() {
    	update_option('plugin_permalinks_flushed', 0);
    }
    
    add_action( 'init', 'custom_query_vars' );
    function custom_query_vars() {
    	global $wp;
    
    	$wp->add_query_var( 'newfeed' );
    	add_rewrite_rule( '^newfeed/([^/]*)/?', 'index.php?newfeed=$matches[1]', 'top' );
    
    	if( !get_option('plugin_permalinks_flushed') ) {
    
    		flush_rewrite_rules(false);
    		update_option('plugin_permalinks_flushed', 1);
    
    	}
    }

  2. Skip to note 9 content

    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…

  3. Skip to note 10 content

    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);

  4. Skip to note 12 content

    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 );
    	}
    
    }

  5. Skip to note 13 content

    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();
    }

  6. Skip to note 14 content

    // flush rules and serve new rules instantly without page refresh
    add_action('init', function() {
        flush_rewrite_rules();
    });
    // Or, hook into wp tag, flush rules and do an internal refresh
    add_action('wp', function() {
        if( "1" !== get_option("my_rules_have_been_flushed") ) {
            flush_rewrite_rules();
            update_option('my_rules_have_been_flushed', '1');
            // now, redirect the request.
            wp_redirect( $_SERVER['REQUEST_URI'] );
            exit;
        }
    });