Since the release of WordPress 4.7 and with it wider support for the WP REST API, I’ve been working on building a starter theme that uses the REST API, Foundation and AngularJS, with the intent to release a theme that uses all three of those to the directory at the start of 2017.
Everything’s gone smoothly for the most part. There are a number of brief tutorials that go over the basics on how to get the REST API and AngularJS (or React and others) to work together to show posts and pages and what not. But what I’ve noticed is that there’s a lack of tutorials on how to do higher level things, such as threading comments, loading new posts with a click of a button or integrating theme options.
So, as I’m working through my development with the REST API and AngularJS, I’ve decided to fill that void with a couple of tutorials that should help those who need help.
This week’s tutorial is over displaying threaded comments. This is something that’s easily done in the normal WordPress, PHP way, but the REST API doesn’t necessarily have this feature built in. Instead, we’ll have to manually go through the set of comments for a post, check for parent comments, rearrange comments to get in the right order and somehow display them correctly in the page.
Sound difficult? Don’t worry, it won’t be shortly.
Now, before we get going I do want to point out that I have a starter theme on GitHub available here. It’s still a work in progress, but it’s a good place to start for anybody interested in learning about the REST API and AngularJS. It includes the code that you’re about to see in this tutorial.
Also, I going to assume that you know about the REST API and know how to work AngularJS, or at least have a basic understanding of both. If you find yourself lost in any of this, you’ll want to learn about both before continuing with this tutorial.
This tutorial will be broken down into three parts to make it somewhat digestible. The first part will discuss getting the parent comment and max depth, rearranging the comments in the array and displaying it on the page.
Sorting parent comments and getting comment depth
Before we do anything, we have to grab the comment data from the server. There’s a way you could do it , but I’m going to do it a different way. Basically, we’re going to register the comments as a field to grab from the post in the single controller. I got this code from Roy Sivian’s Angular theme, which is another great starter theme to learn from.
Place this code inside the functions.php file.
https://gist.github.com/ViewFromTheBox/5b516207dfc662205b6e4248556ff802
Before we get into the specifics, we’re going to wrap all of these functions inside a service name “SortComments”. The code below shows how to do that. Services act similar to classes/objects in JavaScript and other languages, so when calling other functions from inside the service, you’ll use this
as prefix.
https://gist.github.com/ViewFromTheBox/a5bff631f5279439b0444f06d1b7d6fe
Then inside of the service we’re going to have three functions: getCommentById, getCommentDepth and arrangeComments. This section focuses on the first two.
https://gist.github.com/ViewFromTheBox/8541f13948b5114ad760d297ab98440a
The first function is very simple and will be used to simply grab a comment object based on a given id. In the larger scope, it will be used to grab the parent comment for a comment as we loop through the array.
https://gist.github.com/ViewFromTheBox/ea294aa054de348ced68f76233cfff38
The function accepts two parameters, the comment id we’re looking for and the list of comments. It loops through all of the comments until it comes across the comment with that array and returns that comment object.
The next function gets the depth of the comment, which is to say how many comments are between the current comment and the top level comment it’s inevitably tied to. This function accepts two parameters: the comment object and the array of comments.
https://gist.github.com/ViewFromTheBox/aa749ec7188b7f4d6b97ec4895d96ebd
This will be used in the third function to grab the maximum comment depth that we’re dealing with.
Rearranging the comments
https://gist.github.com/ViewFromTheBox/30fdc96e2a2726e5a7a0ed0a4be7db72
This section deals with one function, but there are four parts/loops to it.
The first part (or loop as I will call it from here on out) simply runs through the comment array and removes any comment that has not been approved. The REST API should only output comments that have been approved, but this double checks to make sure that’s the case.
The second loop gets a bit more complicated. This loop adds an array to each comment object. This array will be populated with any child comments (or replies) to this comment. We’re also formatting the date for each comment so that Angular can read it and output it the way we want it on the front end. Next we get the depth of the comment and attach it to the comment object. Finally, we’ll check to see if that comment depth is greater than the current maximum comment depth. If it is, that becomes the max depth. If not, we move on.
The third loop is where all of the rearranging takes place. It’s a lot of code, but it’ll make sense after I break down the logic to go with it. The first for loop starts at the deepest comment depth and for any comment that matches that depth, we find its parent and attach it to the parents comment_children array. Then we move up a level and repeat the process Essentially, we’re building from the bottom.
The fourth loop goes back through the top level of the array and removes any of the comments that have been moved so there aren’t any duplicates.
Now we have to use these functions on our actual comment data.
https://gist.github.com/ViewFromTheBox/fd11d02b914d9e9255eca975b6ffdd2c
This is a truncated version of the single post controller I have. The key here is that we’re grabbing the comments from the field that we registered earlier and are now running it through the arrangeComments function. Make sure you’re injecting the ‘SortComments’ service properly and calling the arrangeComments function correctly.
At this point we have a comment array that is thread. Now we’re ready to display them on the page.
Displaying the comments
Normally, when displaying information that’s in an array in Angular, we would use the ng-repeat
attribute; however, because of the threaded nature of the comments, that won’t really do for us. Instead, we’re going to have to use recursion to display each of the comments correctly.
The code used for this section of the tutorial is modified from this tutorial by Sebastian Porto. If you want to learn more about how to display data recursively in Angular, visit that tutorial to learn more.
This section will use directives, which can be a bit confusing at first, but hopefully this will help you understand what they do.
The first thing we’re going to do it add the html in the single post template (or wherever you want it) that will more-or-less trigger the directive for us.
<collection collection='post.comments'></collection>
This is where the comments will eventually appear. Now to add the jQuery to make it all happen.
https://gist.github.com/ViewFromTheBox/154e699a8ae170b0a631b1363f84cc70
So all you need to know for this directive is that it takes the comments and loops through them. As you will see later, it will also be called for each comment to go through each child comment.
https://gist.github.com/ViewFromTheBox/7624eb6e6a7108a4d1aa9e9415195354
This directive is where it all happens. It goes through each outputted comment and applies the template or templateUrl to each comment. It’s important to note that “templateUrl” can be changed to “template” (as it is for the collection directive) and you can simply put in <li>{{member.comment_content}}</li>
if you wanted to. Or you can keep it at templateUrl and link to a more complicated comment template like I have it.
https://gist.github.com/ViewFromTheBox/ff7bc8b78dff374fa43623e7b79e1002
Another important to note that instead of comment.comment_ in the template, it’ll be member.comment_ to output the comment data.
And before it’s done, the directive adds that collection line to keep the recursive part going.
So there we have it. We now have a threaded comment structure where people can reply to others and have a discussion on each of your posts, similar to how it is in regular WordPress templates.
I hope this tutorial has helped you. Again, feel free to use the starter theme I have on GitHub as a starting point for your theme. If you have any questions, feel to ask it in comments below or drop me a line here. Next week (or the week after) we’ll look at how to load more posts on a button click.
Trying to wrap my head around WP REST API and JavaScript