Working with Forms using REST API

WordPress, being an ever-improving content management system, is now moving toward becoming a full-fledged application framework, which brings up the necessity for new APIs. The WordPress REST API has been created to create necessary and reliable APIs. The plugin provides an easy-to-use REST API, available via HTTP that grabs your site's data in the JSON format and further retrieves it.

WordPress REST API is now at its second version and has brought a few core differences, compared to its previous one, including route registration via functions, endpoints that take a single parameter, and all built-in endpoints that use a common controller.

In this article by Sufyan bin Uzayr, author of the book Learning WordPress REST API, you'll learn how to write a functional plugin to create and edit posts using the latest version of the WordPress REST API. This article will also cover the process on how to work efficiently with data to update your page dynamically based on results. This tutorial comes to serve as a basis and introduction to processing form data using the REST API and AJAX and not as a redo of the WordPress post editor or a frontend editing plugin.

REST API's first task is to make your WordPress powered websites more dynamic, and for this precise reason, I have created a thorough tutorial that will take you step by step in this process. After you understand how the framework works, you will be able to implement it on your sites, thus making them more dynamic.

(For more resources related to this topic, see here.)

Fundamentals

In this article, you will be doing something similar, but instead of using the WordPress HTTP API and PHP, you'll use jQuery's AJAX methods. All of the code for that project should go in its plugin file.Another important tip before starting is to have the required JavaScript client installed that uses the WordPress REST API. You will be using the JavaScript client to make it possible to authorize via the current user's cookies.

As a note for this tip would be the fact that you can actually substitute another authorization method such as OAuth if you would find it suitable.

Setup the plugin

During the course of this tutorial, you'll only need one PHP and one JavaScript file. Nothing else is necessary for the creation of our plugin.

We will be starting off with writing a simple PHP file that will do the following three key things for us:

  • Enqueue the JavaScript file
  • Localize a dynamically created JavaScript object into the DOM when you use the said file
  • Create the HTML markup for our future form

All that is required of us is to have two functions and two hooks. To get this done, we will be creating a new folder in our plugin directory with one of the PHP files inside it. This will serve as the foundation for our future plugin. We will give the file a conventional name, such as my-rest-post-editor.php.

In the following you can see our starting PHP file with the necessary empty functions that we will be expanding in the next steps:

<?php

/*

Plugin Name: My REST API Post Editor

*/

add_shortcode( 'My-Post-EditorR', 'my_rest_post_editor_form');

function my_rest_post_editor_form( ) {

}

add_action( 'wp_enqueue_scripts', 'my_rest_api_scripts' );

function my_rest_api_scripts() {

}

For this demonstration, notice that you're working only with the post title and post content. This means that in the form editor function, you only need the HTML for a simple form for those two fields.

Creating the form with HTML markup

As you can notice, we are only working with the post title and post content. This makes it necessary only to have the HTML for a simple form for those two fields in the editor form function. The necessary code excerpt is as follows:

function my_rest_post_editor_form( ) {

$form = '

<form id="editor">

<input type="text" name="title" id="title" value="My title">

<textarea id="content"></textarea>

<input type="submit" value="Submit" id="submit">

</form>

<div id="results">

</div>';

return $form;

}

Our aim is to show this only to those users who are logged in on the site and have the ability to edit posts. We will be wrapping the variable containing the form in some conditional checks that will allow us to fulfill the said aim. These tests will check whether the user is logged-inin the system or not, and if he's not,he will be provided with a link to the default WordPress login page.

The code excerpt with the required function is as follows:

function my_rest_post_editor_form( ) {

$form = '

<form id="editor">

<input type="text" name="title" id="title" value="My title">

<textarea id="content"></textarea>

<input type="submit" value="Submit" id="submit">

</form>

<div id="results">

</div>

';

if (

is_user_logged_in() ) {

if ( user_can( get_current_user_id(), 'edit_posts' ) ) {

return $form;

}

else {

return __( 'You do not have permissions to do this.', 'my-rest-post-editor' );

}

}

else {

     return sprintf( '<a href="%1s" title="Login">%2s</a>', wp_login_url( get_permalink( get_

queried_object_id() ) ), __( 'You must be logged in to do this, please click here to log in.',

'my-rest-post-editor') );

}

}

To avoid confusions, we do not want our page to be processed automatically or somehow cause a page reload upon submitting it, which is why our form will not have either a method or an action set. This is an important thing to notice because that's how we are avoiding the unnecessary automatic processes.

Enqueueing your JavaScript file

Another necessary thing to do is to enqueue your JavaScript file. This step is important because this function provides a systematic and organized way of loading Javascript files and styles. Using the wp_enqueue_script function, you will tell WordPress when to load a script, where to load it, and what are its dependencies. By doing this, everyone utilizes the built-in JavaScript libraries that come bundled with WordPress rather than loading the same third-party script several times. Another big advantage of doing this is that it helps reduce the page load time and avoids potential code conflicts with other plugins.

We use this method instead the wrong method of loading in the head section of our site because that's how we avoid loading two different plugins twice, in case we add one more manually.

Once the enqueuing is done, we will be localizing an array of data into it, which you'll need to include in the JavaScript that needs to be generated dynamically. This will include the base URL for the REST API, as that can change with a filter, mainly for security purposes.

Our next step is to make this piece as useable and user-friendly as possible, and for this, we will be creating both a failure and success message in an array so that our strings would be translation friendly. When done with this, you'll need to know the current user's ID and include that one in the code as well.

The result we have accomplished so far is owed to the wp_enqueue_script()and wp_localize_script()functions. It would also be possible to add custom styles to the editor, and that would be achieved by using the wp_enqueue_style()function.

While we have assessed the importance and functionality of wp_enqueue_script(), let's take a close look at the other ones as well.

The wp_localize_script()function allows you to localize a registered script with data for a JavaScript variable. By this, we will be offered a properly localized translation for any used string within our script. As WordPress currently offers localization API in PHP; this comes as a necessary measure. Though the localization is the main use of the function, it can be used to make any data available to your script that you can usually only get from the server side of WordPress.

The wp_enqueue_stylefunctionis the best solution for adding stylesheets within your WordPress plugins, as this will handle all of the stylesheets that need to be added to the page and will do it in one place. If you have two plugins using the same stylesheet and both of them use the same handle, then WordPress will only add the stylesheet on the page once.

When adding things to wp_enqueue_style, it adds your styles to a list of stylesheets it needs to add on the page when it is loaded. If a handle already exists, it will not add a new stylesheet to the list. The function is as follows:

function my_rest_api_scripts() {

wp_enqueue_script( 'my-api-post-editor', plugins_url( 'my-api-post-editor.js', __FILE__ ),

array( 'jquery' ), false, true );

wp_localize_script( 'my-api-post-editor', 'my_post_editor', array(

'root' => esc_url_raw( rest_url() ),

'nonce' => wp_create_nonce( 'wp_json' ),

'successMessage' => __( 'Post Creation Successful.', 'my-rest-post-editor' ),

'failureMessage' => __( 'An error has occurred.', 'my-rest-post-editor' ),

'userID'    => get_current_user_id(),

) );

}

That will be all the PHP you need as everything else is handled via JavaScript. Creating a new page with the editor shortcode (MY-POST-EDITOR) is what you should be doing next and then proceed to that new page. If you've followed the instructions precisely, then you should see the post editor form on that page. It will obviously not be functional just yet, not before we write some JavaScript that will add functionality to it.

Issuing requests for creating posts

To create posts from our form, we will need to use a POST request, which we can make by using jQuery's AJAX method. This should be a familiar and very simple process for you, yet if you're not acquitted with it,you may want to take a look through the documentation and guiding offered by the guys at jQuery themselves (http://api.jquery.com/jquery.ajax/). You will also need to create two things that may be new to you, such as the JSON array and adding the authorization header. In the following, we will be walking through each of them in details.

To create the JSON object for your AJAX request, you must firstly create a JavaScript array from the input and then use the JSON.stringify()to convert it into JSON. The JSON.strinfiy() method will convert a JavaScript value to a JSON string by replacing values if a replacer function is specified or optionally including only the specified properties if a replacer array is specified. The following code excerpt is the beginning of the JavaScript file that shows how to build the JSON array:

(function($){

$( '#editor' ).on( 'submit', function(e) {

       e.preventDefault();

var title = $( '#title' ).val();

var content = $( '#content' ).val();

       var JSONObj = {

"title"  :title,

"content_raw" :content,

"status"  :'publish'

};

       var data = JSON.stringify(JSONObj);

})(jQuery);

Before passing the variable data to the AJAX request, you will have first to set the URL for the request. This step is as simple as appending wp.v2/posts to the root URL for the API, which is accessible via _POST_EDITOR.root:

var url = _POST_EDITOR.root;

url = url + 'wp/v2/posts';

The AJAX request will look a lot like any other AJAX request you would make, with the sole exception of the authorization headers. Because of the REST API's JavaScript client, the only thing that you will be required to do is to add a header to the request containing the nonce set in the _POST_EDITOR object. Another method that could work as an alternative would be the OAuth authorization method.

Nonce is an authorization method that generates a number for specific use, such as a session authentication. In this context, nonce stands for number used once or number once.

OAuth authorization method

OAuth authorization method provides users with secure access to server resources on behalf of a resource owner. It specifies a process for resource owners to authorize third-party access to their server resources without sharing any user credentials. It is important to state that is has been designed to work with HTTP protocols, allowing an authorization server to issue access tokens to third-party clients. The third party would then use the access token to access the protected resources hosted on the server.

Using the nonce method to verify cookie authentication involves setting a request header with the name X-WP-Nonce, which will contain the said nonce value. You can then use the beforeSend function of the request to send the nonce. Following is what that looks like in the AJAX request:

$.ajax({

           type:"POST",

url: url,

dataType : 'json',

data: data,

           beforeSend : function( xhr ) {

               xhr.setRequestHeader( 'X-WP-Nonce', MY_POST_EDITOR.nonce );

},

});

As you might have noticed, the only missing things are the functions that would display success and failure. These alerts can be easily created by using the messages that we localized into the script earlier. We will now output the result of the provided request as a simple JSON array so that we would see how it looks like.

Following is the complete code for the JavaScript to create a post editor that can now create new posts:

(function($){

$( '#editor' ).on( 'submit', function(e) {

       e.preventDefault();

var title = $( '#title' ).val();

var content = $( '#content' ).val();

       var JSONObj = {

"title"   :title,

"content_raw" :content,

"status"   :'publish'

};

       var data = JSON.stringify(JSONObj);

       var url = MY_POST_EDITOR.root;

url += 'wp/v2/posts';

       $.ajax({

           type:"POST",

url: url,

dataType : 'json',

data: data,

           beforeSend : function( xhr ) {

               xhr.setRequestHeader( 'X-WP-Nonce', MY_POST_EDITOR.nonce );

},

success: function(response) {

               alert( MY_POST_EDITOR.successMessage );

               $( "#results").append( JSON.stringify( response ) );

},

failure: function( response ) {

               alert( MY_POST_EDITOR.failureMessage );

}

});

});

})(jQuery);

This is how we can create a basic editor in WP REST API.

If you are a logged in and the API is still active, you should create a new post and then create an alert telling you that the post has been created. The returned JSON object would then be placed into the #results container.

Insert image_B05401_04_01.png

If you followed each and every step precisely, you should now have a basic editor ready. You may want to give it a try and see how it works for you. So far, we have created and set up a basic editor that allows you to create posts. In our next steps, we will go through the process of adding functionality to our plugin, which will enable us to edit existing posts.

Issuing requests for editing posts

In this section, we will go together through the process of adding functionality to our editor so that we could edit existing posts. This part may be a little bit more detailed, mainly because the first part of our tutorial covered the basics and setup of the editor.

To edit posts, we would need to have the following two things:

  • A list of posts by author, with all of the posts titles and post content
  • A new form field to hold the ID of the post you're editing

As you can understand, the list of posts by author and the form field would lay the foundation for the functionality of editing posts.

Before adding that hidden field to your form, add the following HTMLcode:

<input type="hidden" name="post-id" id="post-id" value="">

In this step, we will need to get the value of the field for creating new posts. This will be achieved by writing a few lines of code in the JavaScript function. This code will then allow us to automatically change the URL, thus making it possible to edit the post of the said ID, rather than having to create a new one every time we would go through the process.

This would be easily achieved by writing down a simple code piece, like the following one:

var postID = $( '#post-id').val();

if ( undefined !== postID ) {

url += '/';

   url += postID;

}

As we move on, the preceding code will be placed before the AJAX section of the editor form processor. It is important to understand that the variable URL in the AJAX function will have the ID of the post that you are editing only if the field has value as well. The case in which no such value is present for the field, it will yield in the creation of a new post, which would be identical to the process you have been taken through previously.

It is important to understand that to populate the said field, including the post title and post content field, you will be required to add a second form. This will result in all posts to be retrieved by the current user, by using a GET request. Based on the selection provided in the said form, you can set the editor form to update. In the PHP, you will then add the second form, which will look similar to the following:

<form id="select-post">

<select id="posts" name="posts">

</select>

<input type="submit" value="Select a Post to edit" id="choose-post">

</form>

REST API will now be used to populate the options within the #posts select. For us to achieve that, we will have to create a request for posts by the current user. To accomplish our goal, we will be using the available results.

We will now have to form the URL for requesting posts by the current user, which will happen if you will set the current user ID as a part of the _POST_EDITOR object during the processes of the script setup.

A function needs to be created to get posts by the current author and populate the select field. This is very similar to what we did when we made our posts update, yet it is way simpler. This function will not require any authentication, and given the fact that you have already been taken through the process of creating a similar function, creating this one shouldn't be any more of a hassle for you.

The success function loops through the results and adds them to the postselector form as options for its one field and will generate a similar code, something like the following:

function getPostsByUser( defaultID ) {

   url += '?filter[author]=';

   url += my_POST_EDITOR.userID;

   url += '&filter[per_page]=20';

   $.ajax({

type:"GET",

url: url,

dataType : 'json',

success: function(response) {

var posts = {};

$.each(response, function(i, val) {

               $( "#posts" ).append(new Option( val.title, val.ID ) );

});

           if ( undefined != defaultID ) {

               $('[name=posts]').val( defaultID )

}

}

});

}

You can notice that the function we have created has one of the parameters set for defaultID, but this shouldn't be a matter of concern for you just now. The parameter, if defined, would be used to set the default value of the select field, yet, for now, we will ignore it. We will use the very same function, but without the default value, and will then set it to run on document ready. This is simply achieved by a small piece of code like the following:

$( document ).ready( function()

{

   getPostsByUser();

});

Having a list of posts by the current user isn't enough, and you will have to get the title and the content of the selected post and push it into the form for further editing.

This is will assure the proper editing possibility and make it possible to achieve the projected result. Moving on, we will need the other GET request to run on the submission of the postselector form.

This should be something of the kind:

$( '#select-post' ).on( 'submit', function(e) {

   e.preventDefault();

   var ID = $( '#posts' ).val();

   var postURL = MY_POST_EDITOR.root;

postURL += 'wp/v2/posts/';

   postURL += ID;

   $.ajax({

type:"GET",

url: postURL,

dataType : 'json',

success: function(post) {

var title = post.title;

var content = post.content;

           var postID = postID;

$( '#editor #title').val( title );

$( '#editor #content').val( content );

           $( '#select-post #posts').val( postID );

}

});

});

In the form of <json-url>wp/v2/posts/<post-id>, we will build a new URL that will be used to scrape post data for any selected post. This will result in us making an actual request that will be used to take the returned data and then set it as the value of any of the three fields there in the editor form.

Upon refreshing the page, you will be able to see all posts by the current user in a specific selector. Submitting the data by a click will yield in the following:

The content and title of the post that you have selected will be visible to the editor, given that you have followed the preceding steps correctly.

And the second occurrence will be in the fact that the hidden field for the post ID you have added should now be set.

Even though the content and title of the post will be visible, we would still be unable to edit the actual posts as the function for the editor form was not set for this specific purpose, just yet. To achieve that, we will need to make a small modification to the function that will make it possible for the content to be editable. Besides, at the moment, we would only get our content and title displayed in raw JSON data; however, applying the method described previously will improve the success function for that request so that the title and content of the post displays in the proper container, #results. In order to achieve this, you will need a function that is going to update the said container with the appropriate data. The code piece for this function will be something like the following:

function results( val ) {

$( "#results").empty();

       $( "#results" ).append( '<div class="post-title">' + val.title + '</div>'  );

       $( "#results" ).append( '<div class="post-content">' + val.content + '</div>'  );

}

The preceding code makes use of some very simple jQuery techniques, but that doesn't make it any worse as a proper introduction to updating page content by making use of data from the REST API. There are countless ways of getting a lot more detailed or creative with this if you dive in the markup or start adding any additional fields. That will always be an option for you if you're more of a savvy developer, but as an introductory tutorial, we're trying not to keep this tutorial extremely technical, which is why we'll stick to the provided example for now.

Insert image_B05401_04_02.png

As we move forward, you can use it in your modified form procession function, which will be something like the following:

$( '#editor' ).on( 'submit', function(e) {

   e.preventDefault();

var title = $( '#title' ).val();

var content = $( '#content' ).val();

console.log( content );

   var JSONObj = {

"title"

"content_raw"

"status"

};

:title,

:content,

:'publish'

   var data = JSON.stringify(JSONObj);

   var postID = $( '#post-id').val();

   if ( undefined !== postID ) {

url += '/';

       url += postID;

}

   $.ajax({

       type:"POST",

url: url,

dataType : 'json',

data: data,

       beforeSend : function( xhr ) {

           xhr.setRequestHeader( 'X-WP-Nonce', MY_POST_EDITOR.nonce );

},

success: function(response) {

           alert( MY_POST_EDITOR.successMessage );

           getPostsByUser( response.ID );

results( response );

},

failure: function( response ) {

           alert( MY_POST_EDITOR.failureMessage );

}

});

});

As you have noticed, a few changes have been applied, and we will go through each of them in specific:

  • The first thing that has changed is the Post ID that's being edited is now conditionally added. This implies that we will make use of the form and it will serve to create new posts by POSTing to the endpoint. Another change with the POST ID is that it will now update posts via posts/<post-id>.
  • The second change regards the success function. A new result() function was used to output the post title and content during the process of editing. Another thing is that we also reran the getPostsbyUser() function, yet it has been set in a way that posts will automatically offer the functionality of editing, just after you will createthem.

Summary

With this, we havefinishedoff this article, and if you have followed each step with precision, you should now have a simple yet functional plugin that can create and edit posts by using the WordPress REST API.

This article also covered techniques on how to work with data in order to update your page dynamically based on the available results. We will now progress toward further complicated actions with REST API.

Resources for Article:


Further resources on this subject:


You've been reading an excerpt of:

Learning WordPress REST API

Explore Title
comments powered by Disqus