I need to write a REST API endpoint, but lets assume we know nothing about REST APIs.
The Task
My homepage has a box that contains a magical word, and I’m going to use the REST API to grab this word and display it on my site:
<div id="tomsword">... word goes here ...</div>
I’m going to need:
- A word to use, I’ve chosen “moomins”
- A REST API endpoint on my site to send the word from
- Some Javascript to ask the API for the magic word
The Endpoint
This parts easy. REST API endpoints live at /wp-json, and they have a namespace so your endpoints don’t clash with those of other plugins. My endpoint is going to live at tomjn.com/wp-json/tomjn/v1/test.
When my endpoint is called, I want to return the word “moomins”, so I’ve prepared a function to do just that:
function tomjn_rest_test() { return "moomins"; }
and I’ll register my endpoint, and tell WordPress what to do when it’s called like this:
add_action( 'rest_api_init', function () { register_rest_route( 'tomjn/v1', '/test/', array( 'methods' => 'GET', 'permission_callback' => '__return_true', 'callback' => 'tomjn_rest_test' ) ); } );
Congrats! I now have an endpoint, and you can see it by visiting https://tomjn.com/wp-json/tomjn/v1/test :
As for what those parameters do:
tomjn/v1
is the namespace and beginning of the URL ( /wp-json/tomjn/v1/test )/test/
is the name of the endpoint ( /wp-json/tomjn/v1/test )'methods' => 'GET'
tells it to respond to normal browser GET requests, like<form method="get"...
or just loading the page in a browser via the address bar'permission_callback' => '__return_true',
is a chance to name a function that controls if the user can or cannot use this. I’ve chosen__return_true
so everybody can use it'callback' => 'tomjn_rest_test'
when someone uses this endpoint, call thetomjn_rest_test
function to get the answer
Using our Endpoint in The Theme
Let’s write some javascript in our template:
<script> jQuery.ajax({ url: <?php echo wp_json_encode( esc_url_raw( rest_url( 'tomjn/v1/test' ) ) ); ?> }).done(function( data ) { jQuery( '#tomsword' ).text( data ); }); </script>
It’s that simple! Now our homepage runs a bit of code when we load it, that fetches a word from a REST API, and puts it in a div.
Writing REST API endpoints is quick, and easier to secure. There’s no reason to use the AJAX API in the future.
Thanks for the post. Good intro to adding an endpoint and how to use.
Should the PHP perhaps replace esc_url() with wp_json_encode()? The former adds HTML entities (which may not be interpreted properly by the JS parser) while the latter adds the double-quotes with JS esscaping for you (which ensures there won’t be a JS syntax error).
Possibly, my understanding is that the result of
esc_url
is always a URL, even if it’s a mangled one, which was my intention.It’s possible that wrapping it in another function such as
wp_json_encode
may avoid the situation you mentioned, but I’d err on secure but broken code over trying to make it always syntactically perfect. Having said thatwp_json_encode
would also prevent injection attacks 🙂I think then that it could use esc_url_raw() because it doesn’t add HTML entities (for sake of use in href attributes). So like:
echo wp_json_encode( esc_url_raw( rest_url( 'tomjn/v1/test' ) ) )
Here’s a simple example to illustrate the problem, in a
script
tag:console.info( "<?php echo esc_url( rest_url( '/wp/v2/posts/?s=test&status=draft' ) ) ?>" );
Notice that this will output to the console:
http://example.com/wp-json/wp/v2/posts/?s=test&status=draft
Notice how the query params are corrupted in the JS string value. However, doing the follow gets you the expected result printed to the console:
console.info( <?php echo wp_json_encode( esc_url_raw( rest_url( '/wp/v2/posts/?s=test&status=draft' ) ) ) ?> );
This isn’t really a problem in the example you give, but since the return value of
rest_url()
has arest_url
filter, it is possible that a plugin could be attempting to add query params to the REST URL and if they did, the params would be corrupted if passed throughesc_url()
in this context.…and WordPress ate the code in my comment. In the first URL example, I tried to show the ampersand would get encoded an HTML entity and not be converted back into an ampersand when parsed by JS.
This makes sense, I’ll update the post and I fixed the ampersand in your example
Thanks! Also you need to remove the literal double quotes in your example since
wp_json_encode()
will add them.Thanks for this great article Tom. This is by far the most understandable micro tutorial about custom WP REST API endpoints I’ve ever read.
Unfortunately while following your steps I run into an issue. I needed to change get_rest_url( ‘tomjn/v1/test’ ) to get_rest_url( null, ‘tomjn/v1/test’ ). The first call only gave me the REST url (https://tomjn.com/wp-json), whereas the second call gave me the full path (https://tomjn.com/wp-json/tomjn/v1/test). Might this be a glitch on my machine?
good catch!
rest_url
is what I should have used, which does exactly what you suggested internally 🙂Very easy to understand!
By the way, I love the huge typography here! Easy to read 😉
Nice! That’s absolutely the simplest example I’ve seen thus far. Cheers!
Pingback: Introduction – WordPress API tutoriel
Pingback: Ajouter ses propres Endpoints – WordPress API tutoriel
Pingback: Ajouter ses propres Endpoints – #1 – WordPress REST API
Pingback: Références – WordPress REST API
Pingback: Introduction – WordPress REST API
Missing some key information here for those of us who have been away from WordPress for a very long time:
– Where do I put the tomjn_rest_test() function? What’s the filename? I assume it lives in /wp-json/tomjn/v1/test, but every time I make an assumption I am wrong.
– Where do I register the call? The same file? Somewhere else?
Thanks man!!
These are standard hooks, and you’d use them the same way you’d use any other hook in WordPress, just as you might have done 3 or 6 years ago. I won’t go into how to use actions and filters though as it’s covered far better in the Developer Handbook on WordPress.org than I could in a comment
Understood.
For anyone else like me who visits this page, this is the starting point that I assume Tom is referring to:
https://codex.wordpress.org/Plugin_API
I have this working now.
If you are authoring a theme (not a plugin), you can add the function and the REST route registration to your theme’s “functions.php” file.
Very easy to understand and takes no time at all.
Here is an answer to my StackOverflow question which lead me to this very simple and trivial answer:
https://wordpress.stackexchange.com/questions/267491/when-adding-a-custom-rest-endpoint-where-do-you-put-the-endpoint-function-and/267496#267496
Thank you, THIS is what a helpful comment looks like.
Pingback: Unicorn Heaven! Highlights From WordCamp Edinburgh 2017
Pingback: Writing a WordPress REST endpoint in 2 minutes – Full-Stack Feed
Very good explanation. Could you offer one or two examples of a more real-world scenario in which this kind of thing would be useful? I’d really like to start using the REST API more but I have yet to find a situation where I really need it for anything.
Any situation that involves JS contacting your site, be it to fetch posts, create posts, or retrieve other information. E.g. infinite scroll, form submissions, user settings, post widgets, etc
I like the way you laid it out and made it feel so approachable 🙂
Just noted your last sentence :
“There’s no reason to use the AJAX API in the future.”
Perhaps you mean :
“There’s no reason NOT to use the AJAX API in the future.” ?
Cheers !
Thanks! In the last bit I was referring to the admin AJAX API that rest replaces
Your post helped crystalize what an endpoint is, what a route is, and why it matters. Write more… 🙂 Thanks!
Pingback: Rest API instead on .JS file – WordPress Solutions Group
Pingback: The Top 100 Most Commonly Used WordPress Functions - Vegibit
Pingback: Weekly WordPress News: Should You Sell Themes or Plugins?
I type link Rest API: …/wp-json/wp/v2/posts?orderby=rand&per_page=6 to get random post, but the result is only one time, the next times are not random anymore.
How to to fix it?
Thanks bro
Hey Trường, sounds like you have a general support question, you should ask on the .org forums.
Keep in mind though, that asking the database to randomly order the posts is incredibly expensive, and super heavy on the database. It’s one of the worst things you can do for performance, wether you do it via WP_Query or the REST API or another method, always do it in JS, not the database.