I'm trying to add a rewrite rule that will point to a file inside a plugin. This can be added in the plugin, theme or .htaccess file.

My current code from inside the theme's function.php looks like:

// Add Custom Rewrite Rules
function custom_rewrite_basic() {
  add_rewrite_rule('^leaf/([0-9]+)/?', 'wp-content/plugins/my-plugin/index.php?leaf=$matches[1]', 'top');
add_action('init', 'custom_rewrite_basic');

Note: I'm trying to do this on a Multisite network for a path based subdomain.

3 Answers 3


(Revised answer)

  1. Don't call flush_rewrite_rules() on init. Instead, if you want to do it programmatically, call the function from your plugin or theme activation function. If you're not doing it programmatically, you could simply visit the Permalink Settings page (Settings → Permalinks on the WordPress back-end).

  2. WordPress does support adding a rewrite rule that doesn't correspond to index.php, i.e. the second parameter passed to add_rewrite_rule() does not necessarily need to start with index.php — and when it doesn't, WordPress will (attempt to automatically) write the rewrite rule to the .htaccess file.

    However, your code should look like so, where the first parameter should not start with a caret (^), and the second parameter should use $1 instead of $matches[1] ($matches[1] is only for rewrite rule which corresponds to the WordPress's index.php):

    add_rewrite_rule('leaf/([0-9]+)/?', 'wp-content/plugins/my-plugin/index.php?leaf=$1', 'top');

    And if your .htaccess file is writable, then after the rewrite rules are flushed, you should see something like this in the file:

    RewriteRule ^index\.php$ - [L]
    RewriteRule ^leaf/([0-9]+)/? /wp-content/plugins/my-plugin/index.php?leaf=$1 [QSA,L]

    The "leaf" value would be available in the (superglobal) $_GET and within your index.php file, you could do:

    <p><?php echo $_GET['leaf']; ?></p>
  3. Instead of using add_rewrite_rule(), you could also use the parse_request action hook to handle the URL/request and then load the custom plugin file. Working example:

    add_action( 'parse_request', function( $wp ){
        if ( preg_match( '#^leaf/([0-9]+)/?#', $wp->request, $matches ) ) {
            $leaf = $matches[1];
            // Load your file - make sure the path is correct.
            include_once plugin_dir_path( __FILE__ ) . 'index.php';
            exit; // and exit
    } );

    So as you can see, the "leaf" value is saved to the $leaf variable. So within your index.php file, you could do:

    <p><?php echo $leaf; ?></p>

    With the parse_request hook, you don't need to worry about your .htaccess file not being writable; however, the $_GET['leaf'] wouldn't be available, which explains why we use the $leaf variable. :)

    But yes, although I don't recommend it, you could do $_GET['leaf'] = $matches[1]; and the $_GET['leaf'] would be available in your script. ;)


@Sally CJ,

Thank you very much for your reply. You gave me a great direction. Don't have enough reputation yet, but I would definitely Upvote your answer.

My current code (inside the child theme) looks like this:


    add_action( 'parse_request', function( $wp ){
      // The regex can be changed depending on your needs
      if ( preg_match( '#^leaf/(.*)/?#', $wp->request, $matches ) ) {
        // Get the Leaf Number
        $leaf = $matches[1]; 

        // Define it for my-plugin's index.php
        $_GET['leaf'] = urldecode($leaf);

        // Load your file - make sure the path is correct.
        include_once WP_CONTENT_DIR . '/plugins/my-plugin/index.php';
        exit; // and exit

You can test your regex here: https://www.regextester.com/96691

  • Hey Theo. I'm glad my answer helped you and I've revised it - I hope it is more helpful now. :) And actually, I +1 your answer, so you could upvote my answer.. or accept it. ;) I mean, you should accept your answer or mine so that people know the question has an accepted solution. =) Cheers!
    – Sally CJ
    Commented Apr 30, 2019 at 15:02
  • Thank you very much Sally. You're a real lady! I've accepted your answer of course. Commented May 1, 2019 at 22:08

As @SallyCJ mentioned, your .htaccess file must be writable. For this, use the default file permissions 644.

But in my case, it wasn't enough. Using flush_rewrite_rules didn't help too.

WP wrote the rule into the .htaccess file only after I had done

WP Admin -> Settings -> Permalinks -> Save

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.