How To Build A Real-Time Commenting System – Smashing Magazine

Smashing Magazine

Categories:

You know, we use ad-blockers as well. We gotta keep those servers running tho’. Did you know that we publish useful books and run friendly conferences — crafted for pros like yourself? E.g. our upcoming SmashingConf Barcelona, dedicated to clever front-end technics and design patterns.

How To Build A Real-Time Commenting System

  • By Phil Leggetter
  • May 9th, 2012
  • CSSHTMLHTML5
  • 74 Comments

The Web has become increasingly interactive over the years. This trend is set to proceed with the next generation of applications driven by the real-time Web. Adding real-time functionality to an application can result in a more interactive and engaging user practice. However, setting up and maintaining the server-side real-time components can be an unwanted distraction. But don't worry, there is a solution.

Cloud hosted Web services and APIs have come to the rescue of many a developer over the past few years, and real-time functionality is no different. The concentrate at Pusher one , for example, is to let you concentrate on building your real-time Web applications by suggesting a hosted API which makes it quick and effortless to add scalable real-time functionality to Web and mobile apps.

Further Reading on SmashingMag: Link

In this tutorial, I'll demonstrate how to convert a basic blog commenting system into a real-time engaging practice where you'll see a comment made in one browser window “magically” show up in a 2nd window.

Why Should We Care About The Real-Time Web? Link

Albeit the Real-Time Web six is a relatively latest mainstream phrase, real-time Web technologies have been around for over ten years. They were mainly used by companies building software targeted at the financial services sector or in Web talk applications. These initial solutions were classed as “hacks”. In two thousand six these solutions were given an umbrella term called Comet seven , but even with a defined name the solutions were still considered hacks. So, what's switched?

In my opinion there are a number of factors that have moved real-time Web technologies to the forefront of Web application development.

Social Media Data Link

Social media, and specifically Twitter, has meant that more and more data is becoming instantly available. Gone are the days where we have to wait an eternity for Google to find our data (blog posts, status updates, photos). There are now platforms that not only make our data instantly discoverable but also instantly supply it to those who have announced an interest. This idea of Publish/Subscribe eight is core to the real-time Web, especially when building Web applications.

Enhanced User Expectations Link

As more users moved to using applications such as Twitter and Facebook, and the user practices that they produce, their perception of what can be expected from a Web application switched. Albeit applications had become more dynamic through the use of JavaScript, the practices were seldom truly interactive. Facebook, with it's real-time wall (and later other realtime features) and Twitter with it's activity stream centric user interface, and concentrate on conversation, demonstrated how Web applications could be very engaging.

WebSockets Link

Earlier on I stated that previous solutions to let servers instantly shove data to Web browsers were considered “hacks”. But this didn't liquidate the fact that there was a requirement to be able to do this in a cross-browser and standardised way. Our prayers have eventually been answered with HTML5 WebSockets. WebSockets represent a stardardized API nine and protocol ten that permits realtime server and client (web browser) two way communication over a single connection. Older solutions could only achieve two-way communication using two connections so the fact the WebSockets use a single connection is actually a big deal. It can be a massive resource saving to the server and client, with the latter being particularly significant for mobile devices where battery power is utterly valuable.

How are Real-Time Technologies being used? Link

Real-time Web technologies are making it possible to build all sorts of engaging functionality, leading to improved user practices. Here are a handful of common use cases:

  • Realtime Stats – The technology was very first used in finance to display stock exchange information so it's no surprise that the technology is now used more than ever. It's also very beneficial to sports, betting and analytics.
  • Notifications – when something a user is interested in becomes available or switches.
  • Activity Flows – rivulets of friend or project activity. This is commonly seen in apps like Twitter, Facebook, Trello, Quora and many more.
  • Talk – the one hundred one or real-time Web technology but still a very valuable function. It helps delivery instant interaction inbetween friends, work colleagues, customers and customer service etc.
  • Collaboration – Google docs offers this kind of functionality within its docs, spreadsheets and drawing applications and we're going to see similar use cases in many more applications.
  • Multiplayer Games – The capability to instantly produce player moves, game state switches and score updates is clearly significant to multiplayer gaming.

In the rest of this tutorial I'll cover building a basic blog commenting system, how to progressively enhance it using jQuery and eventually I'll also progressively enhance it using the real-time Web service I work for, Pusher, which will demonstrate not just how effortless it can be to use real-time Web technology, but also the value and enhanced engagement that a real-time factor can introduce.

Creating Generic Blog Commenting System Link

Begin from a Template Link

I want to concentrate on adding real-time commenting to a blog post so let's begin from a template eleven .

This template re-uses the HTML5 layout defined in the post on Coding An HTML five Layout From Scrape twelve and the file structure we'll begin with is as goes after (with some additions that we don't need to worry about at the moment):

HTML Link

The template HTML, found in index.php, has been switched from the HTML5 Layout article to concentrate on the content being a blog post with comments. You can view the HTML source here thirteen .

The main elements to be aware of are:

  • <section id="content"> – the blog post content
  • <section id="comments"> – where the comments are to emerge. This is where the majority of our work will be done

Comments Link

Now that we've got the HTML in place for our blog post and for displaying the comments we also need a way for our readers to submit comments, so let's add a <form> element to collect and submit the comment details to post_comment.php. We'll add this at the end of the <section id="comments"> section packaged in a <div id="react"> .

Comment Form CSS Link

Let's apply some CSS to make things look a bit nicer by adding the following to main.css:

Once the HTML structure, the comment form and the CSS are in place our blogging system has embarked to look a bit more presentable.

Treating Comment Subjugation Link

The next step is to write the PHP form subjugation handler which accepts the request and stores the comment, post_comment.php. You should create this file in the root of your application.

As I said earlier I'm keen to concentrate on the real-time functionality so a class exists within the template that you've downloaded which encapsulate some of the standard data checking and persistence functionality. This class is defined in Persistence.php (you can view the source here fourteen ), is in no way production quality, and treats:

  • Basic validation
  • Basic data sanitization
  • Very plain persistence using a user $_SESSION . This means that a comment saved by one user will not be available to another user.

This also means that we don't need to spend time setting up a database and all that goes with it and makes post_comment.php very plain an clean. If you desired to use this functionality in a production environment you would need to re-write the contents of Persistence.php. Here's the code for post_comment.php.

The above code does the following:

  1. Includes the Persistence.php class which treats saving and fetching comments.
  2. Creates a fresh instances of the Persistence object and assigns it to the variable $db .
  3. Attempts to add the comment to the $db . If the comment is successfully added it redirects back to the blog post. If it fails the redirection also occurs but some error text is appended to an error query parameter.

Displaying the Comments with the Blog Post Link

The final thing we need to do to have our Generic Blog Commenting System up and running is to update the blog page, index.php, to fetch and display the comments from the Persistence object.

  • Since this isn't a real blogging system we'll hard code the $comment_post_ID value to be one .
  • Include the Persistence.php class and fetch the comments from it. Comments are associated with a blog post using a unique $comment_post_ID .

Since we now have the $comment_post_ID accessible via PHP we should update the HTML for the comment form to use this value.

We now have all the comments related to the blog post referenced by the $comments variable we need to display them on the page. To do this we need to update the PHP in index.php to iterate through them and create the required HTML.

You'll notice that if the value of $has_comments is true an extra CSS class is applied to the ordered list called has-comments. This is so we can hide the list item with the “Be the very first to add a comment” message when comments are being displayed using CSS:

Now that all this is in place we have a functional blog commenting system. If you would like to begin writing your code from this basic functioning blog commenting system you can also download the code ended up to here fifteen .

Progressive Enhancement With jQuery Link

The very first step in making our blog commenting system feel less like a Web page and more like an application is to stop page reloads when a user submits a comment. We can do this by submitting the comments to the server using an AJAX request. Since jQuery is very likely the defacto standard for cross browser JavaScript functionality we'll use it here. Albeit I'm using jQuery here, I'd also like to highlight that it's a good idea to not always use jQuery sixteen . Instead, analyze your script and make a considered decision because there are some cases seventeen where you are best not to.

In an attempt to attempt and keep as much scripting (PHP and JavaScript) from the index.php file we'll create a fresh folder for our JavaScript and in there a file for our application JavaScript. The path to this pack should be js/app.js. This file should be included after the jQuery include.

Capture the Comment Form Subjugation Link

When the page is ready truss to the submit event of the form.

When the form is submitted and the handleSubmit function is called the comment data we want to send to the server is extracted from the form. There are more elegant ways of fetching the data from the form but this treatment clearly shows where we're getting the values from and the data object we are creating.

POST the Comment with AJAX Link

Within the postComment function make a POST request to the server passing the data that we've retrieved from the form. When the request is made an extra HTTP header will be sent to identify the request as being an AJAX request. We want to do this so that we can comeback a JSON response if it is an AJAX request and maintain our basic functionality if it isn't (for more information on this see Detected AJAX events on the Server eighteen ). We also define two handlers; postSuccess for treating the comment being successfully stored and postError to treat any failures.

Dynamically Updating the User Interface with the Comment Link

At this point the comment data is being sent to the server and saved, but the AJAX response isn't providing any meaningful response. Also, the comments section isn't being updated to showcase the freshly submitted comment so the user would have to refresh the page to see it. Let's commence by writing the code to update the UI and test that functionality.

If you are thinking “String up on a minute! We don't have all the data we need from the Web server to display the comment” then you are correct. However, this doesn't stop us writing the code to update the UI and also testing that it works. Here's how:

The code above does the following:

  • Within the postSuccess function we clear the form values and call displayComment .
  • displayComment very first calls the createComment function to create the list item ( <li> ) HTML as a String .
  • We then convert the HTML to a jQuery object using $(commentHtml) and hide the element.
  • The comment list item is then prepended to the comments ordered list ( <ol> ). The list also has a class called has-comments added to it so we can hide the very first list item which contains the “Be the very first to comment” statement.
  • Ultimately, we call commentEl.slideDown() so that the comment is shown in what is becoming the standard “here's a fresh item” way.

The functionality is now implemented but we want to test it out. This can be achieved in two ways:

  • The displayComment is a global function so we can call it directly using the JavaScript console of the browser.
  • We can tie to an event on the page that triggers a fake update which calls the displayComment function

Let's go with the latter and truss to the “u” key being released by trussing to the keyup event. When it is, we'll create a fake data object containing all the information required to create a fresh comment and pass it to the displayComment function. That comment will then be displayed in the UI.

Hit the “u” key a few times and see the comments emerge.

Superb! We now know that our displayComment function works exactly as we expect it to. Reminisce to liquidate the test function before you go live or you'll indeed confuse your user every time they press “u”.

Detect and Responding to the AJAX request Link

All that's left to do is update the post_comment.php file to detect the AJAX call and come back information about the freshly created comment.

Detecting the AJAX request is done by checking for the X-Requested-With header:

Once we know the request is an AJAX request we can update the code to react with an adequate status code and the data signifying the comment. We also need to ensure that the original functionality is maintained. The post_comment.php code now looks as goes after:

Key points from the above code are:

  • The $db->add_comment($_POST) call comes back the data from the added comment which is assigned to the $added variable.
  • By setting the response Content-Type to “application/json” we tell jQuery to convert the returned string into a JavaScript object. For more information on calling JSON Web services see A Beginner’s Guide To jQuery-Based JSON API Clients19 .
  • The two hundred one status code indicates a successful call and also that a resource (the comment) was created by the call.

The blog commenting system now works in a much more dynamic way, instantly showcasing the user that their comment has been posted without refreshing the page. In addition, the way the we've added the JavaScript based functionality to the page means that if JavaScript is disabled or a JavaScript file fails to explosion that the system will fallback to the standard functionality we very first implemented.

Getting Real-Time—Finally! Link

As with any “from scrape” tutorial it can take a bit of time to get to the indeed interesting part, but we're ultimately here. However, all the work we've up in has been worth it. Because we've built our commenting system up in a progressively enhanced way, plugging Pusher into it is going to be truly effortless

What is Pusher? Link

At the embark of the tutorial we said that we would use Pusher to add the realtime functionality to the application. But what is Pusher?

Pusher is a hosted service for quickly and lightly adding realtime features into Web and mobile applications. It offers a RESTful API that makes it indeed effortless to publish events from any application that can make a HTTP request and a WebSocket API for realtime bi-directional communication. You don't even need to use the APIs directly as there are server twenty (PHP, Ruby, knot.js, ASP.NET, Python and more) and client twenty one (JavaScript, iOS, Android, .NET, ActionScript, Arduino and more) libraries available in a host of technologies which means you can add realtime functionality to an app within minutes ‐ I'm certain you'll be astonished just how effortless!

Sign up for Pusher and get your API Credentials Link

In order to add Pusher-powered real-time functionality to a Web application you very first need to sign up for a free Sandbox account twenty two . After you have signed up you'll be taken to the Pusher dashboard where you'll see that a “Main” application has been created for you. You'll also see you are in the “API Access” section for that application where you can grab your API credentials.

For ease of access create a pusher_config.php file and define the credentials in there so we can refer to them later:

In your version of pusher_config.php be sure to substitute the values which being ‘YOUR_ with your actual credentials.

You should also require this in your index.php file. We should also make the APP_KEY available to the JavaScript runtime as we are going to need it to connect to Pusher.

Real-time JavaScript Link

The very first thing you need to do when adding Pusher to a Web application is include the Pusher JavaScript library and connect to Pusher. To connect you'll need to use the key which you grabbed from the Pusher dashboard. Below you can see all that is required to meet up the front-end application to Pusher.

Include the Pusher JavaScript library after the app.js include:

Add the Pusher functionality to app.js:

This very likely looks too effortless to be true, so here are the details about what the above code does:

  • var pusher = fresh Pusher(APP_KEY);

Creates a fresh example of a Pusher object and in doing so connects you to Pusher. The application to use is defined by the APP_KEY value that you pass in and that we set up earlier.

  • var channel = pusher.subscribe(‘comments-‘ + $(‘#comment_post_ID’).val());

    Channels23 provide a good way of organizing flows of real-time data. Here we are subscribing to comments for the current blog post, uniquely identified by the value of the comment_post_ID hidden form input element.

  • channel.truss(‘new_comment’, displayComment);

    Events24 are used to further filter data and are ideal for linking updates to switches in the UI. In this case we want to truss to an event which is triggered whenever a fresh comment is added and display it. Because we've already created the displayComment function we can just pass in a reference to the call to truss .

  • Sending Real-Time Events using the Event Creator Link

    We can also test out this functionality without writing any server-side code by using the Event Creator for your app which can also be found in the Pusher dashboard. The Event Creator lets you publish events on a channel through a plain user interface. From the code above we can see that we want to publish an event named “new_comment” on the “comments-1” channel. From the earlier test function we also have an example of the test data we can publish.

    Real-time PHP Link

    Again, we've proven that our client-side functionality works without having to write any server-side code. Now lets add the PHP code we need to trigger the fresh comment event as soon as a comment is posted in our comment system.

    Pusher offers a number of server-side libraries twenty five which make it effortless to publish events in addition to helping with functionality such as private channel twenty six authentication and providing user information for presence channels twenty seven . We just want to use the basic event triggering functionality in the post_comment.php file so we need to download the Pusher PHP library.

    Once you've downloaded this zip file, unzip it into the directory along with your other files. Your file structure will now look something like this:

    An event can be triggering in just a few lines of code:

    However, we need to apply a some extra logic before we trigger the event:

    • Check that the comment was added.
    • Extract the unique comment identifier from the $added array.
    • Build the text to identify a channel name for the submitted comment.
    • Trigger a new_comment event on the channel with the $added data. Note: The library automatically converts the $added array variable to JSON to be sent through Pusher.

    Therefore the utter post_comment.php file finishes up looking as goes after:

    If you run the app now in two different browser windows you'll see that as soon as you submit a comment in one window that comment will instantly (“magically”) show up in the 2nd window. We now have a real-time commenting system!

    But…, we're not done fairly yet. You'll also see that the comment is shown twice in the window of the user who submitted it. This is because the comment has been added by the AJAX callback, and by the Pusher event. Because this is a very common script, especially if you've built an application in a progressively enhanced way as we have, the Pusher server libraries expose a way of excluding a connection/user twenty eight from receiving the event via Pusher.

    In order to do this you need to send a unique connection identifier called a socket_id from the client to the server. This identifier can then be used to define who will be excluded.

    The switches we've made are:

    • A fresh function called getSocketId has been added to get the socket_id . It wraps a check to ensure that the pusher variable has been set and also that the client is connected to Pusher.
    • The handleSubmit has been updated to check to see if a socket_id is available. If it is, this information is posted to the server along with the comment data.

    On the server we need to use the socket_id parameter if it is present and therefore exclude the connection and user who submitted the comment, or pass in null if it's not:

    And as plain as that we have a fully realtime enabled blog commenting system and we only send messages to users who truly need to see them. As with the AJAX functionality the realtime functionality has been added in a progressively enhancing way, to ensure it doesn't influence on any other functionality. You can find the a demo running here twenty nine and the ended solution in the realtime commenting repository thirty in github.

    Good Real-Time App Development Practices Link

    Real-time application development shares common good development practices with general Web development. However, I thought I would share a duo of tips that can come in particularly handy.

    Use Browser Developer Contraptions Link

    When you commence doing a lot of JavaScript development the browser developer implements becomes your best friend. It's the same when adding realtime functionality to your Web app, not only because you are using JavaScript, but also because the JavaScript library you are using is likely to be doing some reasonably elaborate things internally. So, the best way of understanding what is going on and if your code is using it as expect is to enable logging which usually goes to the developer console. All major browser vendors now suggest good developer instruments which include a console:

    The Pusher JavaScript library provides a way to hook into the logging functionality. All you need to do is assign a function to the Pusher.log thirty five static property. This function will then receive all log messages. You can do what you like within the function but best practice is to log the messages to the developer console. You can do this as go after, ensuring the code it executed after the Pusher JavaScript library include:

    The code above checks to make sure the console and log function is available – it's not in older browsers – and then logs the messages along with a timestamp to the JavaScript console. This can be amazingly handy in tracking down problems.

    Check Connectivity Link

    Any good real-time technology will maintain a persistent connection inbetween the client (web browser) and the Web server or service. Sometimes the client will lose connectivity and when the client isn't connected to the Internet the real-time functionality won't work. This can happen a lot with applications running on mobile devices which rely on mobile networks. So, if your application relies on that connectivity and functionality then it's significant to deal with screenplays where the client isn't connected. This might be by displaying a message to tell the user they are offline or you might want to implement some alternative functionality.

    The Pusher JavaScript library exposes connectivity state via the pusher.connection object, which we shortly witnessed earlier when fetching the socket_id . Trussing to state switches and implementing your required functionality is fairly ordinary as it goes after the same mechanism as cording to events on channels:

    Conclusion Link

    We're eyeing real-time functionality appearing in a large number of high profile applications: some have it at the core of what they suggest whilst others use it sparingly. No matter how it is used the end purpose is generally the same; to enhance the user practice and keep users engaged with an application. By converting a basic blog commenting system into a more engaging communication platform I hope I've demonstrated that the functionality and practice can lightly be layered on existing application.

    The ease of access to this technology is a relatively fresh thing and we've only just touched the potential uses for the technology. Real-time stats, instant news updates, activity rivulets, social interaction, collaboration and gaming are just a few common uses but as more developers become aware of, and comfy with, the technology I'm certain that we're going to see some truly amazing innovation. An “Internet of Real-Time Things?”?

    Footnotes Link

    Phil Leggetter is a Developer Evangelist at Pusher. He’s been involved in developing and using realtime web technologies for over ten years. His concentrate is to help developers use these technologies to build the next generation of interactive and engaging realtime web applications. Go after him at @leggetter.

    Related video:

    Leave a Reply

    Your email address will not be published. Required fields are marked *