Drupal 6 Limiting threaded comment depth to one

By shane
Thu, 2011-09-01 09:16

Share with Others

I recently wanted to create a comment system that was threaded but only allowed one level of replies. Basically I wanted something like this:

-Comment 1
---Reply 1-1
---Reply 1-2
-Comment 2
---Reply 2-1
---Reply 2-2

I still wanted to show all the reply links in the comment, however if a user tried to reply to an already indented comment, I wanted it to just add it to the bottom of the thread. For instance, clicking the reply link on "Reply 1-1" in the example above would add a "Reply 1-3" comment directly below "Reply-1.2". Make sense?

At first glance the easiest way to do this would be to modify Drupal 6 core comment code (which I usually don't recommend). Here is the code I added to the comment_save function in the comment.module file (The only code I added is after the @HACK comment, the rest is code from the comment_save function so you have context as to where it was added).

if ($edit['pid'] == 0) {
  // This is a comment with no parent comment (depth 0): we start
  // by retrieving the maximum thread level.
  $max = db_result(db_query('SELECT MAX(thread) FROM {comments} WHERE nid = %d', $edit['nid']));
  // Strip the "/" from the end of the thread.
  $max = rtrim($max, '/');
  // Finally, build the thread field for this new comment.
  $thread = int2vancode(vancode2int($max) + 1) .'/';
else {
  // This is comment with a parent comment: we increase
  // the part of the thread value at the proper depth.
  // Get the parent comment:
  $parent = _comment_load($edit['pid']);
  //@HACK to only allow one level of comments
  //This loop is a little bit ugly but I wrote it this way to keep the
  //rest of the comment code unchanged. After the loop is finished, the
  //$parent variable will contain the top level parent comment
  $new_parent = $parent;
  while(isset($new_parent->pid)) {
    $parent = $new_parent;
    $new_parent = _comment_load($new_parent->pid);
  // Strip the "/" from the end of the parent thread.
  $parent->thread = (string) rtrim((string) $parent->thread, '/');
  // Get the max value in _this_ thread.
  $max = db_result(db_query("SELECT MAX(thread) FROM {comments} WHERE thread LIKE '%s.%' AND nid = %d", $parent->thread, $edit['nid']));
  if ($max == '') {
    // First child of this parent.
    $thread = $parent->thread .'.'. int2vancode(0) .'/';
  else {
    // Strip the "/" at the end of the thread.
    $max = rtrim($max, '/');
    // We need to get the value at the correct depth.
    $parts = explode('.', $max);
    $parent_depth = count(explode('.', $parent->thread));
    $last = $parts[$parent_depth];
    // Finally, build the thread field for this new comment.
    $thread = $parent->thread .'.'. int2vancode(vancode2int($last) + 1) .'/';

Basically the loop continues loading the parent comments until it gets to a comment without a parent. It then uses that as the parent comment of the comment you are trying to save. For instance, using the diagram above, if you are saving a comment reply to "Reply 1-1". The code is going to first load the initial parent "Reply 1-1", after that it will notice that "Reply 1-1" also has a parent. The code will proceed to load that parent as well (in this case "Comment 1"). Since "Comment 1" does not have a parent, it will use "Comment 1" as the parent of the newly created comment, rather than than using "Reply 1-1".

Because I never recommend hacking Drupal core, I looked for an alternative, and what do you know... hook_comment to the rescue... or so I thought. It turns out that using hook_comment, you cannot actually alter the comment before it is saved. I guess this is one of those rare cases where the only way to get it to work correctly is to modify core.

Note that if you are doing this, it removes some of the flexibility of the comment system. For instance, if you decide later you want deeper nesting for the comments, and you remove the code above, all the current comments will still stay at only one level of nesting (regardless of what reply links your users clicked on when generating their comments).

Hopefully this helps you keep your nested comments in line. If you find a way to do this without hacking core or if you have questions. Let us know in the comments.