Build an App With WordPress – The compulsory todo list

Matt Mullenweg’s State Of The Word was very insightful into what was to come of WordPress in 2012. One thing he mentioned would be big, is be WordPress powering apps.

With that in mind, there aren’t many posts around that teach you how to make an app. I thought I’d start with the compulsory “How to make a to-do list app using WordPress!” It even works across all platforms- that’s right. Mobile, Tablet and Desktop!

There is a Demo page (username: user, password: notes) where you can see and play with what we’ll be creating. You can download the source theme too, and install it yourself. Or you can follow this tutorial.

A bit of Theory

Many web app frameworks these days use MVC or MVVM structure. WordPress has its own unique structure to handle data, but there’s no reason we can’t take some concepts and apply them ourselves. I’m talking about separating logic, event driven functions and views.

WordPress is a good starting point because it provides a plethora of APIs for us to leverage. We’ve got Authentication, User Roles, Sanitisation, and Content Types out-of-the-box, to name a few. We don’t have to worry about admin screens. If you’re creating a complex app, you don’t even have to worry about meta boxes, taxonomies, or dealing with image upload.

The approach we’re going to take is simple. I’ve built a starter theme (with CSS, and basic WP/JS functionality) for you to begin with. The code you’ll write in this tutorial will be separated into mainly Javascript (main.js), and WordPress logic (ajax-actions.php). This separation of code allows us to create a flexible yet well structured app.

To bring you up to speed

The focus of this tutorial isn’t to show you how to design an app, but to build it with AJAX. I’ll be showing you how to identify and deal with individual events, how to capture the data from them, post them to the WordPress database, and handle the response. All without ever going into wp-admin!

The starter theme I’ve put together for you is just a skeleton without any functionality. The entire UI is done for you (buttons, style, drop down menus, modal boxes), all that’s left to do is the heavy lifting, that is dealing with and saving data, and updating the UI based upon the response from WordPress. I’ve included Mustache.js and the templates we’ll be using (in footer.php), along with enough WordPress code to display a list of all posts and users currently in the database upon first load.

Data flow in a single page web app

Let’s examine the diagram from just above.

Here you can see our data is passed from the UI when a user submits data. Javascript interprets the UI input, and sends it to PHP as data. The PHP does the work of inserting the data into the WordPress database. When WordPress is happy, PHP tells Javascript the data is saved. Javascript then updates the UI for the user to recognise it all went smoothly.

In terms of Javascript, there are 4 important functions missing from the starter theme that we’re going to build. They are:

UI interaction (user actions)

UI requests (when a user submits data)

AJAX requests (sending the data to WordPress code)

AJAX response (handling the response we get back from WordPress)

In terms of WordPress and PHP code, we’re missing all the actions that handle the AJAX requests from the client. I’ll identify them for you in a second, but first get a new WordPress install up and running, and install the starter theme.

The base theme

User Interactions

With the UI installed, four actions jump out to me immediately. I’ve circled them below.

Clear All Posts

Add User (therefore delete user too)

Delete Post

Add Post

Other actions are visible by interacting with the UI, “update post”.

We’re going to use jQuery’s powerful event engine to pick up on each of these interactions, and capture the data related for use in the database. If you quickly open footer.php and look at line 26, you’ll notice each link (button) has 3 sets of data: data-modal, data-action, and data-id.

With jQuery, we can grab this very easily so we know (in this case) which modal box to open (if any), which action is being called, and what the ID of the item being manipulated is. Let’s quickly look at the data structure and type of users and notes.

The data structure of Users and Notes

To keep it simple, a user will simply be included by their email address. That means a User exists of:

An ID (integer)

An Email Address (string)

Posts are simply titles of WordPress posts, broken down to:

An ID (integer)

A note (string)

As you can see, the data object is basically identical, which simplifies things for us a little bit. Here’s what our JSON data that gets passed to the server will look like:

Getting stuck into the AJAX Requests

Now we know a little bit about the data structure we’ll be working with, we need some Javascript functions to process these requests. Open up functions.php, and jump down the file to line 63, and you’ll the comment

//WP LOCALIZE SCRIPT

Just briefly, WordPress has a function called wp_localize_script() that is a helper for multilingual sites. Why does that matter to us? It’s primary purpose is to pass on a language identifier to scripts through the form of a variable attached to the window.

We can use this variable to make the wp-ajax file location available to our scripts, so we have the correct URL to post AJAX requests to. Go ahead and replace the comment with this.

Processing AJAX Requests

Very quickly, we’re going to create our first Javascript function: Processing AJAX requests. Since I’ve packaged jQuery into the starter theme, we’ll be using jQuery’s $.post function to send requests to the server. Once we start detecting actions from the user (next section), we’ll use this function to send the data we collect from the user.

successfulRequest() takes a variable ‘jsonResponse’, which is what we recieve back from the server. When we get to the PHP, we simply echo what we want to come back in this variable, and this function picks it up.

For now, it will just make a browser alert that tells you the AJAX Request has been sent.

But what is all this useful for?!

Aha. These functions don’t do anything yet, but now they’re in place we’re going to use them to handle UI Interactions. The next function we’re going to create is actually already half there.

Handling UI Actions

On line 55 of main.js, you’ll see the function ‘actions’. At present, this isn’t active, and currently only hides the modal boxes at the bottom of the page in the theme. Go up to line 7 where the comment

//actions call

resides, and replace it with

Notes.actions();

Since this is in the init function (which gets called at the very bottom of main.js once the page has loaded), if you refresh the page the modals will be hidden.

Detecting User Interactions

The “actions” function we’re going to write is to detect when the user clicks an action button. It will collect all the neccessary data, then check if a modal window is required. If it’s not, it will fire off an AJAX request. If it does, it will open up the modal window that relates to the action (dictated by the data-modal attribute we saw earlier).

If you’re familiar with jQuery, you’ll know what this does. The “.on()” function tells jQuery to call the following function every time the ‘.action’ class (our action button) is clicked.

e.preventDefault() stop the URL changing.

The following four variable declarations pick up all the data we need to process the request.

It specifies the “action” that will be executed on the server as “notes-action-called”. The Modal will either be empty (in the case where no extra input is required), “yn” when a yes/no confirmation is needed, or “invite” in the case of adding a new user to the app. It then builds the data into a JSON object.

The conditional first checks if a modal is required. If not, it then passes the previously built data off to the function we created earlier that processes requests.

Go ahead and refresh your WordPress site, and then click the delete or add icon. You’ll be alerted that your request has been sent! Sweet!

Now we need to handle the else statement, when a modal is required. replace the

} else { //if a modal is required }

conditional with this one.

} else if ( modal != "" ){
Notes.openNotice(modal, data);
}

This checks if a data-modal attribute is present, and if it is then it passes the modal type and data object to the “openNotice” function.

This firstly hides any modals that are visible, and destroys any data attached to it.

It then centres the modals, another function pre-built for you. Finally it finds the modal with the class (specified by the action button’s data-modal attribute) then attaches our data to it. This last step is important as there’s no other way to pass on data to the next event (confirmation or entering an email address to invite or cancel) to then send to the server.

Save your main.js, and refresh the site. Then click an action that requires a modal, i.e. “add user” or “clear notes”. You’ll get a nice little modal window popping up pre-coded courtesy of yours truly.

The yes/no modal window.

Sending Requests Based On User Interaction

The last piece of the puzzle is to pass forward requests to processRequest() based on user input into the modals, i.e. a user enters an email address into the invite modal or presses yes on the confirmation one.

That comes in the form of UISendRequest(), a function that listens to the user response on a modal, grabs the data we previously attached to the modal, and then shoot it off to processRequest().

On line 8 of main.js, you’ll see another call commented out.

//UISendRequest call

Modify this similar to line 7, making a call to the UISendRequest function inside init().

Notes.UISendRequest();

Now that it’s being called, we need to actually write the function! Line 80 is another comment, of which we need to replace with a function.

This function binds to the click event of the “.go” button and the “.cancel” button. These reside in our modals in footer.php, on line 5, 6 and 12. It looks for the data attached to the modal that the action was called from, processes the request, and then closes the modal and destroys attached data. Cancel closes the modal and destroys the data attached.

Save, and go back to the site and refresh it. Remember how we put console.log() into the processRequest() function? Here is where it comes in handy. If you’re not sure how to bring up your browser console, stackoverflow has a good page to teach you.

The console is basically a log for JavaScript, and any other errors that get spat out by your website’s requests. The function console.log() puts whatever is in between the brackets into the console. Since we put the data variable in there, any time processRequest() gets called it’s going to log the data passed to it.

Here, in the console you can track the actions I’ve taken in the UI.

The first thing I did was confirm I wanted to clear all notes. We only need the action for this, as it will act as a blanket delete.

The second thing I did was attempt to update the post “Hello World!”. You can see the data-action, data-id and the text to update has been passed to processRequest().

The last thing I did was attempt to invite a user to the app. You can see in the console though, there is no email address. This is vital to pass to processRequest, as in the WordPress code we use it to register a new user!

That can be fixed with two lines of code. Before sending the request, it should checks if the modal is an invitation modal and picks out the email address, then adds it to the data variable. Put this right before the Notes.processRequest() line in the UISendRequest() function.

Great. That’s all the Javascript we need for now. We’ll look at it again later when dealing with responses from the server, but right now it’s time to accept the AJAX Requests.

At Long Last, Interacting With WordPress

Right now, the script pings WordPress with the data we’ve collected, but WordPress doesn’t know what to do with it.

Remember how we pass the data-action through the AJAX request? Now is where it comes in handy. As it turns out, an action is the only parameter that WordPress requires to process an AJAX request. We use the action as a hook, to attach our PHP functions too. So the hook

add_action( 'wp_ajax_notes-add-user', 'notes_add_user' );

Will respond to the “notes-add-user” AJAX request. Cool huh? That of course means, a PHP function called notes_add_user() needs to exist.

Before we dive into that though, we need pre-built and consistent response to send back to the Javascript when the PHP code has run. $fail will simply respond with a failed action (i.e. something went wrong in the WordPress code). generate_response(), however, accepts 3 arguments that get passed back to the javascript.

These are two utility functions, and they serve a very important purpose. Notice the json_encode() function. By passing an array as the first argument, and JSON_FORCE_OBJECT as the second, our PHP response gets translated back to JSON for our javascript to interpret.

Secondly, does anything here look familiar? The structure of our response is identical to the structure of our request: action becomes message, id and text remain the same. Whilst it is not 100% necessary to mimic the structure, it keeps things clean, simple, and understandable. Especially when dealing with the response from WordPress and translating it to UI changes (so the user can see what has happened).

Authentication and Failed Responses

For our actions, we want to make sure the current user is actually allowed to do the things we’re asking. For example, if the user is trying to add user, they must have the capability to use wp_insert_user(). The helper function current_user_can() allows us to check this. I’m going to go ahead and flesh out all our actions, along with their AJAX hooks. Add all this below the generate_response() function we just built.

That’s a lot of code to digest, and at present it actually does nothing for us. As you can see though, we have a PHP function and a hook to match every action our app allows.

Note: the extract($_POST) function is absolutely vital. It extracts our data package into variables for us, available as $action, $id and $text.

Another thing that is important to know, is that these hooks are only called if you’re logged in. You should be logged in, but we’ll force login later on to make sure anybody trying to post is logged in and has permissions to post.

Finally, the easiest mistake to make with this is actually including these functions in your theme! Open up functions.php, and go to the bottom. Replace the //INCLUDE AJAX ACTIONS comment with an include_once() function. Don’t forget this! Otherwise you’ll get empty responses forever and you’ll never know why.

include_once(ajax-actions.php);

Adding a user

Funnily enough, our add-user action is the most complex of them all. The reason being we have to perform a number of actions:

Generate a user name based on their email

Check if the user exists already

Generate a random password

Create the new user

Set their role to ‘Editor’ so they have permissions to add, edit and delete posts

That’s quite a lot to digest, but if you follow the points above you can see what happens.

The important thing to note is the generate_response() function. Here we pass the success message ‘user-added’, the new user’s ID, and finally their email address to be added to the UI on the fly. It is also what will show up in your console upon recieving a response from WordPress.

Save that, and go ahead and invite a user. In the screenshot below, you can see me requesting the user to be added, and then getting a response back saying that the user has been added, along with their email address and newly assigned ID. Cool!

This sort of request and response has one last puzzle piece to make the full loop in the diagram from the start of this post. Translating the response from a JSON object recieved from WordPress into a change in the UI that a human can recognise.

If you refresh the page, your newly added user will show up in the “users” menu, which is cool. But we want this to happen without having to refresh!

Handling the response

By now, you can tell that each action has 3 parts. Firstly, it sends the request. This is generic for all actions. Once the action is recieved, it has a WordPress function to do the heavy lifting. Upon return, it needs a function that translates the response.

Since the data is returned to the Javascript function successfulRequest(), that’s where we’ll handle the response.

If you’re adept at PHP, you’ll understand the switch/case loop well. Fortunately Javascript has a switch function as well, and we can switch on the message receieved back from the server to perform different tasks.

Head back to main.js, and go to line 103 where successfulRequest() is. Modify like so:

Firstly, we translate the returned JSON response into jQuery readable JSON using parseJSON().

We then console.log() the message coming back, for our convenience.

Now for the meaty part. We use switch to switch through this message, and apply javascript accordingly. Obviously, we test for the case of ‘user-added’, and then console.log() that the action was successful.

The next 5 lines are setting up a Mustache template, ready to be inserted into the menu (remember I set up these templates so we can focus on the JS and PHP. They are in footer.php if you’re curious).

The next line checks if the list placeholder ‘No users! Add some!’ is present, and if it is, delete it.

Finally, we append the new user to the user list using a Mustache function, render, which spits out the template along with the data we’ve passed to it.

Save that, head to your site, and refresh. Click the Users list, and then click add new user. Input an email address, and select ‘invite’. You’ll magically see the new user get added to the list!

If you visit the wp-admin section of your site, and select “users” you’ll also see all the users you’ve added. All without touching wp-admin!

This shows the power of AJAX requests combined with WordPress’s wp-ajax.php file.

But what about the rest of the actions?

You’re right. There are still 5 actions to be catered to.

Instead of holding your hand through them all, I’m going to show you the code for each action split into the WordPress code, and the main.js code. Simply add them in as you go. There will be short explanations.

If something goes wrong with your code, make sure your switch/case function in main.js is formatted properly. Otherwise, see you on the other side!

Simply grabs the ID, uses wp_delete_post() to delete it, and if it was successful, send a response back with the ID of the post to destroy.

main.js

case "post-deleted" :
$('#post-' + response.id).remove();
break;

Gets the response, and removes the assosciated element based on the ID.

And the rest is history!

If you’ve gotten this far, well done. You now have a fully functioning notes app where you can take, update, delete, or delete all notes, as well as invite and remove users.

Although this is a simple application, you can imagine the power you’d have with more complex data structures, custom post types, and so on. If you have any questions, don’t hesitate to ask now.

Force Authentication

One thing is missing from our app. Forced Authentication. Sure, people would be able to publically view the app, which if you’re ok with stop now. But, if you want to force people to log in to be able to see and edit it, we’ve got a couple of extra lines of code to throw into functions.php.

It consists of 3 parts really. Firstly, force login. Secondly, redirect to home instead of wp-admin to bypass it completely. And thirdly, change the style of the login page to resemble anything but WordPress.

Force login

Here’s a really handy snippet for you. It goes at the bottom of functions.php in your theme.

What this does, is get your current session info. If no user ID is returned (i.e. you’re not logged in), and you’re not on the login page already, send you to the login page. Go ahead and test this, if you log out and try to access any page you’ll get booted out.

Login redirect

Once the user logs in, we want to drop them on the home page of the site, not wp-admin. The following snippet does exactly that.

Extra credit

There are a number of things we could do to further augment our notes app, but I don’t have time to cover them.

Using WP Nonces for security

Auto refresh of notes

Know when other users are online

Validation

Using the return button to fire actions

The possibilities are endless! Go ahead and try to do them.

WordPress to Power an App

As you can see, WordPress is perfectly capable of powering apps. Despite this being a small-scale app, you can imagine the endless possibilities with custom post types, custom taxonomies, custom fields, and basically anything related to content management.

I hope I’ve given you the building blocks here to create something more. If you do build something, please post it below! I’d love to see what you come up with.

Very impressive what you’ve managed to accomplish here. How would you go about adding the ability to create nested notes or categories within the App?

Also would it be possible to add the last modified time/date and user who modified each note? I can see some simple project management uses here, with a much friendlier interface than what you typically see.

I believe using revisions, it would be possible to deal with the last modified issue you bring up. You’d have to look into whether wp_update_post() records revisions, and if not how to do so.

Nested notes, I believe you’d have to make a hierarchical custom post type. You could, however, add a custom field to posts that holds the post parent and post child IDs, and use them to spit out the visual hierarchy on the front-end.

I agree, it would be great if there was a plugin that dealt with all the db syncing issues so you could use backbone properly on the website.

Unfortunately, it doesn’t exist. The js-php-db route is a good leg up though, and is good for teaching the basic idea that JS should handle live events.

Sure. But a lot of people would be afraid of / don’t have the time to learn an entirely new framework. It’s no lie WordPress is easy to use, and it can indeed be used for apps. So why not? With the JSON API, there’s even more reason it can be the back end to a web app.

I would much rather override the default query with one that only fetches posts from a specific user. Doing it the way you list above would have issues with pagination. Consider:

* page-size 20 posts.
* all twenty posts are after 1/1/1970
* author is really old and last posted in 1969

with this scenario the loop will happily loop through all twenty posts and not display each one in turn because they’re not the author’s who’s viewing the page. This leaves the author with a blank page, and a “go to page 2” paginated link.

Nice post!
I just recently created a webapp using wordpress. Actually I created a site with an alternative theme for mobile users which made the site into an app. I think that it was a great solution for a company seeking both since it allows them to have a single administration for both versions.. a strong point for developing apps using wordpress.

Anyway, I think it’s noteworthy that you can create a nonce for the ajax call to make it more secure. wp_create_nonce() and use it for the security parameter of the ajax-call. I saw that you posted about it under “extra credit” but really it’s such a simple thing to do that it should be an obvious thing in all wordpress ajax calls.

Another thing which I think could be an “extra credit” thing would be to not let post_content go to waste but utilize it as a “description” for the note which could appear on mouseover or perhaps mouseclick.

Excellent suggestions. It is simple, but the post was already 5k words long and I didn’t want it to drag on longer. Totally agree with wp_content, it could be utilized much the same way as it is in the workflowy.com app.

Totally agree with the single administration purposes — nearly all my client websites have a jQuery Mobile counterpart that uses the same content as the desktop app. They love it!

As a matter of fact I already built a small web application using WordPress which was initially built using a PHP MVC framework (Yii).
It was a complete headache to follow up and I consider it is complicated to maintain an application with such frameworks (I also tasted CakePHP, CodeIgniter and Symphony), but using WordPress as a development platform is a complete piece of cake to build applications from scratch and maintain them.

Agree. I did the same trip, using codeigniter. A found it a great tool, but all necessary things what i had to code, comes with wordpress. I’ve built a single page app with backbone and wordpress:https://github.com/iamzozo/messageflow

Backbone is a bit tricky for me, but wordpress boost the development to get it done!