Dear Reader,
I’m going to add this to “Using the WordPress REST API“, but I thought I would blog it here as well.
I have a tendency to over think things.
Today, I was working on a REST API endpoint for a client and it needed to have RegEx in it. I hate RegEx with a passion usually reserved for XML, but unlike XML, it’s a necessary evil, so I dove into it.
1 | /item/(?P<itemId>\d+) |
That’s an example.
For the uninitiated, when you are defining a custom WordPress REST endpoint, one of the things you can do is put in Regex into the route definition and WordPress will use that to pull out content and make it a parameter. The code above defines an endpoint for
https://example.com/wp-json/my-namespace/v1/item/4
When run, it will make a parameter named itemId whose value is the 4 from the URI. It’s incredibly handy. They are very easy to work with, especially if you are using numbers like 4, or even 294875. Strings…well, strings get tricky.
The above example expect a number (so no alpha, just numeric) and numbers are contiguous. You don’t have numbers with a space in them. Phrases however, have spaces. And what I needed to pull out was a phrase. So, I did what I always do, I pulled out Regex 101, and started figuring this out. This is where the overthinking part comes in.
I got it working in short order, then I started thinking. “What if…”
- What if There’s a query string at the end
- What if there’s more to the URI
- What if there’s a slash at the end
- …what if
This is where I got into trouble. I lost a good 2-3 hours designing a beautiful piece of RegEx that handled every situation I could think of. It was art, if I do say so myself. The only problem was that once I pasted it into my WordPress REST Controller, it did not work.
So I did what every developer does, I assumed the problem had to be in WordPress. I rolled up my sleeves and found out how WordPress matches routes.
What WordPress does
WordPress matches REST routes in WP_REST_Server::dispatch() (wp-includes/rest-api/class-wp-rest-server.php)
1 | $match = preg_match( '@^' . $route . '$@i', $path, $matches ); |
https://example.com/wp-json/my-namespace/v1/item/this%20item%20name
1 | item/(?P<itemName>[w+].*)[?|/|\$] |
var_dump();die();
into WP_REST_Server. I thought I needed to see what was going on. Turns out, the answer was there in front of me all the time.- It puts a ‘@’ at the beginning of it. This tells PHP that ‘@’ is the regex delimiter, not ‘/’ like usual
- It adds the caret ‘^’ to match the beginning of the line
- It concatenates the route I defined
- It adds the $ to match the end of the line
- It puts the ‘@’ to signify that this is the end of the RegEx
- It adds the ‘i’ pattern modifier (the things I needed to tinker with) to indicate that all matches should be case insensitive
1 | item/(?P<itemName>w+.*) |
itemName
that includes everything past item/
to the end of the line.Conclusion
Did I meantion I hate Regex? :)
Until next time,
I <3 |<
=C=
p.s. the section in the book will be more coherant. I’ve spent the day with RegEx so I’m a bit scatterbrained now. :)