« New blog feature: Hierarchical threaded comments! | Main | 娛樂直播 Interview now online! »
Tue, April 17, 2007
Hierarchical threaded comments; How I did it.
(Announced in "New blog feature: Hierarchical threaded comments!")
WARNING: Lots of technical jargon!
My blog is a MovableType blog developed by Six Apart Ltd. They also have other blog systems. They're a very smart company. You can read about their products on their web site. Like many other systems, MovableType allows you to add functionality via plugins.
One such plugin designed to implement threaded comments is called MTSimplyThreaded which I installed and experimented with. It could link comments to other comments but it couldn't produce a hierarchical comment scheme so it wasn't what I wanted.
Then I was told about MTThreadedComments. I read the documentation and it seemed to be exactly what I wanted, but it was old and apparently not compatible with my version of MovableType. Not to be dissuaded too easily, I searched for tips about running MTThreadedComments with my version of MovableType on google and I came across a couple of sites; one of them in Korean; which explained what adjustments to MovableType's code needed to be done. Strangely enough, it was the Korean site that told me exactly what I needed to know. I couldn't read the Korean but their code screen shots were self explanatory.
I examined MTThreadedComments' documentation and everything I could find on the internet. I didn't like MTThreadedComments' suggested method of responding to comments. Clicking on any 'Respond' link redirected the reader to another page with a copy of the article text or the comment text that the reader was responding to along with the comment form. This is normally ok but I don't like unnecessary page loads and wanted to come up with a more ideal (in my opinion) way of doing it. I liked the way MTSimplyThreaded worked and after analysing what data MTThreadedComments needed to work, I decided to implement a simple Ajax comment system. The investigation of MTThreadedComments and the analysis of what I wanted to do and how to do it took two full days.
What started out as a simple JavaScript script turned into something much more complicated (it's always the same), and IE's many css bugs made me reconsider my plan to implement MTThreadedComments via Ajax more than once, but I eventually finished it and I'm pretty pleased with it. I just wish that IE supported opacity (without requiring ActiveX). I can fully understand now why so many web developers despise IE. Why is it that a humongous company with unlimited resources can't make a decent (standards based) browser??? All I can say is thank God for Dean Edwards and his IE7 JavaScript script.
Now for the details.
MTThreadedComments on MT 3.3: The details
MT 3.33
MTThreadedComments 0.1.1 (Date: 2003/02/19 17:18:16)
MT Code Edits
You'll need to apply the following edits to MT's code:
(Taking a cue from the Korean site, the new code is coloured red.)
File: mt/lib/MT/App/Comments.pm
Subroutine: _make_comment()
$comment->ip($app->remote_ip);
$comment->blog_id($entry->blog_id);
$comment->entry_id($entry->id);
$comment->author(remove_html($nick));
$comment->email(remove_html($email));
$comment->url(is_valid_url($url, 'stringent'));
$comment->text($text);
## MTThreadedComments patch start ##
$comment->subject($q->param('subject'));
$comment->parent_id($q->param('parent_id'));
## MTThreadedComments patch end ##
File: mt/lib/MT/App/Comments.pm
Subroutine: _send_comment_notification()
my %param = (
blog_name => $blog->name,
entry_id => $entry->id,
entry_title => $entry->title,
view_url => $comment_link,
edit_url => $base . $app->uri_params('mode' => 'view', args => { blog_id => $blog->id, '_type' => 'comment', id => $comment->id}),
ban_url => $base . $app->uri_params('mode' => 'save', args => {'_type' => 'banlist', blog_id => $blog->id, ip => $comment->ip}),
comment_ip => $comment->ip,
comment_name => $comment->author,
(is_valid_email($comment->email)?
(comment_email => $comment->email):()),
comment_url => $comment->url,
## MTThreadedComments patch start ##
comment_subject => $comment->subject,
## MTThreadedComments patch end ##
File: mt/lib/MT/App/Comments.pm
Subroutine: view()
my $ctx = MT::Template::Context->new;
$ctx->stash('entry', $entry);
## MTThreadedComments patch start ##
$ctx->stash('comment_parent_id', $q->param('parent_id'));
## MTThreadedComments patch end ##
File: mt/lib/MT/Comment.pm
Subroutine: the root (i.e., the implicit) routine, at the beginning of the file
column_defs => {
'id' => 'integer not null auto_increment',
'blog_id' => 'integer not null',
'entry_id' => 'integer not null',
'author' => 'string(100)',
'commenter_id' => 'integer',
'visible' => 'boolean',
'junk_status' => 'smallint',
'email' => 'string(75)',
'url' => 'string(255)',
## MTThreadedComments patch start ##
'subject' => 'text',
'parent_id' => 'integer',
## MTThreadedComments patch end ##
and…
indexes => {
ip => 1,
created_on => 1,
entry_id => 1,
blog_id => 1,
email => 1,
commenter_id => 1,
## MTThreadedComments patch start ##
parent_id => 1,
## MTThreadedComments patch end ##
mt_comments Table
Next, you'll need to add two columns to the mt_comments table. I used phpMyAdmin.
comment_subject (text)
comment_parent_id (int)
Implementing my Ajax comments script: The details
If you plan on using my Ajax comments script (which you can get directly from my server) or something based on it:
MT Code Edits
File: mt/lib/MT/App/Comments.pm
Subroutine: post()
at the end of the routine:
return do_preview($app, $app->{query}, '');
return $app->redirect($comment_link);
This returns the comment preview html to the Ajax script which then inserts it into the existing individual archive page.
Comment Preview Template
You will need to edit your Comment Preview Template so that it only returns the html required to preview the comment. That means no <head>, no <body>, nothing except the comment itself and any tags that you need to format it. My xhtml code looks like this:
<MTIfNonEmpty tag="CommentPreviewSubject">
<h2><$MTCommentPreviewSubject$></h2></MTIfNonEmpty>
<$MTCommentPreviewBody$>
<div class="posted">
<p>Posted by: <$MTCommentPreviewAuthorLink spam_protect="1"$> |
<$MTCommentPreviewDate format="%a, %B %e, %Y, %H:%M"$></p>
</div>
Incidentally, the MTThreadedComments plugin does not provide a MTIfCommentPreviewSubject container tag so I had to use MTIfNotEmpty provided by Brad Choate's ifempty plugin.
Comment Error Template
You will also need to edit your Comment Error Template so that it only returns the minimum html required to view it within the Comment Form Error div if an error should occur during final submission of the comment. My xhtml code (it's just 3 lines) looks like this:
<h3>Comment Submission Error</h3>
<p>Your comment submission failed for the following reasons:</p>
<$MTErrorMessage$>
Individual Entry Archive edits
You'll need to add MTThreadedComments tags and JavaScript code to your template. For example;
The code that produces the comments list:
<MTIfCommentsActive>
<div id="comments-list">
<h3 id="comments">Comments</h3>
<MTRootComments>
<div id="comment-<$MTCommentID$>-parent" class="comment-parent">
<$MTInclude module="comments nested"$>
</div><!-- comment_parent -->
</MTRootComments>
</div> <!-- comments list -->
</MTIfCommentsActive>
The code for the 'comments nested' module:
<div id="comment-<$MTCommentID$>" class="comments-body">
<MTIfCommentSubject><h2><$MTCommentSubject$></h2></MTIfCommentSubject>
<div id="comment-<$MTCommentID$>-body">
<$MTCommentBody$>
</div> <!-- comment-<$MTCommentID$>-body -->
<div class="posted">
<p>Posted by: <$MTCommentAuthorLink spam_protect="1"$> | <$MTCommentDate format="%a, %B %e, %Y, %H:%M"$>
<MTIfCommentsAccepted> | <a href="javascript:void(0);" onclick="respond(<$MTCommentID$>, '<$MTCommentSubject remove_html="1" encode_js="1"$>', '<$MTCommentAuthor remove_html="1" encode_js="1"$>')">Respond to this comment</a></MTIfCommentsAccepted></p>
</div>
</div> <!-- comment-<$MTCommentID$> comments-body -->
<MTCommentIfChildren>
<div id="comment-<$MTCommentID$>-children" class="comments-children">
<MTCommentChildren>
<div id="comment-<$MTCommentID$>-child" class="comments-child">
<$MTInclude module="comments nested"$>
</div> <!-- comment-<$MTCommentID$>-child -->
</MTCommentChildren>
</div> <!-- comment-<$MTCommentID$>-children -->
</MTCommentIfChildren>
The code in my template that produces the "Create a comment regarding this article." link at the end of the comment list:
<MTIfCommentsAccepted>
<p><a href="javascript:void(0);" onclick="respond (0, '<$MTEntryTitle remove_html="1" encode_js="1"$>', '河國榮')">
Create a comment regarding this article.</a></p>
<MTElse>
<p>Comments to this entry are no longer being accepted.</p>
</MTElse>
</MTIfCommentsAccepted>
For reference, the MTThreadedComments plugin provides the following tags:
<MTRootComments>, <MTCommentChildren>, <MTCommentIfChildren>
<MTIfCommentSubject>, <MTUnlessCommentSubject>, <$MTCommentSubject$>
<$MTCommentPreviewSubject$>, <$MTCommentResponseSubject$>
<MTCommentParent>, <$MTCommentParentID$>, <MTCommentIfParent>, <MTCommentUnlessParent>
<MTCommentPreviewParent>, <$MTCommentPreviewParentID$>, <MTCommentPreviewIfParent>, <MTCommentPreviewUnlessParent>
Optional: An improved link to the comment upon comment submission.
When you submit a comment, MT currently usually in the Comment Notification email returns a link to the Individual Entry Archive page without including the comment # anchor. You can rectify this if you wish.
File: mt/lib/MT/App/Comments.pm
Subroutine: post()
in the # Form a link to the comment section:
# $comment_link = $entry->permalink;
$comment_link = $entry->permalink . '#comment-' . $comment->id;
Note. My Individual Entry Archive template assigns ids to each of the comments using the format id="comment-<$MTCommentID$>". Your format may and probably does differ. You will need to adjust the $comment_link code accordingly.
MT 3.34/3.35 and FastCGI
Note. This setup works with MT 3.34/3.35 and FastCGI as long as you don't use the FastCGI version of AdminScript; i.e., in the config file;
AdminScript mt.cgi
CommentScript mt-c.fcgi
TrackbackScript mt-t.fcgi
SearchScript mt-search.fcgi
ViewScript mt-view.fcgi
If you use the FastCGI version of AdminScript, building the Individual Entry Archive pages will fail; something to do with this line of code in the get_comments() subroutine of the MTThreadedComments.pl code:
my @comments = sort { $a->created_on <=> $b->created_on }
MT produces an error which begins with these three lines:
unknown column: parent_id for class MT::Comment at lib/MT/Object.pm line 283
MT::Object::AUTOLOAD('MT::Comment=HASH(0x92a1cc8)') called at /path_to_cgi-bin/mt/plugins/MTThreadedComments.pl line 123
MT::get_comments('MT::Template::Context=HASH(0x9168aa4)', 'MT::Entry=HASH(0x9175904)', 'undef') called at /path_to_cgi-bin/mt/plugins/MTThreadedComments.pl line 153
If anyone knows why this line doesn't work, please leave a comment.
Other details
You will of course need to write (or copy) the css for the form, etc. I use Dean Edwards' IE7 JavaScript script to help standardise the look of my blog on IE so don't count on my css to help you code for IE.
No support! I can offer no support for this implementation of MTThreadedComments. If you don't understand the instructions, then it's probably too difficult for you and you shouldn't attempt it.
Above all else; and it should go without saying; back up your MT installation before you begin editing the code and templates.
That's all folks!
Copyright 2007 Gregory Charles Rivers 河國榮. All rights reserved.
Posted by
on Tue, April 17, 2007, 02:28
Permalink
| Comments (14)
| TrackBack (0)
Categories: Aussie HK, Technology, Weblogs
TrackBack
TrackBack URL for this entry:
http://www.hokwokwing.hk/cgi-bin/mt/mt-t.fcgi/177.
Listed below are links to weblogs that reference this article:

Comments
IfEmpty is obsolete
The functionality has been integrated for some time as MTIfNonEmpty, which can be combined with MTElse to the same effect.
Posted by: Su | Tue, April 17, 2007, 04:33 | Respond to this comment
whoops! thank you for that information. I'll update the code later.
Posted by: 河國榮 | Tue, April 17, 2007, 08:15 | Respond to this comment
brilliant!!
loving your tunes..'for once in my life' is one of my favourite tune..well done!
Posted by: kenny | Tue, April 24, 2007, 06:56 | Respond to this comment
:-)
Posted by: 河國榮 | Sat, April 28, 2007, 22:30 | Respond to this comment
Thank. Just wanna remind you that the link to Six Apart Ltd doesn't work.
Posted by: cheungie | Sat, April 28, 2007, 19:05 | Respond to this comment
it was missing the protocol prefix: "http://". I've fixed it. thank you for pointing it out.
Posted by: 河國榮 | Sat, April 28, 2007, 22:29 | Respond to this comment
good effort
It is not easy to keep going with several times of failures, but you still kept going for the solution, I think this excellent attitude I should learn from you.
Posted by: stanley | Sat, April 28, 2007, 20:27 | Respond to this comment
Gregory, I'm very impressed by you as a life-driven person. I've always recognized your face from the tv but never did i know that you have a chinese name as well. More alarming is that neither of your parents is Chinese. And for all this time, I've mistaken you as a mixed actor. (: In any case, I'm just dropping to applaud you for your stunning vocal and linguistic talents!! Wish you all the very best in life.
Posted by: Yan | Fri, May 4, 2007, 09:59 | Respond to this comment
hm...... havent see updates for a long time~
just wondering is there any thing wrong~
Hehe, the weather in China or HK has varied so much~ and ive heard its like 35'C everyday~ please take care~
蔡茵
Posted by: yinyin | Sat, June 9, 2007, 15:21 | Respond to this comment
Urgent!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
HI Mr Ho,
i knew that you do adopt dog, would you please please help me?
i hv a girl golden retreiver which is 4 yrs old now, since my family cannot taking care of her anymore, would you kindly adopt her??
I heard that you love dog, can you help us please?
If you read this msg, would you please leave me a msg by email? Really Urgent!!!!!!!!!! Thank you VERy Very MUCH!!!!!
Posted by: Mrs Ho | Wed, June 13, 2007, 01:10 | Respond to this comment
I'm normally a silent reader to your blog...but where did you? You must be busy. I hope all is well. Take care!
Posted by: Kimmie | Thu, June 14, 2007, 10:57 | Respond to this comment
When will you update again?
Posted by: Hang | Tue, June 26, 2007, 16:29 | Respond to this comment
HEY
heyy ho kwok wing. you're cool. i didnt know u had a blog. i think u r so special becos u can speeak cantonese fluently..and i remembere how u looked in "餐餐有宋家"....its impressive!! and i think you r a nice person.ahahhaha!!
Posted by: Rachel | Tue, July 3, 2007, 02:20 | Respond to this comment
Something about improvement of your Blog
Wow..You are not just an actor. You are programmer too. I watch your TV series when I was a child. It is sad to know that you left HK TV already but I know you are moving to another and bigger part of your life so is great.
As I'm a web marketers, I've some suggestions about your site. I actually find your site through Google Sponsors Link. For a personal blog it is not necessary to paid for traffic. I'll suggest you to do search engine optimisation (SEO) first on your website. I found most of the meta tag, title tag and description tag is not quite right and not suitable on each articles. I won't leave a whole big tutorial about SEO here because the information is available everywhere. Just Google it. After you done the SEO on your site I'm sure your traffic will boost hugely and you can save the Google Adward budget for better use.
Hope this help!
Kelvin Lai
Posted by: Kelvin | Thu, April 3, 2008, 18:10 | Respond to this comment