Shiba

Adventures in WordPress

  • Home
  • Dog
  • Art
  • Contact
  • WordPress Articles
    • WP Plugins
    • WP Programming
    • WP Admin Panels
    • WP Theme Design
    • WP How-To
    • WP Theme Images
You are here: Home / WordPress Admin / Custom Post Type / How to Flush Permalink Rules with flush_rules()

How to Flush Permalink Rules with flush_rules()

by ShibaShake 11 Comments

If we want to create our own permalinks for custom post types, we can do so by using the WP_Rewrite WordPress object.

We can also create our own permalink rules from scratch, by using the same object.

One very important function while creating permalink rules is the $wp_rewrite->flush_rules() function. This function does the following –

  1. Deletes the ‘rewrite_rules’ option. This is where all the permalink rules for our blog are stored. When someone clicks on one of our blog pages, the parse_request function retrieves these rewrite rules and translates them into a query request.
  2. Regenerates new rewrite rules from scratch using the wp_rewrite_rules function. This function regenerates the rules and updates the ‘rewrite_rules’ option.
  3. It may also write to the .htaccess file if necessary.

When we add new permalink structures with register_post_type or add_permastruct, the structures only get added to the global $wp_rewrite object. It does not manifest as a rewrite rule until after we execute the $wp_rewrite->flush_rules() command.

That is why if we have a plugin that adds new permalink rules (including through register_post_type) we want to run $wp_rewrite->flush_rules() –

  • During the activation process to ensure that our new permalink structures show up in the blog rewrite rules.
  • During the deactivation process to remove our permalink structures from the blog rewrite rules.

function _activate() {
    	global $wp_rewrite;
	$wp_rewrite->add_rewrite_tag("%gallery%", '([^/]+)', "gallery=");
	$wp_rewrite->add_permastruct('gallery', $gallery_structure, false);    
	$wp_rewrite->flush_rules();	
}

function _deactivate() {
    	global $wp_rewrite;		
	$wp_rewrite->add_permastruct( 'gallery', '');
	$wp_rewrite->flush_rules();	
}

Note – flush_rules is also run by the WordPress system when we Save Changes in Settings >> Permalinks. Therefore, if our blog permalinks are not working properly, we can manually flush our permalink rules by going into Settings >> Permalinks and doing a save.

Flushing Permalink Rules in WordPress Multi-Site

In WordPress multi-site, we may need to flush rewrite rules for multiple blogs during network activation and deactivation.

However, there is a fly in the ointment. When we change blogs using set_blog_id, we are only changing the database context. The global $wp_rewrite object remains the same, i.e., it is the $wp_rewrite object of the original blog from where we executed the network activate or deactivate.

If we cycle through the blogs of a multi-site configuration and simply execute flush_rules, the wrong permalink rules from the non-updated $wp_rewrite object will be written into the ‘rewrite_rules’ option of each of the blogs. In effect, we would mess up the permalink rules of all our blogs except for the original activation/deactivation blog.

To properly flush permalink rules, we must limit our changes to the database and not access blog specific data stored within the $wp_rewrite object. Below, we do this by adding new permalink rules directly into the ‘rewrite_rules’ database option instead of using the flush_rules function.

function shiba_add_rewrite_rules($permastruct, $ep_mask=EP_NONE) {
	if (!$permastruct)return;
	global $wp_rewrite;
	$wp_rewrite->matches = 'matches'; // this is necessary to write the rules properly
	$new_rules = $wp_rewrite->generate_rewrite_rules($permastruct, $ep_mask);
	$rules = get_option('rewrite_rules');
	$rules = array_merge($new_rules, $rules);
	update_option('rewrite_rules', $rules);				
}

// remove all rewrite rules for a given permastruct
function shiba_remove_rewrite_rules($permastruct, $ep_mask=EP_NONE) {
	// replace all tags within permastruct
	if (!$permastruct)return;
	global $wp_rewrite;
	$wp_rewrite->matches = 'matches';
	$remove_rules = $wp_rewrite->generate_rewrite_rules($permastruct);
	$num_rules = count($remove_rules);
	// Get first rule
	$rule1 = reset($remove_rules); $key_rule1 = key($remove_rules);
		
	$rules = get_option('rewrite_rules');
	$i = $num_rules;
	foreach ($rules as $pretty_link => $query_link) {
		// find the first rule
		if (($pretty_link == $key_rule1) && ($query_link == $rule1)) { $i = 0; }
		if ($i < $num_rules) {
			// Delete next $num_rules
			unset($rules[$pretty_link]); $i++;
		}	
	}
	update_option('rewrite_rules', $rules);
}

Line 5 – Generate permalink rules for our plugin permalink structures. Even though we are using $wp_rewrite here, we are only using one of its functions. Most importantly, that function does not rely on any blog specific data or state stored in the $wp_rewrite object.
Line 6 – Get the ‘rewrite rules’ for the current blog. This is a database operation which does get updated with set_blog_id.
Line 7 – Merge our new permalink rules with the previous blog rules.
Line 8 – Update the ‘rewrite rules’ for the current blog.

In the shiba_remove_rewrite_rules function we use a similar process to remove the permalink rules added by our plugin.

We Are Done!

Now we can flush permalink rules in our regular and multi-site blogs!

Leave a Reply Cancel reply

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

Comments

  1. Ian Dunn says

    November 14, 2014 at 12:14 pm

    A simpler solution for Multisite is to re-initialize the rewrite rules before flushing them:

    https://gist.github.com/iandunn/c5a983d1a9d4b09d6d20

    Reply
    • ShibaShake says

      November 14, 2014 at 2:30 pm

      Thanks! Will have to try it out.

      Reply
  2. snowboard mommy says

    June 13, 2013 at 8:38 am

    Hi Shiba,

    Thanks for this information. How/where do we call the rewrite functions for multisite? Is it part of the activation routine, and where is the $permalink variable is being passed from?

    Thanks!

    Reply
    • snowboard mommy says

      June 13, 2013 at 8:39 am

      (actually it’s the $permastruct var that’s being passed, sorry about that)

      Reply
    • ShibaShake says

      June 13, 2013 at 11:43 am

      I pass in the permastruct variable myself. It is simply the permalink structure I want to set my object to, for example-
      “/gallery/%monthnum%/%category%/%gallery%”

      I call the flush functions during activation and deactivation.

      Reply
      • snowboard mommy says

        June 13, 2013 at 4:03 pm

        Great! That makes sense. Thank you for the speedy reply. You are pretty, awesome, you know, right? : )

      • snowboard mommy says

        June 13, 2013 at 6:04 pm

        I’m back … I was having trouble with WordPress adding yet another “/blog/” before my custom post type slug. I had to set the “with_front” property of the custom post type rewrite setting to “False” (and not put it in quotes!!! yeah, that was kinda stupid). Anyway, I just though I’d mention it in case anyone else crazy enough to use both Multisite and Custom Post Types comes along.

  3. Thomas says

    October 21, 2012 at 6:07 pm

    You can also add rewrite rules within the rewrite_rules_array filter directly. I wrote up this gem earlier today with the purpose of manually creating callback linked action pages. The usage would be something like:

    new action_page(‘cart’, array(‘items’));
    add_action(‘admin_post_nopriv_cart’, array($this, ‘display_cart’));
    add_action(‘admin_post_cart’, array($this, ‘display_cart’));

    <?php
    action_page::init();
    class action_page {
    
    	protected $action;
    	protected $vars;
    		
    	public static function init() {
    		add_action('template_redirect', array(__CLASS__, 'action_redirect'));	
    	}
    	
    	public function __construct( $action, $vars = array()) {
    	
    		$this->action = $action;
    		$this->vars = $vars;
    				
    		add_filter('query_vars', array($this, 'add_query_vars'));
    		add_filter('rewrite_rules_array', array($this, 'add_rewrite_rules'));
    		add_filter("{$action}_query_vars", array($this, 'import_vars'));
    	}
    	
    	public function add_query_vars( $vars ) {
    		$vars[] = 'action';
    		return array_merge($vars, $this->vars);
    	}
    	
    	public function add_rewrite_rules( $rules ) {
    		$regex = implode("/", $this->regex());
    		$regex = !empty($regex) ? "{$regex}/?$" : "?$";
    		$rules = array("{$this->action}/{$regex}" => $this->match()) + $rules;
    		return $rules;
    	}
    	
    	protected function regex() {
    		$m = array_fill_keys($this->vars, "([^/]+)");
    		return apply_filters("{$this->action}_regex", $m);
    	}
    	
    	protected function match() {
    		$size = sizeof($this->vars);
    		$match = "/index.php?action={$this->action}";
    		for($i = 0; $i < $size; $i++) { 
    			$m = $i + 1;
    			$match .= "&{$this->vars[$i]}=\$matches[{$m}]"; 
    		}
    		return apply_filters("{$this->action}_match", $match);
    	}
    	
    	public function import_vars( $vars = array() ) {
    		global $wp_query;
    		$vars += array_intersect_key($wp_query->query_vars, array_flip($this->vars));
    		return $vars;
    	}
    	
    	
    	public static function action_redirect() {
    		if($action = get_query_var('action')) {
    			$vars = apply_filters("{$action}_query_vars", array());
    			$action = wp_validate_auth_cookie() ? "admin_post_{$action}" : "admin_post_nopriv_{$action}";
    			do_action($action, $vars);
    		}
    	}
    }
    
    Reply
  4. staff says

    December 6, 2011 at 7:30 am

    Still a bit confuse here.. I am trying to add a new category using the WP API (multiple sites), the permalinks are not refreshing.
    So when a visitor goes to the page on the site it throws a 404 error. I have to manually go to to wp-admin -> settings -> permalinks and save to solve the problem.

    Here is what I am doing that is not working:

    add_action(‘init’, ‘flush_permalinks’);

    function flush_permalinks(){
    global $wp_rewrite;
    $wp_rewrite->set_permalink_structure(‘/%postname%/’);
    //$wp_rewrite->flush_rules();
    // flush_rewrite_rules();
    }

    Could you find my error? Thanks.

    Reply
  5. rashid says

    July 16, 2011 at 1:42 am

    what the $gallery_structure, in $wp_rewrite->add_permastruct(‘gallery’, $gallery_structure, false); contains, (I understand its a struct based on google search). BUt its initialized or assigned a value?

    Reply
    • ShibaShake says

      July 18, 2011 at 12:48 pm

      $gallery_structure contains a regular WP permalink structure, e.g. /galleries/%year%/%monthnum%/%gallery%.
      http://shibashake.com/wordpress-theme/custom-post-type-permalinks-part-2

      Reply

Recent Posts

  • Screenshot of an example article in code view of a modified Gutenberg editor.How to Harness the Power of WordPress Gutenberg Blocks and Combine It with Legacy Free-Form Text
  • Screenshot of the Success, WordPress has been installed page.Migrating Your WordPress Website to Amazon EC2 (AWS)
  • Screenshot of WinSCP for creating a SFTP configuration.How to Set-Up SFTP on Amazon EC2 (AWS)
  • WordPress Gutenberg code view screenshot of this article.How to Prevent Gutenberg Autop from Messing Up Your Code, Shortcodes, and Scripts
  • Screenshot of the Success, WordPress has been installed page.How to Create a WordPress Website on Amazon EC2 (AWS)

Recent Comments

  • Screenshot of an example article in code view of a modified Gutenberg editor.How to Harness the Power of WordPress Gutenberg Blocks and Combine It with Legacy Free-Form Text (1)
    • tom
      - hi,my experience was like the same, but for me as theme developer the "lazy blocks"(https://wordpress.org/plugins/lazy-blocks/) ...
  • WordPress Custom Taxonomy Input Panels (106)
    • Phil T
      - This is unnecessarily confusing. Why declare a variable with the same name as your taxonomy? Why did you choose a taxonomy ...
  • Create Pop-up Windows in Your WordPress Blog with Thickbox (57)
    • Jim Camomile
      - I have used this tutorial several times and it is one of the few simple and effective ways to add popups with dynamic content, ...
  • How to Add Admin Columns in WordPress (7)
    • Andy Globe
      - Hi Friends, I am facing two problem in WordPress admin1. Load custom CSS for wp-admin on user-role base (editor) 2. ...
  • Example blog front-page using excerpts and the Shiba Theme.Optimize Your WordPress Plugins with Tags (5)
    • DF
      - thanks, i went the other way and added a filter if pages I wanted.

Copyright © 2023 · Genesis Skins by ShibaShake · Terms of Service · Privacy Policy ·