Add Rewrite Rule to point to a file on the server

(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:

    <?php
    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. 😉