Disqus's commenting system is one of the most popular free blog plugin's in the world right now. It allows blog users to log in using various social media services such as Facebook and Twitter, and offers a bevy of tools and comment moderation features. Most of the popular open source blogs (now including Galaxie Blog) have optional built in Disqus integration. However, what if you as the developer want to implement Disqus into your own custom software or blog? This article will show you a way to use the Disqus API key to build your own custom recent comments Disqus widget.

Do you really need your own custom Disqus Recent Comments Widget?

A recent comments widget is a tool that allows blog owners to show the most recent comments on a page. If you're just using Disqus on a static site that does not contain all of the blog entries, you might not need to roll your own custom recent comment widget. And, even if you do have a page that contains all of the blog entries, you may not need a custom widget- Disqus already provides one. To incorporate it, all that you need to do is replace the 'gregorys-blog' string with your own Disqus Blog Identifier (also known as the blog short name) like so:

view plain about
1<script type="text/javascript" src="https://gregorys-blog.disqus.com/recent_comments_widget.js?num_items=10&hide_avatars=0&avatar_size=40&excerpt_length=100"></script>
This is a basic widget, and it contains nearly everything that you may need. My code falls back to this approach in Galaxie Blog when the blog owner does not paste in his own API Key. However, it is not flexible. It is what you see is what you get, and I wanted to blend the recent comment widget with Galaxie Blogs themes, and needed other things, such as having to use the Disqus API to have my own statistical reporting. I'm a stickler for design- I personally determined from the outset that I need roll my own Disqus recent comments widget, and I'll share my approach...

Building your own Disqus Recent Comments Widget

  1. First, you will need to obtain a Disqus Blog Identifier (aka Blog Short Name) and a Disqus API Key. If you don't already have these keys, the following articles should help you in getting these:
  2. The code below is the style sheets that I developed for Galaxie Blogs recent comments. There is nothing interesting to note here but I am sharing to give you a starting point:

view plain about
1<!--- Styles for disqus --->
2<style>
3    .userProfile {
4        margin: 15px 0;    
5        list-style-type: none;    
6        clear: both;
7    }
8
9    img.disqusAvatar {
10        width: 64px;
11        height: 64px;
12        float: left;
13        position: relative;
14        z-index: 99;
15        border: 0px;
16        margin: 0px;
17        /* The padding needs to be uniform, otherwise the avatar circle will be elongated */
18        padding: <cfoutput>#avatarPadding#</cfoutput>;
19        -moz-border-radius: 50%;
20        -webkit-border-radius: 50%;
21        -webkit-box-shadow: 0 1px 2px rgba(0,0,0,0.2);
22        -moz-box-shadow: 0 1px 2px rgba(0,0,0,0.2);
23        box-shadow: 0 1px 2px rgba(0,0,0,0.2);
24        overflow: hidden;
25    }
26
27    #disqusCommentDiv a {
28        overflow: hidden; /* Prevent wrapping */
29    }
30
31    #disqusCommentDiv p {
32        display: inline; /* Prevent wrapping */
33    }
34
35    #disqusCommentPanel a {
36        overflow: hidden; /* Prevent wrapping */
37    }
38
39    #disqusCommentPanel p {
40        display: inline; /* Prevent wrapping */
41    }
42
43    .comment-avatar img {
44        width: 100%;
45        height: 100%;
46    }
47</style>

  1. The real magic happens in the javascript below. I'll try to walk you through some of the more interesting tidbits
    1. The getRecentDisqusComments function makes a call to the Disqus API invoking the listsPosts method
    2. Additionally, the related=thread argument is appended to the URL string. This argument allows us to get the URL and Title of the post. Without this argument, we would need to make another call the threads list method, which is frankly a nightmare1.
    3. We are passing our Disqus keys in the Ajax post
    4. The getDisqusCommentsResponse callback method retrieves the data, and writes out our custom HTML. Here, I am using my own custom class definitions to make the widget blend in with my own themes.
    5. The isOdd method assists creating alternate the colors of each row.
    6. The timeSince method is used to append a string to tell the viewer when the comment was made (ie '20 seconds ago').
    7. Finally, the truncateString method is used to truncate the comment string.

view plain about
1function getRecentDisqusComments(){
2
3    // Submit form via AJAX.
4    $.ajax(
5        {
6            type: "get",
7            url: "https://disqus.com/api/3.0/forums/listPosts.json?related=thread",
8            data: {
9                // Passing my own keys.
10                api_key: "<cfoutput>#application.disqusApiKey#</cfoutput>",
11                forum: "<cfoutput>#application.disqusBlogIdentifier#</cfoutput>",
12
13                limit: "<cfoutput>#numComments#</cfoutput>"
14            },
15            // jsponp is supported as well.
16            dataType: "json",
17            cache: false,
18            success: function(data) {
19                setTimeout(function () {
20                    // Callback function
21                    getDisqusCommentsResponse(data);
22                // The timeout ensures that the data will be available to the callback function.
23                }, 250);
24            }
25        }
26    );
27}//..function getRecentDisqusComments(){
28
29function getDisqusCommentsResponse(data){
30    var html = "";
31    // Loop through the json structure.
32    for (var i = 0, len = data.response.length; i < len; i++) {
33        // Isolate our post (or entry).
34        var post = data.response[i];
35        // Set a current row value from our index. I need a whole number to determine the alternating row color. I could just use [i]+1, but I am setting this for readability.
36        var row = parseInt([i]);
37        // Get the data for the post.
38        var authorName = post.author.name;
39        var authorProfileUrl = post.author.profileUrl;
40        var authorAvatarUrl = post.author.avatar.cache;
41        // We need to strip the HTML out of the comment. It has links that are not useful and will take up our space.
42        var comment = stripHtml(post.message);
43        var commentPromoted = post.isHighlighted;
44        var approved = post.isApproved;
45        // Get the timestamp and convert it into a proper js date object.
46        var created = new Date(post.createdAt);
47        // Find the link to the actual article. Note: for this to work, you must have related=thread appended to the ajax link (ie https://disqus.com/api/3.0/forums/listPosts.json?related=thread).
48        var pageLink = post.thread.link;
49        var pageTitle = post.thread.title;
50
51        // Create the HTML. We will try to keep this nearly identical to the recent comment widget, but put in our own kendo classes here.
52        // Crete the table on the first row.
53        if (row == 0){
54            html += '<table id="disqusComment" align="center" class="k-content fixedPodTableWithWrap" width="100%" cellpadding="0" cellspacing="0">';
55        }
56        // Create the row and alternate the k-content and k-alt class.
57        if (isOdd(row)){
58            html += '<tr class="k-alt" height="50px;">';
59        } else {
60            html += '<tr class="k-content" height="50px;">';
61        }
62        // After the first iteration, create a row with a border. Javascript arrays (which is our 'row') start at 0.
63        if (row == 0){
64            html += '<td align="left" valign="top" class="userProfile">';
65        } else {
66            html += '<td align="left" valign="top" class="border userProfile">';
67        }
68        // Wrap the avatar with the authors profile link
69        html += '<br/><a href="' + authorProfileUrl + '" aria-label="Profile for ' + authorName + '" rel="nofollow noopener">' + authorName;
70        // Place the avatar into the cell and close the anchor link.
71        html += '<img class="disqusAvatar" src="' + authorAvatarUrl + '" aria-label="Profile for ' + authorName + '"></a><br/>';
72        // Add the comment. The comment is already wrapped with a paragraph tag.
73        html += truncateString(comment, <cfoutput>#lenComment#</cfoutput>) + '<br/>';
74        // Create the HTML to insert into the page title.
75        html += '<a href="' + pageLink + '" aria-label="' + pageLink + '">' + pageTitle + '</a> - ';
76        // Add the timestamp to quickly identify how recent the post is.
77        html += timeSince(new Date(created)) + ' ago<br/>';
78        // Close the cell and the row.
79        html += '</td></tr>';
80        // Close the table on the last row
81        if (row == <cfoutput>#round(numComments-1)#</cfoutput>){
82            html += '</table>'
83        }
84        // Append the html to the page.
85        $(document).ready(function() {
86            $("#recentCommentsDiv").html(html);
87            $("#recentCommentsPanel").html(html);
88        });
89
90    }//..for (var i = 0, len = data.response.length; i < len; i++) {
91
92}
93
94// Helper function to determine if the number is even or odd. This is used to create alternating row colors.
95function isOdd(num) {
96    return num % 2;
97}
98
99function stripHtml(html){
100    html.replace(/<[^>]*>
?/gm, '');
101    return html;
102}
103
104// Function to write out the time since the post.
105// Source: https://stackoverflow.com/questions/3177836/how-to-format-time-since-xxx-e-g-4-minutes-ago-similar-to-stack-exchange-site    
106function timeSince(date) {
107 var seconds = Math.floor((new Date() - date) / 1000);
108 var interval = Math.floor(seconds / 31536000);
109
110 if (interval >
1) {
111    return interval + " years";
112 }
113 interval = Math.floor(seconds / 2592000);
114 if (interval >
1) {
115    return interval + " months";
116 }
117 interval = Math.floor(seconds / 86400);
118 if (interval > 1) {
119    return interval + " days";
120 }
121 interval = Math.floor(seconds / 3600);
122 if (interval > 1) {
123    return interval + " hours";
124 }
125 interval = Math.floor(seconds / 60);
126 //alert(interval + ' minutes date: ' + date);
127 if (interval > 1) {
128    return interval + " minutes";
129 }
130 return Math.floor(seconds) + " seconds";
131}
132
133truncateString = function(str, length, ending) {
134    if (length == null) {
135        length = 100;
136    }
137    if (ending == null) {
138        ending = '...';
139    }
140    if (str.length > length) {
141        return str.substring(0, length - ending.length) + ending;
142    } else {
143        return str;
144    }
145};
146
147// Call the method to populate the recent comments.
148getRecentDisqusComments();

If you have any questions, don't hesitate to ask.

Happy commenting!

Further Reading: 1Raymond Camden has an excellent article at https://www.raymondcamden.com/2014/03/21/Example-of-a-JavaScript-Disqus-Recent-Comment-Widget. I wished that I had read this earlier before going down my own rabbit hole. To get the related post, I initially tried to call the thread list method (at https://disqus.com/api/3.0/threads/list.json) within a nested ajax post. My initial code was just... ugly. Finally, I stumbled upon this article and found out that I could simply use the related=thread argument to attach the comment to a thread.