diff --git a/flatcomments_existing/flatcomments_existing.admin.inc b/flatcomments_existing/flatcomments_existing.admin.inc
new file mode 100644
index 0000000..554f35d
--- /dev/null
+++ b/flatcomments_existing/flatcomments_existing.admin.inc
@@ -0,0 +1,173 @@
+<?php
+
+/**
+ * @file
+ *  Administrative callbacks to provide the functionality of flattening
+ *  previously existing comments.
+ */
+
+/**
+ * This is a multi-pass form, the confirmation being second pass.
+ */
+function flatcomments_existing_form($form, &$form_state) {
+  // Need to make sure the form's state is preserved.
+  if ($form_state['rebuild']) {
+    $form_state['input'] = array();
+  }
+
+  $all_types = flatcomments_existing_node_types();
+
+  if (empty($form_state['storage']['types'])) {
+    // First pass: Fresh form to select content types
+    $form['types'] = array(
+      '#type' => 'checkboxes',
+      '#title' => t('Flatten existing comments for content types'),
+      '#options' => $all_types,
+      '#description' => t('To remove all threading information from already existing comments, select content types you wish to process, and click "Execute". <strong>Warning: This operation breaks any previously existing threads into separate comments permanently, so there\'s no way to revert existing discussions back to threads afterwards.</strong>'),
+    );
+    $form['actions']['submit'] = array(
+      '#type' => 'submit',
+      '#value' => t('Execute'),
+    );
+    $form['#submit'][] = 'flatcomments_existing_form_submit_1';
+  }
+  else {
+    // Second pass: Confirmation screen.
+    // Keep the selection from first pass.
+    $form['types'] = array(
+      '#type' => 'value',
+      '#value' => $form_state['storage']['types'],
+    );
+    $form['#submit'][] = 'flatcomments_existing_form_submit_2';
+
+    $types = array();
+    foreach ($form_state['storage']['types'] as $type) {
+      $types[] = '&bull; ' . $all_types[$type];
+    }
+
+    $form = confirm_form($form,
+      t('Are you sure you want to remove threading from these comments?'),
+      'admin/content/comment/flatten',
+      t('<strong>Warning: This operation is permanent and can NOT be undone. All comments of the selected content types will be flattened.</strong><br />') . implode('<br />', $types),
+      t('Flatten comments'),
+      t('Cancel')
+    );
+  }
+
+  return $form;
+}
+
+/**
+ * Form validation; checks that node type(s) are selected, and all valid.
+ * The checks are executed on both passes of the form.
+ */
+function flatcomments_existing_form_validate($form, &$form_state) {
+  $content_types = flatcomments_existing_node_types();
+  $is_selected = FALSE;
+  $is_valid = TRUE;
+
+  foreach ($form_state['values']['types'] as $type => $value) {
+    if (!empty($value)) {
+      $is_selected = TRUE;
+      if (!isset($content_types[$type])) {
+        $is_valid = FALSE;
+      }
+    }
+  }
+
+  if (!$is_selected || !$is_valid) {
+    form_set_error('types', t('You must choose at least one valid content type.'));
+  }
+}
+
+/**
+ * Form submit handler - first pass. Triggers second pass for confirmation.
+ */
+function flatcomments_existing_form_submit_1($form, &$form_state) {
+  // Pass the submitted selection of content types to the second pass.
+  // The existence of $form_state['storage'] triggers the second pass
+  // of the form being rendered in our code, as well as in the FAPI.
+  $form_state['storage']['types'] = array_filter($form_state['values']['types']);
+
+  // Don't rebuild the form on the next page load.
+  $form_state['rebuild'] = TRUE;
+}
+
+/**
+ * Generate a list of content types.
+ */
+function flatcomments_existing_node_types() {
+  $types = &drupal_static(__FUNCTION__);
+
+  if (empty($types)) {
+    foreach (_node_types_build()->types as $type => $spec) {
+      $types[$type] = $spec->name;
+    }
+  }
+
+  return $types;
+}
+
+/**
+ * Form submit handler - second pass. Starts a batch of required operations.
+ */
+function flatcomments_existing_form_submit_2($form, &$form_state) {
+  // Reset the form to show first pass when finished.
+  $form_state['storage'] = NULL;
+
+  $content_types = flatcomments_existing_node_types();
+  $processed_types = array();
+  $batch = array('file' => drupal_get_path('module', 'flatcomments_existing') . '/flatcomments_existing.admin.inc');
+
+  // Add operations to the batch
+  foreach ($form_state['values']['types'] as $type => $value) {
+    if (!empty($value)) {
+      $processed_types[$type] = $content_types[$type];
+      $nodes = db_query("SELECT DISTINCT c.nid FROM {comment} c INNER JOIN {node} n ON c.nid = n.nid WHERE n.type = :type", array(':type' => $type));
+      foreach ($nodes as $node) {
+        $batch['operations'][] = array('flatcomments_existing_one', array($node->nid));
+      }
+    }
+  }
+
+  // This is a replacement for 'finished' callback, so that we can pass
+  // $processed_types.
+  $batch['operations'][] = array('flatcomments_existing_finished', array($processed_types));
+
+  // Execute the batch.
+  batch_set($batch);
+
+  // batch_process() is not needed here, because we're inside a form
+  // submit handler.
+}
+
+/**
+ * Flatten comments for single node. This is a batch operation.
+ */
+function flatcomments_existing_one($nid, &$context) {
+  // Collect all comment ID's for the given node (published or not), ordering
+  // by cid to get the comments in the order they were created (the same order
+  // as flat display uses).
+  $records = db_query('SELECT cid FROM {comment} WHERE nid = :nid ORDER BY cid', array(':nid' => $nid));
+
+  // Iterate through the comments and set each one to be start of a new thread
+  // by clearing the parent ID and setting the 'thread' vancode equal to the
+  // order in flat list (with no descendants). This is done as PHP loop rather
+  // than database query to ensure the vancodes are consistent with comment
+  // module, and to avoid possible MySQL/PgSQL/whatever compatibility issues.
+  $order = 1;
+  foreach ($records as $record) {
+    $thread = int2vancode($order++) .'/';
+    $updated = db_query("UPDATE {comment} SET pid = 0, thread = :thread WHERE cid = :cid", array(':thread' => $thread, ':cid' => $record->cid));
+  }
+}
+
+/**
+ * Print message when finished. This is a batch operation.
+ */
+function flatcomments_existing_finished($processed_types, &$context) {
+  $types = implode(', ', $processed_types);
+
+  drupal_set_message(t('Threading information was successfully removed from comments on %types content type(s).', array('%types' => $types)));
+  watchdog('content', 'Removed threading information from comments on %types content type(s).', array('%types' => $types));
+}
diff --git a/flatcomments_existing/flatcomments_existing.info b/flatcomments_existing/flatcomments_existing.info
new file mode 100644
index 0000000..b43c03c
--- /dev/null
+++ b/flatcomments_existing/flatcomments_existing.info
@@ -0,0 +1,5 @@
+name = Flat comments existing
+description = Remove threading on existing comments.
+dependencies[] = comment
+dependencies[] = flatcomments
+core = 7.x
diff --git a/flatcomments_existing/flatcomments_existing.install b/flatcomments_existing/flatcomments_existing.install
new file mode 100644
index 0000000..ce646b2
--- /dev/null
+++ b/flatcomments_existing/flatcomments_existing.install
@@ -0,0 +1,13 @@
+<?php
+
+/**
+ * @file
+ *  (Un)Install, (dis)enable, and update functions.
+ */
+
+/**
+ * Implementation of hook_enable().
+ */
+function flatcomments_existing_enable() {
+  drupal_set_message(t('Flatcomments Existing successfully installed. Go to <a href="!url">admin/content/comment/flatten</a> to flatten existing comments.', array('!url' => url('admin/content/comment/flatten'))));
+}
diff --git a/flatcomments_existing/flatcomments_existing.module b/flatcomments_existing/flatcomments_existing.module
new file mode 100644
index 0000000..8007ea5
--- /dev/null
+++ b/flatcomments_existing/flatcomments_existing.module
@@ -0,0 +1,39 @@
+<?php
+
+/**
+ * @file
+ *  Remove threading from existing comments by content type.
+ */
+
+/**
+ * Implementation of hook_help().
+ */
+function flatcomments_existing_help($path, $arg) {
+  switch ($path) {
+    case 'admin/help#flatcomments_existing':
+    case 'admin/content/comment/flatten':
+      return '<p>' . t('The Flatcomments Existing module allows you to remove threading information from comments already existing in the database. This is useful when the Flatcomments module gets installed to an already existing site, and/or if a content type is switched from threaded to flat commenting mode later, in order to apply the behavior to previously existing comments.') . '</p>';
+  }
+}
+
+/**
+ * Implementation of hook_menu().
+ */
+function flatcomments_existing_menu() {
+  $items = array();
+
+  $items['admin/content/comment/flatten'] = array(
+    'title' => 'Flatten comments',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('flatcomments_existing_form'),
+    'access callback' => 'flatcomments_existing_flatten_access',
+    'file' => 'flatcomments_existing.admin.inc',
+    'type' => MENU_LOCAL_TASK,
+  );
+
+  return $items;
+}
+
+function flatcomments_existing_flatten_access() {
+  return (user_access('administer comments') && user_access('administer nodes') && user_access('administer content types'));
+}
