 Hey there, and welcome to Learn WordPress. In this tutorial, you're going to learn how to extend the WordPress REST API by creating your own roots and endpoints. You will learn how to use the registerREST root function to register roots and how to create specific endpoints by setting the root method. You'll also learn how it's possible to specify root arguments and how to use them to fetch specific data. Let's consider a requirement to build a simple form submissions plugin which allows a name and email field to be captured via the WordPress REST API. The plugin should allow for a form submissions REST API root, which has three endpoints. One to fetch all form submissions, one to post a form submission to create it, and one to fetch a specific form submission. To start, because you're only storing a few simple fields, you might create a custom table to store the form submissions. The plugin code to create the custom table might look something like this. Here, in a function hooked into the plugin activation hook, you're using the global wpdb object and the dbdelta function to create a new table in the WordPress database called form submissions. The table has three fields ID, name and email. The ID field is set to auto increment and is the primary key. Once the plugin is activated, this will create the form submissions table in the database with the three fields. To register a custom REST API root, you use the register REST root function. This function requires the following three parameters. The namespace, which is the portion of the root URL that comes before the root itself. The root, which is the portion of the root URL that comes after the namespace. And the root arguments, which is an array of arguments that specify things like the root method and any other arguments that you need to pass to the callback function. Register REST root should only be called when the REST API net action is found. This ensures that the root is only registered when the WordPress REST API is loaded. So in your plugin, you might hook a callback function into the REST API net hook like this and set up the function to register the roots. Let's look at what the code would look like to register a custom root to fetch all form submissions. In this root, the namespace is wplearnformsubmission-v1. The root is form submissions. And the root arguments specify the root method as a get method and the callback function as wplearngetformsubmissions. It also specifies a permission callback function, which is used to check if the user has permission to access this root. In this case, it's using the built-in return true function, which returns true so that anyone can access this root. Once the root is created, you'll need to create the callback function. In this case, wplearngetformsubmissions. This function will be called when the root is requested and should return the form submissions. The code for this function could look something like this. Here this function uses the global wpdb variable to access the database and then uses its getResults function to fetch all the rows from the form submission table based on the SQL query. It then returns the results as an array. Because you've registered this callback against a wpREST API root using registerREST root, the array will automatically be sent in the REST API response as a JSON object. To test this, you can activate the plugin. Then check if the form submissions table has been created using your favorite database tool. In this case, I'm using phpmyadm. Next, add a few rows of data. So let's just add one row now. So Jonathan and Jonathan at gmail.com. Then open a REST API testing tool like Postman and create a new request to test the root. So here we have our existing Postman workspace for this website. We'll use the getPosts request to create the getFormSubmissions. So we can duplicate that. And let's rename this to getFormSubmissions and then we need to change the URL. So we need to include the namespace and the root. The namespace is learnFormSubmissions v1 and the root is formSubmissions. And if we save and send that request, we can see the response from the database. Now that you can fetch form submissions, you can register a root to create them. To do this, register a new root to use the post method and specify a callback function which will handle the post request. The quickest way to do that is to copy the existing registered root and make a few changes. Change the method to post and change the callback to something that makes more sense. As you can see, the namespace and root name are the same, but the method is set to post and a different callback function is specified. This callback function will be called when the root is accessed using the post method. It could look something like this. Here we can say function createFormSubmission and it will receive quest and actual code. Do this. The callback function accepts a single parameter, which is a WPRestRequest object and contains all the data that was sent to the root. In this case, the name and email fields will be available in the request object, which can be used to create the form submission. Again, the callback function uses the global WPDB variable in order to access the database and then uses its insert function to insert a new row into the form submission's table using the name and email field sent to the root. Notice how this code accesses the name and email properties using an array-like syntax. This is because the WPRestRequest object implements a PHP interface called ArrayAxis, which allows you to access object properties using the array syntax. Finally, the code returns the number of rows inserted. Note that in this example, there's no validation of the name and email inputs, which is a security vulnerability. For more information on how to validate inputs, check out the introduction to Security Developing Plugins tutorial at learn.wordpress.org. Note also that in this example, the callback function does not check if the fields have been sent in the request or even if they contain data. For the purposes of this example, let's assume they will always have been passed. To test this, create a new post request in your API testing tool and submit the name and email data as a JSON object in the request body. So again, we can copy the get form submissions request, update the name. We can leave the URI as is, but change the method to post. And then in the body, switch it to raw, change the formatting to JSON, and then pass in the required fields, which in this case are name and email. When you save and send the request, you should see the number of rows inserted return in the response. Notice how you didn't need to pass any authentication credentials to this route. This is because you set the permission callback to return true on the post request. This means that anyone can currently create a post request to this route and create a new form submission. If you want to restrict access to this route, you can specify a specific permissions callback function. So let's say something like wp-learn-check-permissions. You can then use the current user can function to check if the user has the required permissions. So we specify the callback function, the permissions callback, and we can return, it has to return either true or false, so we can say return current current user can and let's go with the edit posts permission. In this case, this will check for a valid user with permissions edit posts. Try testing this by submitting the post request using the route again. If we go back to postman and we try and send this again, you should see an authentication error, which means you don't have permission to access the route. To fix this, set up an application password for your current user, configure it in postman under authorization and try the request again. So let's go into the admin user and specify an application password and then we will copy that password, switch back to postman and click on the authorization tab, select basic auth, the username is admin and let's make sure we've got the correct password, there it is, and let's save and then just to verify the testing, let's change the values and send it. It should work this time and you see the returned rows in the response. To verify this, you can also check the database to make sure the data has been saved. So let's pop on over to the database and browse the form submissions table and there's John and Jane. The last requirement for your custom API route was an endpoint that could fetch a single submission. One way you could do this is set up the WP Learn Get Form Submissions callback to also accept the request parameter and then check if an ID value is passing the request body. So you could do something like this, you could say request here and then you could check for request ID and then pass that ID in the request body. A better solution is to use something called path variables. You've seen REST API variables before in the using the WP REST API tutorial where global variables were discussed. Path variables are similar, but they're used to pass data to the root. To implement a path variable, you add the path variable to the root name when you register the root. For example, if you wanted to implement a path variable for the ID field to fetch a single submission, you could register a root something like this. So let us pop this below our post and that's what it would look like. The key thing to note is the format of the path variable. It starts with a question mark in the case p, that it has the ID in greater than or smaller than signs and then it has a slash, d and a plus. The start of the path variable is a query string using an uppercase p as the query parameter. The next part is the name which is the name of the path variable. This will be used to create the property on the request object to access the path variable value. In this case we're specifying ID. Next is a regex pattern which is a regular expression pattern that the value should match. In this case the slash d plus means that the value should be a number. This tells the root that a value will be passed to the root and that it should be numeric. This numeric value will then be set up as a property with the name ID on the request object. Now you just need to create the wp-learn-getFormSubmission function to get the form submission based on the ID that looks something like this. So we will pop this just below the create form. There it is wp-learn-getFormSubmission. As you can see in the first line of this callback function it's expecting the ID to be passed to the root. It then uses that ID to retrieve a specific record from the FormSubmissions table. Because you have set this up as a path variable you only need to append the ID value at the end of the root URI when you make the request. The path variable will handle getting the value and setting it up inside the ID property of the request object. To test this create a new get request in your API testing tool and add the ID value to the end of the root. So to check this let's verify the IDs in our database so we have ID 1, 2 and 3. Again the quickest way to create this is to duplicate the getFormSubmissions request and then make some changes so we'll make this the getFormSubmission by ID we'll leave it as a get request but the root name is FormSubmission and we can verify that by looking at the root formSubmission and then the ID FormSubmission and then the ID and we can save and send. There's ID 1 and let's check if it will work for 2 and let's test 4. We're not expecting there to be a 4 so we should see some kind of error. So the reason we don't see a response here is because we're not actually checking in the code what to do if that record doesn't exist. You can play around with this a little to test it create a few more submissions, use the get root to fetch them and use the get single root to fetch a single submission by ID. This has been a fairly brief introduction to what you can achieve using registerRestRoot. For more information and examples check out the extending the REST API chapter of the WordPress REST API Handbook at developer.wordpress.org. Specifically, it's a good idea to read the adding custom endpoints page and the roots and endpoints section. Happy coding!