How To Consistently Enforce Rewrite Rule in Plugin Development

Let’s say I create a customer support plugin that hijacks the /support part of the URL and redirects it to an MVC framework in my app folder of my plugin folder, like so:

RewriteRule ^support(.*)$ wp-content/plugins/csupport/app/$1 [L]

I know that I can do this in a blog’s .htaccess right before the RewriteBase line, but not everyone has .htaccess turned on unless they add a custom permalink. I found a technique to force custom permalinks, but that’s brute force and not recommended.

Read More

What is the recommended way for plugin developers to add a rewrite rule so that they can capture a subdirectory call like /support and redirect it to somewhere else?

Related posts

Leave a Reply

1 comment

  1. Here’s a solution. See comments at the end…

    // I am a functions.php file of a plugin called "sample" -- implement me slightly differently for a theme.
    // Note this code requires WP 3.0 or greater.
    class SAMPLE {
    
    public static function activatePlugin() {
      self::rewriteURL();
      flush_rewrite_rules();
      if (get_option('permalink_structure') == '') {
        self::updatePermalinks();
      }
      // add your other plugin activation code here
    }
    
    public static function deactivatePlugin(){
      flush_rewrite_rules();
      // add your other plugin deactivation code here
    }
    
    public static function drawAdminMenu(){
    $s = <<<EOD
    <div class="wrap">
      <div id="icon-options-general" class="icon32"><br></div>
      <h2>Sample Panel</h2>
      <!-- kludge to fix permalinks issue -- this ties into the plugin activation code -->
      <iframe style="position:absolute;top:-5000px" src="<?= admin_url() ?>options-permalink.php"></iframe>
      <p>Your options go here.</p>
    </div><!-- .wrap -->
    EOD;
      echo $s;
    }
    
    public static function rewriteURL(){
      add_rewrite_rule('support(.*)$','wp-content/plugins/sample/app/$1','top');
      // this edits your .htaccess file and adds: 
      // RewriteRule ^support(.*)$ /wp-content/plugins/sample/app/$1 [QSA,L]
    }
    
    public static function updatePermalinks(){
    global $wp_rewrite;
      $wp_rewrite->set_permalink_structure('/%postname%/');
      $wp_rewrite->flush_rules();
      // Note that the rest of this runs via the registration form via hidden IFRAME
      // in order to create the .htaccess file. It's a kludge -- but she works well!
    }
    
    } // end SAMPLE class
    
    register_activation_hook(__FILE__,'SAMPLE::activatePlugin');
    register_deactivation_hook(__FILE__,'SAMPLE::deactivatePlugin');
    add_action('admin_menu', 'SAMPLE::drawAdminMenu');
    add_action('init','SAMPLE::rewriteURL');
    
    1. You should never run flush_rewrite_rules() all the time. Andrew Nacin, one of the core devs for WordPress, advises on more than one occasion that this must be done from a plugin or theme’s activation and deactivation callbacks. (Themes don’t have these callbacks, but there are examples on the web that kludge theme callbacks for activation/deactivation.) Andrew says it degrades performance, if otherwise. This is obvious because it could potentially rewrite the .htaccess file every time a page load occurs.

    2. I use static class methods instead of global functions in the namespace. It’s less dangerous and more tidy.

    3. Note the sequence in the activatePlugin() — that’s important. You should rewrite the URL, flush the rules, and, if custom permalinks are not turned on, turn them on.

    4. Custom permalinks are crucial. Without them you don’t get the .htaccess file and thus no rewrite rules.

    5. Note that we don’t blindly brute-force custom permalinks on someone. We see if they have these enabled. If not, we turn them on and use a common kind of permalink often used with SEO.

    6. Note my updatePermalinks() function has a problem. It’s something I detected in all versions of WordPress. I found that the .htaccess file was not being created unless one clicked to see the Permalinks options panel. I have no idea why WordPress has this bug, but it does. So, as you can see with the IFRAME below, I came up with a decent workaround. That IFRAME will ensure the .htaccess file gets created if it was not — as long as that call to updatePermalinks() was done previously.

    7. The WordPress Codex seemed to indicate that I would have all kinds of problems with query parameters in my rewritten URL if I didn’t implement add_query_vars(). However, I found that not to be the case at all. I was able to hijack /support and redirect it to an MVC framework inside my plugin, and then load that framework up with fancy URLs like /support/tickets/1, as well as use query parameters on the end like /support/tickets/1?q=open&s=sample+keywords.

    8. Note that:

    add_rewrite_rule(‘support(.*)$’,’wp-content/plugins/sample/app/$1′,’top’);

    …equates to:

    RewriteRule ^support(.*)$ /wp-content/plugins/sample/app/$1 [QSA,L]

    …in the .htaccess file, which is exactly what I needed.

    As for why the docs are so confusing and misleading on the topic of RewriteRules, I have no idea.

    EDIT1: Changed site_url() to admin_url() in the IFRAME call.