25 Dec 2005

WordPress Ajax Commenting revisited

NOTICE: This development is now part of K2 and have been moved to K2. You can get the latest code from K2 SVN.

For those that been wondering how my commenting system is submitting comment without reloading the whole page, the answer is AJAX commenting. Please take note that it’s not a WordPress 2.0 feature (up until now I guess). WordPress theme like K2 and Squible already bundle this feature into their theme.

There’s 2 ways that you can implement AJAX commenting into your WordPress theme, either you download K2 or Squible or hack your current theme so that it can support this awesome feature. Porting this hack is easy like sticking fish into a pond even without knowing any PHP knowledge and the only thing important is that you know the basic function of WordPress templating system.

Can’t really confirm the actual hack written by whom, but listed below is the known individuals that I learn from on how to port AJAX commenting system into any WordPress theme:

  1. Nico from siriux.net
  2. K2 Binary Bonsai by Micheal and Chris J Davis
  3. Squible by Theron Parlin

How to implement AJAX Commenting in your current WordPress theme

Quick note that this method is tested on WordPress Default theme (Kubrick).

  1. Backup your current theme.
  2. Download ajax-comment.zip (modified version from K2) zipped file. There are 1 important file and 3 JavaScript to be downloaded. For this tutorial, I’m using scriptalious 1.5.0 final library. As explain by Nico from siriux.net,

    comments-ajax.php handles the AJAX requests and acts just like wp-comments-post.php from WordPress. ajax_comments.js is the JavaScript part that sends AJAX requests and updates the page. You have to adjust this file to match your style ids! And the comments ol tag must be present for this to work, even if it’s empty.

    prototype.js is a JavaScript framework that aims to ease development of dynamic web applications. effect.js handles all the effects.

  3. Place the comments-ajax.php file inside your current WordPress theme directory. For example: /wp-content/themes/your_theme/
  4. Create a new folder named js inside your WordPress theme folder. For example: /wp-content/themes/your_theme/js/
  5. Place the 3 javascript, ajax_comments.js, prototype.js.php and effect.js.php library into the js folder.
  6. Open header.php, somewhere before <?php wp_head(); ?>, insert this code
    <?php if (is_single() and ('open' == $post-> comment_status) or ('comment' == $post-> comment_type) ) { ?>
            <script type="text/javascript" src="<?php bloginfo('template_directory'); ?>/js/prototype.js.php"></script>
            <script type="text/javascript" src="<?php bloginfo('template_directory'); ?>/js/effects.js.php"></script>
            <script type="text/javascript" src="<?php bloginfo('template_directory'); ?>/js/ajax_comments.js"></script>
    <?php } ?>
    
  7. Open comments.php, find <ol class="commentlist"> and replace that line with <ol class="commentlist" id="commentlist">. Notice that we add an additional id="commentlist".
    Take note that most of WordPress theme that I tried or those themes that made for public download, uses ordered list with class commentlist for displaying submitted comments. So there’s 99% posibility that your theme is one of theme using the same tag with the same class.
  8. This should be tricky. In the same file, find <?php if ($comments) : ?>. Make sure that <?php if ($comments) : ?> is below <ol class="commentlist" id="commentlist"> at any cause. Example:
    <ol class="commentlist" id="commentlist">
    <?php if ($comments) { ?>
    

    In a normal WordPress theme, <?php if ($comments) { ?> is on top of <ol class="commentlist">. As a result, this won’t work and the submitted comment will not be display and load in real time viewing. Therefore, <ol class="commentlist" id="commentlist"> must always be on top of <?php if ($comments) { ?>.

  9. Somewhere before the Reply Form find:
    <?php else : // this is displayed if there are no comments so far ?>
    
      <?php if ('open' == $post->comment_status) : ?>
                    <!-- If comments are open, but there are no comments. -->
    
             <?php else : // comments are closed ?>
                    <!-- If comments are closed. -->
                    <p class="nocomments">Comments are closed.</p>
    
            <?php endif; ?>
    

    Take note that this line of code may be different from your current theme. This is because some of WordPress public released theme does not include some of the if else statement for no comment and comment closed. Replace those lines with:

    <?php else : // this is displayed if there are no comments so far ?>
    <?php if ('open' == $post->comment_status) : ?>
    <!-- If comments are open, but there are no comments. -->
    <li id="hidelist" style="display:none"></li>
    </ol>
    <p id="nocomment">No comments yet</p>
    <?php else : // comments are closed ?>
    <!-- If comments are closed. -->
    <li style="display:none"></li>
    </ol>
    <p>Comments are closed.</p>
    <?php endif; ?>
    

    Notice the additional <ol> end tag and hidden <li> tag.

  10. In comments.php, find <?php if ('open' == $post->comment_status) : ?>. Before OR after that line, put this code
    <div id="loading" style="display: none;">Posting your comment.</div>
    <div id="errors"></div>
    

    The first line will indicate that the comment is currently in posting state and the second line is use to indicate any sorts of error like an empty required field. Probably I will include on how to customize both of this message to suit your current theme. Take note that the id’s must matched the one in your ajax_comments.js.

  11. In comments.php, find and replace:
    <form action="<?php echo get_option('siteurl'); ?>/wp-comments-post.php" method="post" id="commentform">
    

    to:

    <form id="commentform" action="<?php echo get_option('siteurl'); ?>/wp-comments-post.php" method="post" onsubmit="new Ajax.Updater({success: 'commentlist'}, '<?php bloginfo('stylesheet_directory') ?>/comments-ajax.php', {asynchronous: true, evalScripts: true, insertion: Insertion.Bottom, onComplete: function(request){complete(request)}, onFailure: function(request){failure(request)}, onLoading: function(request){loading()}, parameters: Form.serialize(this)}); return false;">
    

    This code is borrowed from K2 theme and should be in one line. With this line of code, it’s possible even your browser JavaScript is disable, the comment will still be send using the normal comment post. As a result, your visitor will have an option between AJAX commenting or normal comment post.

  12. This is optional. Finally check whether your input submit button have or uses id="submit".

    If not, please insert id="submit" into that line. Example:

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

    Some WordPress theme replace that value with their own id and some of theme doesn’t even have that id. For example theme Blix does not use id="submit" in their input tag. The id="submit" must be included so that the AJAX commenting will work perfectly.

  13. Save and close all file.
  14. Make sure that the JavaScripts files are loaded when viewing single entry posting. Test and see whether it works.

Additional Note

  • AJAX commenting will not work if the comment is inside definition list. An example theme that using definition list is Regulus from Binary Moon.
  • In order to make the comment numbering increment properly, you need to remove <?php $count++; ?> and uses the standard ordered list.
  • Your comments.php won’t be a valid XHTML unless you put a hidden nested list inside the ordered list, example <li style="display:none">No Comments</li>.But as a result, the first comment will be count as 2 but will change to 1 if the page is reloaded again. If you don’t care about XHTML validation, then you should probably ignore the empty ordered list. This is because we change the placing of <ol class="commentlist" id="commentlist"> on top of <?php if ($comments) { ?>.

    UPDATE: Refer to step 9 and download ajax_comments.js revision 2.4.

  • An older prototype and script.alicio.us library is available if you don’t want to use the final release. The file size are a bit smaller. Take note that this file is originally taken from K2 file and the script does not cover in this tutorial.
  • For those that having problem copy pasting the codes, please view or download the ajax commenting addon codes in txt format.
  • nocomment, hidelist, errors and loading are the element id’s assigned uniquely to ajax comment. You should not use any of these id’s in your theme or your stylesheet to avoid conflict with ajax commenting.
  • To hide the comment edit link from visible to user that is not logged in, find:
    <?php edit_comment_link('e','',''); ?>
    

    and replace with:

    <?php if ( $user_ID ) { ?><?php edit_comment_link('e','',''); ?><?php } ?> 
    
  • Spam Karma 2 compatibility code changes:

    comments-ajax.php, line 61 change from:

    wp_new_comment($commentdata);
    

    to:

    $new_comment_ID = wp_new_comment($commentdata);
    

    comments-ajax.php, line 72 change from:

    $comment = $wpdb->get_row("SELECT * FROM {$wpdb->comments} WHERE comment_ID = {$wpdb->insert_id};");
    

    to:

    $comment = $wpdb->get_row("SELECT * FROM {$wpdb->comments} WHERE comment_ID = " . $new_comment_ID);
    
  • There seems to be a bit of confusion here. I didn’t say that you MUST use ol tag(ordered list). You can use either unordered list or ordered list. As long as it’s a nested list. There’s also a way to make this work inside only a div but that’s a different story to tell.

You are free to view this page source code for clearer view. But certain part of the code placing has been heavily modified. But I hope you still get the idea.

Additional Bonus

Below are some random selected themes with only the changes files.

Plugin compatibility

Below are some comment related plugin known to be compatible with AJAX commenting:

  • LiveCommentPreview by Jeff Minard and Iacovos Constantinou. You have to put extra line of code inside function commentAdded line 4 ajax_comments.js to hide the preview comment on submit.

    Before Element.hide('errors'); add Element.hide('commentPreview');.

  • Quote Comment by Viper007Bond. For nested quote fix, please download Quote Comment V2.0.

Updated Files