Custom plugin route in WordPress

You need to do three important things:

  1. Create a custom rewrite rule to turn parts of the URI into values passed to index.php.
  2. Add myroute and myargument to WordPress’s query variables whitelist, so that WordPress doesn’t just ignore them when they appear in a query string.
  3. Flush the rewrite rules.

Firstly, I’m going to recommend that instead of http://www.example.org/myroute/myargument, you settle on some kind of special prefix or suffix to denote when the URI should be considered one of these special ‘routes’. For the the sake of this example, I’ve chosen the prefix api, so that it would be http://www.example.org/api/myroute/myargument. I chose api because when I did something RESTful, like what you seem to be working on, it was for an API.

The Code

add_filter( 'rewrite_rules_array', 'my_insert_rewrite_rules' );
add_filter( 'query_vars', 'my_insert_query_vars' );
add_action( 'wp_loaded', 'my_flush_rules' );

// flush_rules() if our rules are not yet included
function my_flush_rules() {
    $rules = get_option( 'rewrite_rules' );

    if ( ! isset( $rules['api/(.*?)/(.+?)'] ) ) {
        global $wp_rewrite;
        $wp_rewrite->flush_rules();
    }
}

// Adding a new rule
function my_insert_rewrite_rules( $rules ) {
    $newrules = array();
    $newrules['api/(.*?)/(.+?)'] = 'index.php?myroute=$matches[1]&myargument=$matches[2]';
    return $newrules + $rules;
}

// Adding the id var so that WP recognizes it
function my_insert_query_vars( $vars ) {
    array_push( $vars, 'myroute', 'myargument' );
    return $vars;
}

Quick Breakdown

It’s all fairly straight forward. The regex pattern is added to a list of all the rewrite rules in WordPress, and your custom pattern is at the top of the list. When the pattern is matched, WordPress will stop looking through the list of rewrite rules, and use the regex’s captured values in place of the references ($matches[1] and $matches[2]) in the query string passed to index.php.

Adding the query variables myroute and myargument to the whitelist just makes WordPress pay attention to them rather than discarding them.

Alternative way of ‘namespacing’ your custom route

If you wanted to avoid using /api/ as a prefix, you could use a query string variable/field instead. To do something like that, you would change the regex to something like (.*?)/(.+?)\\?api=1 and then add api as an additional parameter to the array_push() call made in my_insert_query_vars().

That would change the custom route so that it triggers any time api=1 is the first element of the query string, e.g. it would trigger for http://example.com/anytext/anytext?api=1.

Ignore the use of the term ‘namespacing’ – just used it for brevity.

If you don’t ‘namespace’ with either a prefix or a suffix, you will end up with colliding URI patterns. This is because WordPress will have no way to distinguish your custom pattern from one intended to be a post or page. How would WordPress know that myroute is not a taxonomy, term, or a parent page?

Hope this helps.

Leave a Comment