We will use the WordPress REST API Routes to retrieve questions and scores used for building our Quiz in React. We need a route to retrieve the questions with their answers and to submit the answers so we can get our result. In this tutorial, we will proceed to our WordPress roadmap and define our custom post type, metabox and also the WordPress REST API Routes.
If you have not yet learned about what we are going to build and the roadmap for each part, you can check the last article: Building a Quiz with React and WordPress REST API: Introduction.
The Base Plugin
In the last article, we did not create a base plugin. So let’s do that now. Create a folder in the
plugins folder and name it
wp-quiz-tut. Create a new
php file inside that folder with the same name
Inside that folder create another one and name it
inc. We will use that folder for additional files. Create 2 empty
wp-quiz-tut.php will hold the main class of our plugin that is going to be used when loading the plugin and all the dependencies. Add this code to the file.
Now activate the plugin inside the WordPress admin area.
We need only one custom post type and that is the
question post type. This post type will be used for storing the information of our questions and the answers.
Let’s now create our custom post type. We will extend the
load method and add a new once
I won’t go into details on how to configure your custom post type, but if you want to know, do check the Codex or the Developer Resources. If you refresh the admin area, you will now see a Questions menu.
For the metabox, we will create a new class
WPQR_Metaboxes that can be used for defining various metaboxes. Before that we will register the registration method in our main class
For now, your plugin would not work and it will break your site. That’s because we still have not defined our
WPQR_Metaboxes class. We will do that right now.
Open the file
class-wpqr-metaboxes.php that we created before and add the code below.
Inside of our class, we have the static method
answers that is called as a callback function for the registered metabox. Inside of that method, we are retrieving the answers.
For the sake of simplicity, I’ve made a form of 3 static answers. You could enhance that and create a repeater field for adding and removing answers. If you want to see how to do that, you can read my article on How to create a Repeater Field with wp.template().
Inside that form, I am checking for each answer if there is a defined value for
points. If it is, we are displaying that data. Otherwise, we are displaying an empty string for the answer’s text and
0 for points.
Saving the Answers
Since we will save those answers in one postmeta field, we need to define a save method that will do just that. But before we do that, let’s add that save method in our main class.
It is important to understand how this data is posted on our server before we create the method
If we add the text for each answer and points next to it and then try to save the post, we would receive something like this on the server:
We will now need to map the points to the answers based on their order (index). Let’s now define our
Basically, we are going through each posted answer and then we are checking if there are any points defined on the same order (index) as the current answer. If it is, we are mapping them together. In the end, we will have an array like this:
REST API Routes
The last part is to define the REST API Routes. We will do that in a static method
register_routes in our new class
WPQR_REST_API. Let’s load that in our main class:
Now our static method will be called so we need to define that. If you’re interested on how to create custom WordPress REST API routes check the handbook.
Open the file
class-wpqr-rest-api.php and add the code below.
In the first method, we are register the route through the function
register_rest_route. We are providing the “rest namespace” of our plugin which will be
wpqr/v1. The endpoint is
By doing that, we can load this by using
In the method
get_questions we are checking if have a cached version of the questions. If not, we are retrieving all the questions. After we have retrieved all the questions, we are getting all the answers and then we are also filtering the answers array.
We don’t want to include the points in the output because we could just check the network tab in our browser and see all the points associated with answers. After filtering, we are only getting the Answer’s text.
In the screenshot below, you’ll see how this response can look like. Since I have entered only one question, you can only see the one object 🙂
Now it’s time to define our result route. On this route, we will expect an array
answers inside the body of the request. If there is none, we will throw an error. If there is, we will go through each answer where the
key will be the Question’s ID and the
value will be the index of the answer.
By using the
WP_REST_Server::CREATABLE, we are defining that only methods inside that constant will trigger our callback. If not, WordPress will send an error saying there is no such route for that method.
get_results is used to retrieve the user’s result. First, we are checking if we have any answers by using the method
get_body_params() on the
$request (this is passed to each REST API callback). If there are no answers, we will get an error response.
Here is an example of that when I don’t send anything inside the body of the request.
If there are answers, then we are going through each of them, we get the answers for that question and then we are calculating the points as described in the comments of the code.
Here is an example of it when I pick the third answer that has 10 points.
Securing the REST API
We could include a
permission_callback there and define a function that will return true or false based on my criteria. We can check for the
_wpnonce and if that is not posted, we don’t allow this route to execute.
REST API does check for the
_wpnonce and it validates it if that is posted. If not, it assumes that we are allowing the execution of our route without it (which if fine). Let’s see what happens if I include an invalid
_wpnonce in the request.
Download the Plugin
You can download the current state of our plugin here in a ZIP file.
By using the WP REST API, we can easily define how we retrieve data and also how we post the data. By having our own callback functions we can make the data much easier to parse and use in our React Apps.
Have you already defined some custom REST API routes? Are you using them with some complex Authentication? Please do share in the comments below!