There has been sporadic discussion about the possibility of converting comments (and their dependent threads) to new nodes, eg:

http://drupal.org/node/3489
http://drupal.org/node/11877
http://drupal.org/node/38249

Is anything happening? It would be very helpful to have this functionality - in fact for me it's becoming a critical need. Does some sort of incentive need to be offered?

Comments

budda’s picture

Don't hold your breath.

I recall some devs are against making the move to using nodes anytime soon.

--
www.bargainspy.co.uk | More Drupal modules

droopy’s picture

Sorry, that wasn't really my point. What I'm looking for (it's clear from the linked discussions) is the functionality (I guess by means of a module) to start a new thread from a comment.

It's very easy for people to go off at a tangent as they join in a conversation, and it would be helpful to be able to cut that branch of the discussion off and replant it as a new thread - so the first comment in the pruned section would need to be converted to a node but dependent comments would remain attached to it. Ideally a marker would be left in the old thread to indicate the editing that had been done.

Surely this counts as basic management of content.

coreyp_1’s picture

I hacked the comment.module to allow for this, but, as everyone knows, hacking core is bad in the long run.

Now, I'm working on switching everything over to a module.

It's not ready yet, but I wanted to go ahead and post here so that I could track the thread (so it doesn't get lost amid all the other activity), and also to see if you are still interested.

droopy’s picture

Absolutely still interested! It would be a godsend. I wouldn't mind getting my hands on your hacked comment module either. Is it for 4.6?

coreyp_1’s picture

how can I send it to you?

I can send you my copy of the hacked comment.module, too, but it is always better in the long run to use a module. I wrote it using 4.6.4 (haven't upgraded to 4.6.5 yet).

BTW, this does leave a comment in the original location where the comment was moved from, with a message linking to the new location.

The only advantage to the hacked core is that, when a comment has been moved, it prevents the "reply" and "edit" links from appearing. Otherwise, the two function identically.

One other thing: Each node can potentially save information in a different way. As such, this is not a blanket solution, since I know of no way to anticipate every possible node type that someone may devise. Therefore, I have written this module to only work with the forum node type, since I presume that is where most discussions would take place. There are just too many different ways to handle other situations. That being said, if you need another node type addressed, then we can look at that particular type, and develop a strategy for handling it.

Even if this particular attempt is not quite what you need, I hope this works out for you in the long run... I've pulled out too much hair for it not to! :)

sepeck’s picture

There is no reason to not submit this as a patch for review and feedback. Dries has mentioned that for 4.8 and beyond he wants to look at ways to improve forums module. So, your strategy may prove to be an approach that is attractive. It may not.

It will also be in the patch queue for others to take advantage of if they so choose.

-sp
---------
Test site, always start with a test site.
Drupal Best Practices Guide -|- Black Mountain

-Steven Peck
---------
Test site, always start with a test site.
Drupal Best Practices Guide

droopy’s picture

Could you send it via my contact form? Either paste the code in, or send me an email and I'll reply to you. I presume it's not a good idea to post the email address in this reply. I'd like to try the hacked comment module too.

My need currently is to convert comments from both forum posts and stories to both forum posts and stories, though in practice the distinction between stories and forum posts is rather blurred, and I have been thinking of getting rid of the forum structure altogether. Anyway, if it does half of what I need, I will be delighted! Thanks.

coreyp_1’s picture

I decided to post the code here, just in case someone else wanted to see the code. I decided against hacking the comment module, since the changes were fairly extensive, which would cause issues when upgrading. Besides, the same effect can be achieved having a stand alone module and adding three lines to the appropriate function (discussed later in this post). I might submit this as a new feature patch to the comments module, but I don't know if it is something desired for core. *shrug*

Copy and paste the following code into a file named comment_split.module. Enable it, and it will work for both stories and forums (Drupal 4.6).

function comment_split_help($section) {
  switch ($section) {
    case 'admin/modules#description':
      // This description is shown in the listing at admin/modules.
      return t('This module gives the added ability to split a comment in a forum into a separate forum topic, moving the appropriate child comments to follow.');
      break;
  }
}

function comment_split_perm() {
  return array('split forum comments', 'split story comments');
}

function comment_split_menu($maycache) {
  $items = array();
  if ($maycache) {
      $items[] = array('path' => ('comment/convert'), 'title' => t('convert'),
      'callback' => 'comment_split_convert', 'access' => user_access('administer nodes'),
      'type' => MENU_CALLBACK);
  }
  return $items;
}

function comment_split_link($type, $node = NULL, $teaser = FALSE){
  $links = array();
  if ($type == 'comment'){
    if (arg(0) == 'node' && is_numeric(arg(1))) {
      $cid = $node->cid;
      $comment = $node->comment;
      $node = node_load(array('nid' => arg(1)));
      if (( ($node->type == 'forum' && user_access('split forum comments')) ||
            ($node->type == 'story' && user_access('split story comments'))
           ) && !(strpos($comment, '<!-- MOVED -->') !== false)) {
        $links[] = l(t('convert to node'), "comment/convert/$cid");
      }
    }
  }
  return $links;
}

function _comment_split_convert_recursive($cid, $nid, $thread, $parentthread, $clearparent = false){
  // $cid = the comment ID to change
  // $nid = the new node id
  // $thread = the comment's current thread string
  // $parentthread = the portion of the thread that should be discarded under the new node
  // $clearparent = whether or not to set the pid to 0 (only "true" first time)
  $thread = substr($thread, strlen($parentthread));
  $query = 'UPDATE {comments} SET nid=' . $nid;
  $query .= ($clearparent ? ', pid=0' : '');
  $query .= ', thread="' . $thread . '" WHERE cid=' . $cid;
  db_query ($query);
  $query = "SELECT cid, thread from {comments} WHERE pid=$cid";
  $resource = db_query($query);
  while ($result = db_fetch_array($resource)) {
    _comment_split_convert_recursive($result['cid'], $nid, $result['thread'], $parentthread);
  }
}

function comment_split_convert($cid) {
  $op = $_POST['op'] ? $_POST['op'] : 0;
  $edit = $_POST['edit'];
  $content = '';
  $cid = (int)$cid;
  $query = 'SELECT * FROM {comments} c WHERE c.cid=' . $cid . ' LIMIT 1';
  if ($node = db_fetch_object(db_query($query))){
    if (!(strpos($node->comment, '<!-- MOVED -->') !== false)) {
      if ($edit['convert']) {
        // action confirmed, begin conversion...
        $savenodeforlater = $node;
        $parentnid = $node->nid;

        // convert the comment into a node
        $node2 = node_load(array('nid' => $node->nid));
        $node->tid = $node2->tid;
        $node->type = $node2->type;
        $node->title = $node->subject;
        $node->body = $node->comment;
        $node->created = $node->timestamp;
        $node->changed = $node->timestamp;
        $node->status = $node2->status;
        $node->comment = $node2->comment;
        $node->promote = $node2->promote;
        unset ($node->nid);
        $newnid = node_submit($node);
        if (function_exists('taxonomy_node_save')){
          taxonomy_node_save($newnid, array($node->tid));
        }

        // transfer child comments to the new node
        $query = "SELECT cid, thread from {comments} WHERE pid=$cid";
        $resource = db_query($query);
        while ($result = db_fetch_array($resource)) {
          _comment_split_convert_recursive($result['cid'], $newnid, $result['thread'], $node->thread, true);
        }

        // change old comment to let the user know that it has been moved
        $edit = object2array($savenodeforlater);
        $edit['subject'] = t('Comment Moved');
        $edit['comment'] = '<!-- MOVED -->' . t('This comment has been moved to a new location %s.', array('%s' => l(t('here'), 'node/' . $newnid)));
        $edit['status'] = 0;
        comment_save($cid, $edit);

        // clean-up
        _comment_update_node_statistics($parentnid);
        _comment_update_node_statistics($newnid);
        cache_clear_all();

        // job's done, let's go!
        $node = node_load(array('nid' => $newnid));
        if (node_access('view', $node)) {
          drupal_goto('node/'. $newnid);
        }
        else if (db_result(db_query('SELECT nid FROM {node} WHERE nid = %d', $newnid))) {
          drupal_access_denied();
        }
        else {
          drupal_goto();
        }
      }
      else {
        // confirm request
        $node2 = node_load(array('nid' => $node->nid));
        $content = theme('confirm',
          t('Are you sure you want to convert this Comment into a new Node (%s)?', array('%s' => t($node2->type))),
          'node/'. $node->nid,
          t('This action cannot be undone.'),
          t('Convert'),
          t('Cancel'),
          NULL,
          'convert');
        print theme('page', $content);
      }
    }
    else {
      // double request
      drupal_set_message(t('The comment has already been converted.'));
    }
  }
  else {
    drupal_set_message(t('The comment no longer exists.'));
  }
  print theme('page', $content);
}

function comment_split_links_cleanup($links){
  foreach ($links AS $key => $val){
    if (strpos($val, 'comment/edit/') !== false) {
      unset($links[$key]);
    }
    if (strpos($val, 'comment/reply/') !== false) {
      unset($links[$key]);
    }
  }
  return $links;
}

(Believe it or not, but I did put blank lines between the functions and sections of code, but the <php> tags remove them all.)

If you want to hide the "edit" and "reply" links for when a comment has been moved, then add the following around line 704 of comment.module, in the comment_links() function, just before the return $links; statement:

  if (function_exists('comment_split_links_cleanup') && strpos($comment->comment, '<!-- MOVED -->') !== false) {
    $links = comment_split_links_cleanup($links);
  }

Using function_exists keeps this from breaking the module should you deactivate the comment_split module.

This module makes use of user roles so that you can allow moderators to split comments, if desired.

Sorry it took a few days to get this out... things got hectic at work.

Let me know if there are any problems!

droopy’s picture

This is going to be a great help for me. Many thanks for putting it together.

It seems to work very well, but a couple of issues:

1. I had to remove the line

print theme('page', $content);

from the 'confirm request' part of comment_split_convert because the confirmation page was printing twice. I know next to nothing about PHP so could you confirm that this is correct?

2. I changed the following line in the 'convert the comment into a node' section

$node->body = $node->comment;

to

$node->body = '[New post created by admin from: ' . l(t($node->title), 'node/' . $node->nid . '#comment-' . $cid) . ']<br>' . $node->comment;

to show where the new post had been taken from. Is there a better way of doing this?

coreyp_1’s picture

1. I have to laugh about the duplicate content. Would you believe that I never scrolled down far enough in the page to see that it was being printed twice? Thanks for catching the redundancy.

2. Customizing the new node's text is not a problem, either. One consideration, though: This module lets others split comments, too (if you give them permission, that is), so you may want to code this in such a way as to allow the admin (or moderator) name to be put in dynamically.

droopy’s picture

This module has been invaluable for me. Are there plans to upgrade it to 4.7?