register_rest_route regex option for base64 or alternate

What I tested

WordPress Version: 4.9.5

PHP Version: 7.1.7/7.1.4/7.2.0/7.0.3/5.6.20/5.5.38/5.4.45

Web Server: Nginx 1.10.1/Apache 2.4.10

Environment/Host: Flywheel local https://local.getflywheel.com/

PCRE Library Version: 8.38 2015-11-23

I have been trying to work with register_rest_route but running into regex issues. It seems that there is some filtering on the regex before its executed.

The function I am trying to create is grabbing a post by the permalink. Basically I have a client that is structuring its url’s similar to wordpress so it wants to pass the permalink to wordpress so I can get the post data

register_rest_route( $this->namespace, '/post_by_permalink/(?P<path>[\w-]+)', array(
   'methods'             => WP_REST_Server::READABLE,
   'callback'            => array( $this, 'postByPermalink' ),
   'permission_callback' => array( $this, 'permissions' ),
   'show_in_rest' => true
));

This is the function I am using and it works in some cases. However that is only because the ones that work do not produce any special characters.

Right now my plan was in the client to convert the permalink to base64 to make it easier to pass through the url, though I am open to suggestions if they work (I only thought of base64 since urlencode was even more of a nightmare).

Basically the only regex that work in wordpress seems to be (?P<path>[\w-]+) and (?P<path>[\d]+). Anything else, does not work, even if it was successful testing it in something like http://www.phpliveregex.com

For instance, according to the tester (?P<path>[\S]+) should work, but all I get from wordpress is rest_no_route

Is there anyway to get wordpress to handle regex normally? Or at least tell it to allow an expression that could catch base64? I have seen some options online, but none work, likely due to changes in wp rest over time (all say “just use regex”, yet it seems to filter more complex regex)

EDIT: extending example

app/v1/post_by_permalink/(?P<path>[\S-]+)

Is what will work in http://www.phpliveregex.com

The search string being

/wp-json/app/v1/post_by_permalink/dGVzdC90ZXN0

That same regex will not work in wordpress, only (?P<path>[\w-]+) will work, and for the the above example, it will work as well in both since there are no special characters.

However for this string it will not

/wp-json/app/v1/post_by_permalink/dGVzdC90ZXN0LzM1NzM0Ly0=

Since it has an = So although in the regex tester (?P<path>[\S]+) works, it will not work in wordpress.

Edit: further testing

I managed to look up rest_pre_dispatch and get it working to catch the request before it checks the routes.

add_filter('rest_pre_dispatch', 'filter_request');
function filter_request($result) {
    global $wp;

    //print_r($wp->request); die;
    preg_match("/app\/v1\/post_by_permalink\/(?P<path>[\S]+)/", $wp->request, $output);
    print_r($output); die;
    return $result;
}

Is able to set the path correctly, so it does not seem to be a preg_match problem. At least with this I can bypass wp-rest and get around this issue, but I still have not found what is actually causing every environment I try this in to fail, and yet no one else can recreate it…..

After testing more thoroughly I got the below to work, I was using $wp->request witch included wp-json that was causing the regex to fail.

Though when I use preg_match( '@^' . $route . '$@i', $path, $matches ) I cannot get it to work (that is how wp-rest does it, $route being what is passed through register_rest_route), and using preg_match in this way is not supported in the regex tester http://www.phpliveregex.com/ either. It adds more questions then answers.

2 Answers
2

I got curious, so I tested this barebone demo:

add_action( 'rest_api_init', function () {
    register_rest_route( 'wpse/v1', '/post_by_permalink/(?P<path>[\S]+)', [
        'methods'      => WP_REST_Server::READABLE,
        'callback'     => 'wpse_callback',
        'show_in_rest' => true
    ] );
});

function wpse_callback( $request ) {
    $data = [ 'path' => base64_decode( $request['path'] ) ];
    return $data;
}

Testing:

https://example.com/wp-json/wpse/v1/post_by_permalink/aHR0cHM6Ly93b3JkcHJlc3Muc3RhY2tleGNoYW5nZS5jb20vcS8zMDEwNjcv

gives

{
   path: "https://wordpress.stackexchange.com/q/301067/"
}

Tested also

https://example.com/wp-json/wpse/v1/post_by_permalink/aHR0cHM6Ly93b3JkcHJlc3Muc3RhY2tleGNoYW5nZS5jb20vcXVlc3Rpb25zLzMwMTA2Ny9yZWdpc3Rlci1yZXN0LXJvdXRlLXJlZ2V4LW9wdGlvbi1mb3ItYmFzZTY0LW9yLWFsdGVybmF0ZS8zMDEwNzY=

that gave:

{
path: "https://wordpress.stackexchange.com/questions/301067/register-rest-route-regex-option-for-base64-or-alternate/301076"
}

Tested further:

https://example.com/wp-json/wpse/v1/post_by_permalink/dGVzdC90ZXN0LzM1NzM0Ly0=

with output:

{
path: "test/test/35734/-"
}

Leave a Comment