diff --git a/apachesolr.admin.inc b/apachesolr.admin.inc
index 9deed2f..f24ba8a 100644
--- a/apachesolr.admin.inc
+++ b/apachesolr.admin.inc
@@ -395,76 +395,6 @@ function apachesolr_settings_validate($form, &$form_state) {
   }
 }
 
-/**
- * Gets information about the fields already in solr index.
- */
-function apachesolr_index_page($env_id = NULL) {
-  try {
-    $solr = apachesolr_get_solr($env_id);
-    // TODO: possibly clear this every page view if we are running multi-site.
-    if (apachesolr_index_get_last_updated()) {
-      $solr->clearCache();
-    }
-    $data = $solr->getLuke();
-  }
-  catch (Exception $e) {
-    watchdog('Apache Solr', nl2br(check_plain($e->getMessage())), NULL, WATCHDOG_ERROR);
-    drupal_set_message(nl2br(check_plain($e->getMessage())), "warning");
-    $data = new stdClass;
-    $data->fields = array();
-  }
-
-  if (empty($env_id)) {
-    $env_id = apachesolr_default_environment();
-  }
-
-  // Initializes output with information about which server's setting we are
-  // editing, as it is otherwise not transparent to the end user.
-  $output = array(
-    'apachesolr_environment' => array(
-      '#theme' => 'apachesolr_settings_title',
-      '#env_id' => $env_id,
-    ),
-  );
-
-  $status_header = '';
-  $solr_msg = $num_docs = $delay_msg = $delete_msg = '';
-  if (isset($data->index->numDocs)) {
-    try {
-      $stats_summary = $solr->getStatsSummary();
-      $solr_msg = '<p>' . t('Using schema.xml version: <strong>@schema_version</strong>', $stats_summary);
-      // We need a schema version greater than beta3. This is mostly to catch
-      // people using the Drupal 6 schema.
-      if (version_compare($stats_summary['@schema_version'], 'drupal-3.0-beta3', '<=')) {
-        drupal_set_message(t('Your schema.xml version is too old. You must update it and re-index your content.'), 'error');
-      }
-      if (!empty($stats_summary['@core_name'])) {
-        $solr_msg .= '<br />' . t('Solr core name: <strong>@core_name</strong>', $stats_summary);
-      }
-      $delay_msg = '<br />' . t('<em>The server has a @autocommit_time delay before updates are processed.</em>', $stats_summary) . "</p>\n";
-      $delete_msg = '<p>' . t('Number of pending deletions: @deletes_total', $stats_summary) . "</p>\n";
-    }
-    catch (Exception $e) {
-      watchdog('Apache Solr', nl2br(check_plain($e->getMessage())), NULL, WATCHDOG_ERROR);
-    }
-    $status_header .= $solr_msg . $delay_msg;
-    $pending_msg = isset($stats_summary['@pending_docs']) ? t('(@pending_docs sent but not yet processed)', $stats_summary) : '';
-    $num_docs = '<p>' . t('Number of documents in index: @num !pending', array('@num' => $data->index->numDocs, '!pending' => $pending_msg)) . "</p>\n";
-    $status_header .= $num_docs . $delete_msg;
-  }
-  $status_header .= '<p>' . l(t('View more details on the search index contents'), 'admin/reports/apachesolr') . "</p>\n";
-  $output['apachesolr_index_action_status_header'] = array('#markup' => $status_header);
-  if (apachesolr_environment_variable_get($env_id, 'apachesolr_read_only', APACHESOLR_READ_WRITE) == APACHESOLR_READ_WRITE) {
-    // Display the Delete Index form.
-    $output['apachesolr_index_action_form'] = drupal_get_form('apachesolr_index_action_form');
-  }
-  else {
-    drupal_set_message(t('The index is in read-only mode. Options for deleting and re-indexing are therefore not available. The index mode can be changed on the <a href="!settings_page">settings page</a>', array('!settings_page' => url('admin/config/search/apachesolr-env/' . $env_id, array('query' =>  drupal_get_destination())))), 'warning');
-  }
-
-  return $output;
-}
-
 function apachesolr_index_report($env_id = NULL) {
   if (empty($env_id)) {
     $env_id = apachesolr_default_environment();
diff --git a/apachesolr.module b/apachesolr.module
index 671df46..51c5af9 100644
--- a/apachesolr.module
+++ b/apachesolr.module
@@ -16,18 +16,11 @@ function apachesolr_menu() {
   $items = array();
   $items['admin/config/search/apachesolr'] = array(
     'title'              => 'Apache Solr search',
-    'description'        => 'Administer Apache Solr.',
-    'page callback'      => 'apachesolr_index_page',
+    'page callback'      => 'drupal_get_form',
+    'page arguments'     => array('apachesolr_settings'),
     'access arguments'   => array('administer search'),
-    'weight'             => -8,
     'file'               => 'apachesolr.admin.inc',
-  );
-  $items['admin/config/search/apachesolr/index'] = array(
-    'title'              => 'Search index',
-    'access arguments'   => array('administer search'),
-    'weight'             => -10,
     'file'               => 'apachesolr.admin.inc',
-    'type'               => MENU_DEFAULT_LOCAL_TASK,
   );
   $items['admin/config/search/apachesolr/settings'] = array(
     'title'              => 'Settings',
@@ -36,7 +29,7 @@ function apachesolr_menu() {
     'page arguments'     => array('apachesolr_settings'),
     'access arguments'   => array('administer search'),
     'file'               => 'apachesolr.admin.inc',
-    'type'               => MENU_LOCAL_TASK,
+    'type'               => MENU_DEFAULT_LOCAL_TASK,
   );
   $items['admin/config/search/apachesolr-env/%apachesolr_environment'] = array(
     'title'              => 'Apache Solr search environment edit',
@@ -271,6 +264,7 @@ function apachesolr_facetapi_query_types() {
 
 /**
  * Implements hook_facetapi_facet_info().
+ * Currently it only supports the node entity type
  */
 function apachesolr_facetapi_facet_info($searcher_info) {
   $facets = array();
@@ -584,32 +578,6 @@ function apachesolr_get_last_change($namespace) {
 }
 
 /**
- * Returns an array of rows from a query based on an indexing namespace.
- */
-function apachesolr_get_nodes_to_index($namespace, $limit) {
-  $rows = array();
-  if (apachesolr_environment_variable_get(apachesolr_default_environment(), 'apachesolr_read_only', APACHESOLR_READ_WRITE) == APACHESOLR_READ_ONLY) {
-    return $rows;
-  }
-
-  $excluded_types = apachesolr_get_excluded_types($namespace);
-  list($last_change, $last_nid) = apachesolr_get_last_change($namespace);
-  // TODO: remove old code
-  // list($excluded_types, $args, $join_sql, $exclude_sql) = apachesolr_exclude_types($namespace);
-  // $result = db_query_range("SELECT asn.nid, asn.changed FROM {apachesolr_search_node} asn ". $join_sql ."WHERE (asn.changed > :last_changed OR (asn.changed = :last_changed AND asn.nid > :last_nid)) AND asn.status = 1 ". $exclude_sql ."ORDER BY asn.changed ASC, asn.nid ASC", 0, $limit, $args);
-  $query = db_select('apachesolr_search_node', 'asn')
-    ->fields('asn', array('nid', 'changed'))
-    ->condition('asn.status', 1)
-    ->condition(db_or()->condition('asn.changed', $last_change, '>')->condition(db_and()->condition('asn.changed', $last_change)->condition('asn.nid', $last_nid, '>')))
-    ->orderBy('asn.changed', 'ASC')
-    ->orderBy('asn.nid', 'ASC')
-    ->range(0, $limit);
-  apachesolr_query_add_excluded_types($query, $excluded_types);
-  $result = $query->execute();
-  return $result;
-}
-
-/**
  * Function to handle the indexing of nodes.
  *
  * The calling function must supply a namespace.
@@ -756,37 +724,13 @@ function apachesolr_flatten_documents_array($documents, &$tmp) {
   }
 }
 
-function apachesolr_delete_node_from_index($node) {
-  static $failed = FALSE;
-  if ($failed) {
-    return FALSE;
-  }
-  try {
-    $solr = apachesolr_get_solr();
-    $solr->deleteById(apachesolr_document_id($node->nid));
-    apachesolr_index_set_last_updated(REQUEST_TIME);
-    return TRUE;
-  }
-  catch (Exception $e) {
-    watchdog('Apache Solr', nl2br(check_plain($e->getMessage())), NULL, WATCHDOG_ERROR);
-    // Don't keep trying queries if they are failing.
-    $failed = TRUE;
-    return FALSE;
-  }
-}
-
 /**
  * Set the timestamp of the last index update
  * @param $updated
  *   A timestamp or zero. If zero, the variable is deleted.
  */
-function apachesolr_index_set_last_updated($updated = 0) {
-  if ($updated) {
-    variable_set('apachesolr_index_updated', (int) $updated);
-  }
-  else {
-    variable_del('apachesolr_index_updated');
-  }
+function apachesolr_index_set_last_updated($timestamp = 0) {
+ variable_set('apachesolr_indexer_last_run', $timestamp);
 }
 
 /**
@@ -794,7 +738,7 @@ function apachesolr_index_set_last_updated($updated = 0) {
  * @return integer (timestamp)
  */
 function apachesolr_index_get_last_updated() {
-  return variable_get('apachesolr_index_updated', 0);
+  return variable_get('apachesolr_indexer_last_run', 0);
 }
 
 /**
@@ -1835,7 +1779,7 @@ function apachesolr_entity_fields($entity_type = 'node') {
     }
 
     // Allow other modules to add or alter mappings.
-    drupal_alter('apachesolr_field_mappings', $mappings);
+    drupal_alter('apachesolr_field_mappings', $mappings, $entity_type);
     $modules = system_get_info('module');
     $instances = field_info_instances($entity_type);
     foreach (field_info_fields() as $field_name => $field) {
diff --git a/apachesolr_indexer/apachesolr_indexer.admin.inc b/apachesolr_indexer/apachesolr_indexer.admin.inc
new file mode 100644
index 0000000..1df30da
--- /dev/null
+++ b/apachesolr_indexer/apachesolr_indexer.admin.inc
@@ -0,0 +1,295 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ *   Administrative pages for the Apachesolr indexer module.
+ */
+
+function apachesolr_indexer_configure($env_id = NULL) {
+  try {
+    $solr = apachesolr_get_solr();
+    // TODO: possibly clear this every page view if we are running multi-site.
+    if (apachesolr_index_get_last_updated()) {
+      $solr->clearCache();
+    }
+    $data = $solr->getLuke();
+  }
+  catch (Exception $e) {
+    watchdog('Apache Solr', filter_xss(nl2br($e->getMessage())), NULL, WATCHDOG_ERROR);
+    drupal_set_message(filter_xss(nl2br($e->getMessage())), "warning");
+    $data = new stdClass;
+    $data->fields = array();
+  }
+
+  if (empty($env_id)) {
+    $env_id = apachesolr_default_environment();
+  }
+
+  // Initializes output with information about which server's setting we are
+  // editing, as it is otherwise not transparent to the end user.
+  $output = array(
+    'apachesolr_environment' => array(
+      '#theme' => 'apachesolr_settings_title',
+      '#env_id' => $env_id,
+    ),
+  );
+
+  $status_header = '';
+  if (isset($data->index->numDocs)) {
+    $pending_docs = $delay_msg = $delete_msg = '';
+    try {
+      $stats_summary = $solr->getStatsSummary();
+
+      $stats = array();
+      $stats[] = t('Using schema.xml version: <strong>@schema_version</strong>', $stats_summary);
+      if ($stats_summary['@core_name']) {
+        $stats[] = t('Solr core name: <strong>@core_name</strong>', $stats_summary);
+      }
+
+      $stats[] = t('The server has a @autocommit_time delay before updates are processed.', $stats_summary);
+      $stats[] = t('Number of pending deletions: @deletes_total', $stats_summary);
+      $stats[] = t('Number of documents in index: @num', array('@num' => $data->index->numDocs));
+      $stats[] = t('@pending_docs sent but not yet processed', $stats_summary);
+
+      $output['stats'] = array(
+        '#theme' => 'item_list',
+        '#items' => $stats,
+        '#title' => t('Solr status'),
+      );
+    }
+    catch (Exception $e) {
+      watchdog('Apache Solr', nl2br(check_plain($e->getMessage())), NULL, WATCHDOG_ERROR);
+    }
+  }
+
+  if (variable_get('apachesolr_read_only', APACHESOLR_READ_WRITE) == APACHESOLR_READ_WRITE) {
+    $output['apachesolr_index_action_status_header'] = array(
+      '#markup' => l(t('View more details on the search index contents'), 'admin/reports/apachesolr'),
+    );
+  }
+  else {
+    $message = t('The index is in read-only mode. Options for deleting and re-indexing are therefore not available. The index mode can be changed on the !settings_page', array('!settings_page' => l(t('settings page'), 'admin/config/search/apachesolr')));
+    drupal_set_message(check_plain($message), 'warning');
+  }
+
+  $output['index_action_form'] = drupal_get_form('apachesolr_indexer_action_form');
+  $output['index_config_form'] = drupal_get_form('apachesolr_indexer_config_form');
+
+  return $output;
+}
+
+/**
+ * Form builder for the Apachesolr Indexer actions form.
+ *
+ * @see apachesolr_indexer_action_form_delete_submit().
+ */
+function apachesolr_indexer_action_form() {
+  $form = array();
+  $form['action'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Index Modifications'),
+    '#collapsible' => TRUE,
+  );
+  $form['action']['reset'] = array(
+    '#prefix' => '<div>',
+    '#suffix' => '</div>',
+    '#type' => 'submit',
+    '#value' => t('Queue content for reindexing'),
+    '#submit' => array('apachesolr_indexer_action_form_reset_submit'),
+  );
+
+  $form['action']['reset_description'] = array(
+    '#prefix' => '<div>',
+    '#suffix' => '</div>',
+    '#markup' => t('All content on the site will be queued for indexing. The documents currently in the Solr index will remain searchable. The content will be gradually resubmitted to Solr during cron runs.'),
+  );
+
+  $form['action']['delete'] = array(
+    '#prefix' => '<div>',
+    '#suffix' => '</div>',
+    '#type' => 'submit',
+    '#value' => t('Delete index'),
+    '#submit' => array('apachesolr_indexer_action_form_delete_submit'),
+  );
+  $form['action']['delete_description'] = array(
+    '#prefix' => '<div>',
+    '#suffix' => '</div>',
+    '#markup' => t('All documents in the Solr index will be deleted. This is rarely necessary unless your index is corrupt or you have installed a new schema.xml. After doing this your content will need to be resubmitted for indexing.'),
+  );
+  return $form;
+}
+
+/**
+ * Submit handler for the Indexer actions form, delete button.
+ */
+function apachesolr_indexer_action_form_delete_submit($form, &$form_state) {
+  $destination = array();
+  if (isset($_GET['destination'])) {
+    $destination = drupal_get_destination(); unset($_GET['destination']);
+  }
+
+  $form_state['redirect'] = array('admin/config/search/apachesolr/indexer/reindex/delete', array('query' => $destination));
+}
+
+/**
+ * Submit handler for the Indexer actions form, delete button.
+ */
+function apachesolr_indexer_action_form_reset_submit($form, &$form_state) {
+  $destination = array();
+  if (isset($_GET['destination'])) {
+    $destination = drupal_get_destination(); unset($_GET['destination']);
+  }
+
+  $form_state['redirect'] = array('admin/config/search/apachesolr/indexer/reindex/reset', array('query' => $destination));
+}
+
+/**
+ * Form builder for the index delete/clear form.
+ *
+ * @see apachesolr_indexer_action_form_delete_confirm_submit().
+ */
+function apachesolr_indexer_action_form_delete_confirm($form, &$form_state) {
+  return confirm_form($form,
+    t('Are you sure you want to clear your index?'),
+    'admin/config/search/apachesolr/indexer/reindex',
+    t('This will remove all data from your index and all search results will be incomplete until your site is reindexed.'),
+    t('Delete index')
+  );
+}
+
+/**
+ * Form builder for the index re-enqueue form.
+ *
+ * @see apachesolr_indexer_action_form_reset_confirm_submit().
+ */
+function apachesolr_indexer_action_form_reset_confirm($form, &$form_state) {
+  return confirm_form($form,
+    t('Are you sure you want to queue content for reindexing?'),
+    'admin/config/search/apachesolr/indexer/reindex',
+    t('All content on the site will be queued for indexing. The documents currently in the Solr index will remain searchable. The content will be gradually resubmitted to Solr during cron runs.'),
+    t('Reindex')
+  );
+}
+
+/**
+ * Submit handler for the deletion form.
+ */
+function apachesolr_indexer_action_form_reset_confirm_submit($form, &$form_state) {
+  $form_state['redirect'] = 'admin/config/search/apachesolr/indexer/reindex';
+
+  foreach (entity_get_info() as $entity_type => $entity_info) {
+    if ($entity_info['apachesolr']['indexable']) {
+      $bundles = apachesolr_indexer_get_bundles('default', $entity_type);
+      $reindex_callback = '';
+      if (!empty($bundles)) {
+        $callback = apachesolr_entity_get_callback($entity_type, 'reindex callback');
+        $reindex_callback = $callback;
+      }
+      if (! empty($reindex_callback)) {
+        if (! $reindex_callback()) {
+          drupal_set_message(t('There was an error reindexing @entity_type.  Please consult the log for more information.', array('@entity_type' => $entity_info['label'])), 'error');
+          return;
+        }
+      }
+
+    }
+  }
+
+  drupal_set_message(t('All the content on your site is queued for indexing. You can wait for it to be indexed during cron runs, or you can manually reindex it.'));
+}
+
+/**
+ * Submit handler for the deletion form.
+ */
+function apachesolr_indexer_action_form_delete_confirm_submit($form, &$form_state) {
+  // Instantiate a new Solr object.
+  $solr = apachesolr_get_solr();
+  $query = '*:*';
+
+  // Allow other modules to modify the delete query.
+  // For example, use the site hash so that you only delete this site's
+  // content:  $query = 'hash:' . apachesolr_site_hash()
+  drupal_alter('apachesolr_delete_index', $query);
+  $solr->deleteByQuery($query);
+  $solr->commit();
+
+  // Rebuild our tracking table.
+  variable_get('apachesolr_indexer_last_run', 0);
+
+  drupal_set_message(t('The index has been deleted.'));
+
+  $form_state['redirect'] = 'admin/config/search/apachesolr/indexer/reindex';
+}
+
+/**
+ * Form builder for the bundle configuration form.
+ *
+ * @see apachesolr_indexer_config_form_submit().
+ */
+function apachesolr_indexer_config_form() {
+  $form['config'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Index Configurations'),
+    '#collapsible' => TRUE,
+  );
+
+  $form['config']['bundles'] = array(
+    '#type' => 'markup',
+    '#markup' => t('Select the entity types and bundles that should be indexed.'),
+  );
+
+  // For future extensibility, when we have multiple cores.
+  $form['config']['core'] = array(
+    '#type' => 'value',
+    '#value' => 'default',
+  );
+  foreach (entity_get_info() as $entity_type => $entity_info) {
+    if ($entity_info['apachesolr']['indexable']) {
+      $options = array();
+      foreach ($entity_info['bundles'] as $key => $info) {
+        $options[$key] = $info['label'];
+      }
+
+      $form['config']['entities']['#tree'] = TRUE;
+
+      $form['config']['entities'][$entity_type] = array(
+        '#type' => 'checkboxes',
+        '#title' => check_plain($entity_info['label']),
+        '#options' => $options,
+        '#default_value' => apachesolr_indexer_get_bundles('default', $entity_type),
+      );
+    }
+  }
+
+  $form['config']['submit'] = array('#type' => 'submit', '#value' => t('Save'));
+
+  return $form;
+}
+
+/**
+ * Submit handler for the bundle configuration form.
+ */
+function apachesolr_indexer_config_form_submit($form, &$form_state) {
+  $form_values = $form_state['values'];
+  $core = $form_values['core'];
+  $entity_count = 0;
+
+  foreach ($form_values['entities'] as $entity_type => $bundles) {
+    $entity_bundles = array_flip($bundles);
+    unset($entity_bundles[0]); // Nuke unchecked bundles
+    if (!empty($entity_bundles)) {
+      $entity_count++;
+    }
+    apachesolr_indexer_set_bundles($core, $entity_type, $entity_bundles);
+  }
+
+  // set our amount of entities we are indexing. Useful for cron limits
+  // to make sure every entity can be indexed
+  variable_set('apachesolr_indexer_entity_count', $entity_count);
+
+  // Clear the entity cache, since we will be changing its data.
+  entity_info_cache_clear();
+
+  drupal_set_message(t('Your settings have been saved. You should reindex your site for the changes to take effect.'));
+}
diff --git a/apachesolr_indexer/apachesolr_indexer.apachesolr.inc b/apachesolr_indexer/apachesolr_indexer.apachesolr.inc
new file mode 100644
index 0000000..084d8f3
--- /dev/null
+++ b/apachesolr_indexer/apachesolr_indexer.apachesolr.inc
@@ -0,0 +1,8 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ *   ApacheSolr hook implementations for the apachesolr_indexer module.
+ */
+
diff --git a/apachesolr_indexer/apachesolr_indexer.info b/apachesolr_indexer/apachesolr_indexer.info
new file mode 100644
index 0000000..9650d26
--- /dev/null
+++ b/apachesolr_indexer/apachesolr_indexer.info
@@ -0,0 +1,9 @@
+; $Id:$
+name = Apache Solr Indexer
+description = Indexer for reading arbitrary entity types into a solr core.
+dependencies[] = apachesolr
+package = Search Toolkit
+core = 7.x
+
+files[] = apachesolr_indexer.module
+files[] = apachesolr_indexer.apachesolr.inc
diff --git a/apachesolr_indexer/apachesolr_indexer.install b/apachesolr_indexer/apachesolr_indexer.install
new file mode 100644
index 0000000..b5e4b54
--- /dev/null
+++ b/apachesolr_indexer/apachesolr_indexer.install
@@ -0,0 +1,99 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ *   Install and related hooks for apachesolr_indexer.
+ */
+
+/**
+ * Implements hook_install().
+ */
+function apachesolr_indexer_install() {
+  // Initialize the queue we will use for processing entities into the Solr index.
+  DrupalQueue::get('apachesolr_indexer_entities')->createQueue();
+}
+
+/**
+ * Implements hook_schema().
+ */
+function apachesolr_indexer_schema() {
+
+  //Predefine an amount of types that get their own table
+  $types = array(
+      'other' => 'apachesolr_indexer_entities',
+      'node' => 'apachesolr_indexer_entities_node',
+      'user' => 'apachesolr_indexer_entities_user',
+      'term' => 'apachesolr_indexer_entities_term',
+  );
+
+  foreach ($types as $type) {
+    $schema[$type] = array(
+      'description' => t('Stores a record of when an entity changed to determine if it needs indexing by Solr.'),
+      'fields' => array(
+        'entity_type' => array(
+          'description' => t('The type of entity.'),
+          'type' => 'varchar',
+          'length' => 128,
+          'not null' => TRUE,
+        ),
+        'entity_id' => array(
+          'description' => t('The primary identifier for an entity.'),
+          'type' => 'int',
+          'unsigned' => TRUE,
+          'not null' => TRUE,
+        ),
+        'bundle' => array(
+          'description' => t('The bundle to which this entity belongs.'),
+          'type' => 'varchar',
+          'length' => 128,
+          'not null' => TRUE,
+        ),
+        'status' => array(
+          'description' => t('Boolean indicating whether the entity is visible to non-administrators (eg, published for nodes).'),
+          'type' => 'int',
+          'not null' => TRUE,
+          'default' => 1,
+        ),
+        'changed' => array(
+          'description' => t('The Unix timestamp when an entity was changed.'),
+          'type' => 'int',
+          'not null' => TRUE,
+          'default' => 0,
+        ),
+      ),
+      'indexes' => array(
+        'changed' => array('changed', 'status'),
+      ),
+      'primary key' => array('entity_id'),
+    );
+  }
+
+
+  $schema['apachesolr_indexer_bundles'] = array(
+    'description' => t('Records what bundles we should be indexing for a given core.'),
+    'fields' => array(
+      'core' => array(
+        'description' => t('The name of the core.'),
+        'type' => 'varchar',
+        'length' => 128,
+        'not null' => TRUE,
+      ),
+      'entity_type' => array(
+        'description' => t('The type of entity.'),
+        'type' => 'varchar',
+        'length' => 128,
+        'not null' => TRUE,
+      ),
+      'bundle' => array(
+        'description' => t('The bundle to index.'),
+        'type' => 'varchar',
+        'length' => 128,
+        'not null' => TRUE,
+      ),
+    ),
+    'primary key' => array('core', 'entity_type', 'bundle'),
+  );
+
+  return $schema;
+}
diff --git a/apachesolr_indexer/apachesolr_indexer.module b/apachesolr_indexer/apachesolr_indexer.module
new file mode 100644
index 0000000..325df2d
--- /dev/null
+++ b/apachesolr_indexer/apachesolr_indexer.module
@@ -0,0 +1,1078 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ *   Indexer for the ApacheSolr module.
+ */
+
+/**
+ * Implements hook_permission().
+ */
+function apachesolr_permission() {
+  return array(
+    'configure indexing settings' => array(
+      'title' => t('Configure indexing settings'),
+      'description' => t('Configure how Apachesolr will index content and what content will get indexed.'),
+    ),
+  );
+}
+
+/**
+ * Implements hook_menu().
+ */
+function apachesolr_indexer_menu() {
+
+  $items['admin/config/search/apachesolr/indexer'] = array(
+    'title' => 'Indexing',
+    'page callback' => 'apachesolr_indexer_configure',
+    'file' => 'apachesolr_indexer.admin.inc',
+    'access arguments' => array('configure indexing settings'),
+    'type' => MENU_LOCAL_TASK,
+    'weight' => -8,
+  );
+  $items['admin/config/search/apachesolr/indexer/status'] = array(
+    'title' => 'Indexing',
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+    'weight' => -1,
+  );
+  $items['admin/config/search/apachesolr/indexer/reindex/delete'] = array(
+    'title' => 'Reindex',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('apachesolr_indexer_action_form_delete_confirm'),
+    'file' => 'apachesolr_indexer.admin.inc',
+    'access arguments' => array('configure indexing settings'),
+    'type' => MENU_CALLBACK,
+  );
+  $items['admin/config/search/apachesolr/indexer/reindex/reset'] = array(
+    'title' => 'Reindex',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('apachesolr_indexer_action_form_reset_confirm'),
+    'file' => 'apachesolr_indexer.admin.inc',
+    'access arguments' => array('configure indexing settings'),
+    'type' => MENU_CALLBACK,
+  );
+  $items['admin/config/search/apachesolr/index/confirm/clear'] = array(
+    'title'              => 'Confirm the re-indexing of all content',
+    'page callback'      => 'drupal_get_form',
+    'page arguments'     => array('apachesolr_clear_index_confirm'),
+    'access arguments'   => array('administer search'),
+    'file'               => 'apachesolr.admin.inc',
+    'type'               => MENU_CALLBACK,
+  );
+  $items['admin/config/search/apachesolr/index/confirm/delete'] = array(
+    'title'              => 'Confirm index deletion',
+    'page callback'      => 'drupal_get_form',
+    'page arguments'     => array('apachesolr_delete_index_confirm'),
+    'access arguments'   => array('administer search'),
+    'file'               => 'apachesolr.admin.inc',
+    'type'               => MENU_CALLBACK,
+  );
+  return $items;
+}
+
+/**
+ * Implements hook_entity_info_alter().
+ */
+function apachesolr_indexer_entity_info_alter(&$entity_info) {
+  $default_info = apachesolr_indexer_get_entity_defaults();
+  // First set defaults so that we needn't worry about NULL keys.
+  foreach (array_keys($entity_info) as $type) {
+    $entity_info[$type]['apachesolr'] = array();
+    if (isset($default_info[$type])) {
+      $entity_info[$type]['apachesolr'] += $default_info[$type];
+    }
+    $default = array(
+      'indexable' => FALSE,
+      'status callback' => '',
+      'document callback' => '',
+      'reindex callback' => '',
+    );
+    $entity_info[$type]['apachesolr'] += $default;
+  }
+
+
+
+  // For any supported entity type and bundle, flag it for indexing.
+  foreach ($entity_info as $entity_type => $info) {
+    if ($info['apachesolr']['indexable']) {
+      $supported = apachesolr_indexer_get_bundles('default', $entity_type);
+      foreach (array_keys($info['bundles']) as $bundle) {
+        if (in_array($bundle, $supported)) {
+          $entity_info[$entity_type]['bundles'][$bundle]['apachesolr']['index'] = TRUE;
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Getting the default callbacks for the entity index functions
+ */
+function apachesolr_indexer_get_entity_defaults() {
+  // Set those values that we know.  Other modules can do so
+  // for their own entities if they want.
+  $entity_info['node']['indexable'] = TRUE;
+  $entity_info['node']['status callback'] = 'apachesolr_indexer_node_status_callback';
+  $entity_info['node']['document callback'][] = 'apachesolr_indexer_solr_document_node';
+  $entity_info['node']['reindex callback'] = 'apachesolr_indexer_solr_reindex_node';
+  $entity_info['node']['index_table'] = 'apachesolr_indexer_entities_node';
+
+  $entity_info['user']['indexable'] = TRUE;
+  $entity_info['user']['status callback'] = 'apachesolr_indexer_user_status_callback';
+  $entity_info['user']['document callback'][] = 'apachesolr_indexer_solr_document_user';
+  $entity_info['user']['reindex callback'] = 'apachesolr_indexer_solr_reindex_user';
+  $entity_info['user']['index_table'] = 'apachesolr_indexer_entities_user';
+
+  $entity_info['taxonomy_term']['indexable'] = TRUE;
+  $entity_info['taxonomy_term']['status callback'] = 'apachesolr_indexer_taxonomy_term_status_callback';
+  $entity_info['taxonomy_term']['document callback'][] = 'apachesolr_indexer_solr_document_taxonomy_term';
+  $entity_info['taxonomy_term']['reindex callback'] = 'apachesolr_indexer_solr_reindex_taxonomy_term';
+  $entity_info['taxonomy_term']['index_table'] = 'apachesolr_indexer_entities_term';
+
+  //Allow implementations of HOOK_apachesolr_indexer_get_entity_defaults_alter to modify these default indexers
+  drupal_alter('apachesolr_indexer_get_entity_defaults', $entity_info);
+
+  return $entity_info;
+}
+
+/**
+ * Reindexing callback for ApacheSolr, for nodes.
+ */
+function apachesolr_indexer_solr_reindex_node() {
+
+  $indexer_table = apachesolr_indexer_get_indexer_table('node');
+  $transaction = db_transaction();
+  try {
+    db_delete($indexer_table)
+      ->condition('entity_type', 'node')
+      ->execute();
+
+    $select = db_select('node', 'n');
+    $select->addExpression("'node'", 'entity_type');
+    $select->addField('n', 'nid', 'entity_id');
+    $select->addField('n', 'type', 'bundle');
+    $select->addField('n', 'status', 'status');
+    $select->addExpression(REQUEST_TIME, 'changed');
+    $select->condition('n.type', apachesolr_indexer_get_bundles('default', 'node'), 'IN');
+
+    $insert = db_insert($indexer_table)
+      ->fields(array('entity_id', 'bundle', 'status', 'entity_type', 'changed'))
+      ->from($select)
+      ->execute();
+  }
+  catch (Exception $e) {
+    $transaction->rollback();
+    //drupal_set_message($e->getMessage(), 'error');
+    watchdog_exception('Apache Solr', $e);
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+/**
+ * Reindexing callback for ApacheSolr, for users.
+ */
+function apachesolr_indexer_solr_reindex_user() {
+
+  $indexer_table = apachesolr_indexer_get_indexer_table('user');
+  $transaction = db_transaction();
+  try {
+    db_delete($indexer_table)
+      ->condition('entity_type', 'user')
+      ->execute();
+
+    // We know there's only one bundle type, so if that doesn't get indexed just
+    // skip this entirely.
+    if (apachesolr_indexer_get_bundles('default', 'user')) {
+      $select = db_select('users', 'u');
+      $select->addExpression("'user'", 'entity_type');
+      $select->addExpression("'user'", 'bundle');
+      $select->addField('u', 'uid', 'entity_id');
+      $select->addField('u', 'status', 'status');
+      $select->addExpression(REQUEST_TIME, 'changed');
+
+      $insert = db_insert($indexer_table)
+        ->fields(array('entity_id', 'status', 'entity_type', 'bundle', 'changed'))
+        ->from($select)
+        ->execute();
+    }
+  }
+  catch (Exception $e) {
+    $transaction->rollback();
+    drupal_set_message($e->getMessage(), 'error');
+    watchdog_exception('Apache Solr', $e);
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+
+/**
+ * Reindexing callback for ApacheSolr, for taxonomy terms.
+ */
+function apachesolr_indexer_solr_reindex_taxonomy_term() {
+
+  $indexer_table = apachesolr_indexer_get_indexer_table('taxonomy_term');
+  $transaction = db_transaction();
+  try {
+    db_delete($indexer_table)
+      ->condition('entity_type', 'taxonomy_term')
+      ->execute();
+
+    $select = db_select('taxonomy_term_data', 't');
+    $select->innerJoin('taxonomy_vocabulary', 'v', 't.vid = v.vid');
+
+    $select->addField('t', 'tid', 'entity_id');
+    $select->addField('v', 'machine_name', 'bundle');
+    $select->addExpression(1, 'status');
+    $select->addExpression("'taxonomy_term'", 'entity_type');
+    $select->addExpression(REQUEST_TIME, 'changed');
+
+    $select->condition('v.machine_name', apachesolr_indexer_get_bundles('default', 'taxonomy_term'), 'IN');
+
+    $insert = db_insert($indexer_table)
+      ->fields(array('entity_id', 'bundle', 'status', 'entity_type', 'changed'))
+      ->from($select)
+      ->execute();
+  }
+  catch (Exception $e) {
+    $transaction->rollback();
+    //drupal_set_message($e->getMessage(), 'error');
+    watchdog_exception('Apache Solr', $e);
+    return FALSE;
+  }
+
+  return TRUE;
+
+}
+
+/**
+ * Status callback for ApacheSolr, for nodes.
+ */
+function apachesolr_indexer_node_status_callback($node, $type) {
+  return $node->status;
+}
+
+/**
+ * Status callback for ApacheSolr, for users.
+ */
+function apachesolr_indexer_user_status_callback($user, $type) {
+  return $user->status;
+}
+/**
+ * Status callback for ApacheSolr, for users.
+ */
+function apachesolr_indexer_taxonomy_term_status_callback($user, $type) {
+  return TRUE;
+}
+
+/**
+ * Implements hook_cron().
+ */
+function apachesolr_indexer_cron() {
+  $cron_limit = variable_get('apachesolr_cron_limit', 50);
+
+  $rows = apachesolr_indexer_get_entities_to_index('apachesolr_search', $cron_limit);
+
+  $documents = array();
+  foreach ($rows as $row) {
+    $documents = array_merge($documents, apachesolr_indexer_index_entity($row));
+  }
+  apachesolr_indexer_send_to_solr($documents);
+  apachesolr_index_set_last_updated(REQUEST_TIME);
+}
+
+
+/**
+ * Worker callback for apachesolr_indexer_entities.
+ *
+ * @see apachesolr_index_nodes() for the old-skool version.
+ * @return array of documents that need to be sent to the index of solr
+ */
+
+function apachesolr_indexer_index_entity($item) {
+
+  // Always build the content for the index as an anonynmous user to avoid
+  // exposing restricted fields and such.
+  // @todo Uncomment these lines when we're done debugging, since they break dpm().
+  global $user;
+  drupal_save_session(FALSE);
+  $saved_user = $user;
+  $user = drupal_anonymous_user();
+
+  // Pull out all of our pertinent data.
+  $entity_type = $item->entity_type;
+
+  // TRUE on reset to bypass static caching and not blow out our memory limit.
+  $entity = entity_load($entity_type, array($item->entity_id), array(), TRUE);
+  $entity = $entity ? reset($entity) : FALSE;
+
+  if (empty($entity)) {
+    // If the object failed to load, just stop.
+    return FALSE;
+  }
+
+  list($entity_id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
+
+  //$status = apachesolr_entity_get_callback($entity, $type, 'status callback', array($entity, $type));
+
+  // Create a new document, and do the bare minimum on it.
+  $document = _apachesolr_indexer_process_entity_get_document($entity, $entity_type);
+
+  //Get the callback array to add stuff to the document
+  $callbacks = apachesolr_entity_get_callback($entity_type, 'document callback');
+  $documents = array();
+  foreach ($callbacks as $callback) {
+    // Call a type-specific callback to add stuff to the document.
+    $documents = array_merge($documents, $callback($document, $entity, $entity_type));
+  }
+
+  //do this for all possible documents that were returned by the callbacks
+  foreach ($documents as $id => $document) {
+    // Call an all-entity hook to add stuff to the document.
+    module_invoke_all('apachesolr_indexer_document_build', $documents[$id], $entity, $entity_type);
+
+    // Call a type-specific hook to add stuff to the document.
+    module_invoke_all('apachesolr_indexer_document_' . $entity_type . '_build', $documents[$id], $entity, $entity_type);
+
+    // Call a bundle-specific hook if available.
+    module_invoke_all('apachesolr_indexer_document_' . $entity_type . '_' . $bundle . '_build', $documents[$id], $entity, $entity_type);
+
+    // Now allow modules to alter each other's additions for maximum flexibility.
+    drupal_alter('apachesolr_indexer_document', $documents[$id], $entity, $entity_type);
+    drupal_alter('apachesolr_indexer_document_' . $entity_type, $documents[$id], $entity, $entity_type);
+    drupal_alter('apachesolr_indexer_document_' . $entity_type . '_' . $bundle, $documents[$id], $entity, $entity_type);
+    // Final processing to ensure that the document is properly structured.
+
+    // All records must have a label field, which is used for user-friendly labeling.
+    if (empty($documents[$id]->label)) {
+      $documents[$id]->label = '';
+    }
+
+    // All records must have a "body" field, which is used for fulltext indexing.
+    // If we don't have one, enter an empty value.  This does mean that the entity
+    // will not be fulltext searchable.
+    if (empty($documents[$id]->content)) {
+      $documents[$id]->content = '';
+    }
+
+    // All records must have a "teaser" field, which is used for abbreviated
+    // displays when no highlighted text is available.
+    if (empty($documents[$id]->teaser)) {
+      $documents[$id]->teaser = truncate_utf8($documents[$id]->content, 300, TRUE);
+    }
+
+    // Add additional indexing based on the body of each record.
+    apachesolr_indexer_add_tags_to_document($documents[$id], $documents[$id]->content);
+  }
+
+  return $documents;
+
+
+  // Restore the user.
+  // @todo Uncomment these lines when we're done debugging, since they break dpm().
+  $user = $saved_user;
+  drupal_save_session(TRUE);
+
+}
+
+function apachesolr_indexer_send_to_solr($documents) {
+
+  try {
+    // Get the $solr object
+    $solr = apachesolr_get_solr();
+    // If there is no server available, don't continue.
+    if (!$solr->ping(variable_get('apachesolr_ping_timeout', 4))) {
+      throw new Exception(t('No Solr instance available during indexing.'));
+    }
+  }
+  catch (Exception $e) {
+    watchdog('Apache Solr', nl2br(check_plain($e->getMessage())), NULL, WATCHDOG_ERROR);
+    return FALSE;
+  }
+
+  // Send the document off to Solr.
+  watchdog('Apache Solr', 'Adding @count documents.', array('@count' => count($documents)));
+  try {
+    $docs_chunk = array_chunk($documents, 20);
+    foreach ($docs_chunk as $docs) {
+      $solr->addDocuments($docs);
+    }
+    $ret = $solr->addDocuments($documents);
+    watchdog('Apache Solr', 'Indexing succeeded on @count documents', array(
+      '@count' => count($documents),
+    ), WATCHDOG_INFO);
+  }
+  catch (Exception $e) {
+    if (!empty($docs)) {
+      foreach ($docs as $doc) {
+        $eids[] = $doc->entity_id;
+      }
+    }
+    watchdog('Apache Solr', 'Indexing failed on one of the following entity ids: @eids <br /> !message', array(
+      '@eids' => implode(', ', $eids),
+      '!message' => nl2br(strip_tags($e->getMessage())),
+    ), WATCHDOG_ERROR);
+    // dpm($e->getMessage());
+    return FALSE;
+  }
+}
+
+/**
+ * Builds the node-specific information for a Solr document.
+ *
+ * @param ApacheSolrDocument $document
+ *   The Solr document we are building up.
+ * @param stdClass $entity
+ *   The entity we are indexing.
+ * @param string $entity_type
+ *   The type of entity we're dealing with.
+ */
+function apachesolr_indexer_solr_document_node(ApacheSolrDocument $document, $node, $entity_type) {
+
+  // None of these get added unless they are explicitly in our schema.xml
+
+  $document->label = apachesolr_clean_text($node->title);
+
+  // Build the node body.
+  $build = node_view($node, 'search_index');
+  // Why do we need this?
+  unset($build['#theme']);
+  $text = drupal_render($build);
+  $node->label = apachesolr_clean_text($node->title);
+
+
+  $document->ss_name = $node->name;
+  // We want the name to ale be searchable for keywords.
+  $document->tos_name = $node->name;
+
+  // Everything else uses dynamic fields
+  $document->is_uid = $node->uid;
+  $document->bs_status = $node->status;
+  $document->bs_sticky = $node->sticky;
+  $document->bs_promote = $node->promote;
+  $document->is_tnid = $node->tnid;
+  $document->bs_translate = $node->translate;
+  if (empty($node->language)) {
+    // 'und' is the language-neutral code in Drupal 7.
+    $document->ss_language = LANGUAGE_NONE;
+  }
+  else {
+    $document->ss_language = $node->language;
+  }
+  $document->ds_created = apachesolr_date_iso($node->created);
+  $document->ds_changed = apachesolr_date_iso($node->changed);
+  if (isset($node->last_comment_timestamp) && !empty($node->comment_count)) {
+    $document->ds_last_comment_timestamp = apachesolr_date_iso($node->last_comment_timestamp);
+    $document->ds_last_comment_or_change = apachesolr_date_iso(max($node->last_comment_timestamp, $node->changed));
+  }
+  else {
+    $document->ds_last_comment_or_change = apachesolr_date_iso($node->changed);
+  }
+  $document->is_comment_count = isset($node->comment_count) ? $node->comment_count : 0;
+
+
+  // @todo The comment stuff may well belong in a comment-specific hook instead.
+  // We should figure that out later.
+
+  // Fetch extra data normally not visible, including comments.
+  // We do this manually (with module_implements instead of node_invoke_nodeapi)
+  // because we want a keyed array to come back. Only in this way can we decide
+  // whether to index comments or not.
+  $extra = array();
+  $exclude_comments = in_array($node->type, variable_get('apachesolr_exclude_comments_types', array()), TRUE);
+  foreach (module_implements('node_update_index') as $module) {
+    if ($exclude_comments && $module == 'comment') {
+      // Don't add comments.
+      continue;
+    }
+    $function = $module . '_node_update_index';
+    if ($output = $function($node)) {
+      $extra[$module] = $output;
+    }
+  }
+  if (!variable_get('apachesolr_index_comments_with_node', TRUE)) {
+    unset($extra['comment']);
+  }
+
+  $text .= "\n\n" . implode(' ', $extra);
+
+  $document->content = apachesolr_clean_text($text);
+  if (isset($node->teaser)) {
+    $document->teaser = apachesolr_clean_text($node->teaser);
+  }
+  else {
+    $document->teaser = truncate_utf8($document->content, 300, TRUE);
+  }
+
+  $document->type_name = node_type_get_name($node);
+  $document->created = apachesolr_date_iso($node->created);
+  $document->changed = apachesolr_date_iso($node->changed);
+  $last_change = (isset($node->last_comment_timestamp) && $node->last_comment_timestamp > $node->changed) ? $node->last_comment_timestamp : $node->changed;
+  $document->last_comment_or_change = apachesolr_date_iso($last_change);
+  $document->comment_count = isset($node->comment_count) ? $node->comment_count : 0;
+
+  // We need to get the real username here, since it needs a full user object.
+  // That means we can't do the format_username() call on the display side.
+  $document->name = format_username(user_load($node->uid));
+
+  //  Generic usecase for future reference. Callbacks can
+  //  allow you to send back multiple documents
+  $documents = array();
+  $documents[] = $document;
+  return $documents;
+}
+
+
+/**
+ * Builds the user-specific information for a Solr document.
+ *
+ * @param ApacheSolrDocument $document
+ *   The Solr document we are building up.
+ * @param stdClass $entity
+ *   The entity we are indexing.
+ * @param string $entity_type
+ *   The type of entity we're dealing with.
+ */
+function apachesolr_indexer_solr_document_user(ApacheSolrDocument $document, $account, $entity_type) {
+
+  $document->uid = $account->uid;
+
+  // Title is a required field.
+  $document->label = apachesolr_clean_text(format_username($account));
+
+  $document->mail = $account->mail;
+  $document->signature = $account->signature;
+
+  // Note the conspicuous lack of password hash. :-)
+
+  // Build the user body.
+  $build = user_view($account, 'search_index');
+  // Why do we need this?
+  unset($build['#theme']);
+  $text = drupal_render($build);
+
+  $document->content = apachesolr_clean_text($text);
+
+  $document->created = apachesolr_date_iso($account->created);
+  $document->access = apachesolr_date_iso($account->access);
+
+  //  Generic usecase for future reference. Callbacks can
+  //  allow you to send back multiple documents
+  $documents = array();
+  $documents[] = $document;
+  return $documents;
+}
+
+
+function apachesolr_indexer_solr_taxonomy_ancestors($term) {
+  static $ancestors = array();
+
+  $vocab_names = array();
+  if (!isset($ancestors[$term->tid])) {
+    $ancestors[$term->tid] = taxonomy_get_parents_all($term->tid);
+  }
+  foreach ($ancestors[$term->tid] as $ancestor) {
+    // Index parent term against the field. Note that this happens
+    // regardless of whether the facet is set to show as a hierarchy or not.
+    // We would need a separate field if we were to index terms without any
+    // hierarchy at all.
+
+    $fields[] = array(
+      'key' => 'tid',
+      'value' => $ancestor->tid,
+    );
+    $fields[] = array(
+      'key' => 'im_vid_' . $ancestor->vid,
+      'value' => $ancestor->tid,
+    );
+    $name = apachesolr_clean_text($ancestor->name);
+    $vocab_names[$ancestor->vid][] = $name;
+    // We index each name as a string for cross-site faceting
+    // using the vocab name rather than vid in field construction .
+    $fields[] = array(
+      'key' => 'sm_vid_' . apachesolr_vocab_name($ancestor->vid),
+      'value' => $name,
+    );
+  }
+
+  foreach ($vocab_names as $vid => $names) {
+    $fields[] = array(
+      'key' => 'tm_vid_' . $vid . '_names',
+      'value' => implode(' ', $names),
+    );
+  }
+
+  return $fields;
+
+}
+
+/**
+ * Builds the user-specific information for a Solr document.
+ *
+ * @param ApacheSolrDocument $document
+ *   The Solr document we are building up.
+ * @param stdClass $entity
+ *   The entity we are indexing.
+ * @param string $entity_type
+ *   The type of entity we're dealing with.
+ */
+function apachesolr_indexer_solr_document_taxonomy_term(ApacheSolrDocument $document, $term, $entity_type) {
+
+  $document->tid = $term->tid;
+
+  // Title is a required field.
+  $document->label = apachesolr_clean_text(format_username($term));
+
+  $term_tree = apachesolr_indexer_solr_taxonomy_ancestors($term);
+  foreach ($term_tree as $tt => $td) {
+    $document->addField($td['key'], apachesolr_clean_text($td['value']));
+  }
+
+  // Note the conspicuous lack of password hash. :-)
+  $build = taxonomy_term_view($term, 'search_index');
+
+  // Why do we need this?
+  unset($build['#theme']);
+  $text = drupal_render($build);
+
+  $document->content = apachesolr_clean_text($text);
+  //  Generic usecase for future reference. Callbacks can
+  //  allow you to send back multiple documents
+  $documents = array();
+  $documents[] = $document;
+  return $documents;
+
+}
+
+/**
+ * Extract HTML tag contents from $text and add to boost fields.
+ *
+ * $text must be stripped of control characters before hand.
+ */
+function apachesolr_indexer_add_tags_to_document(&$document, $text) {
+  $tags_to_index = variable_get('apachesolr_tags_to_index', array(
+    'h1' => 'tags_h1',
+    'h2' => 'tags_h2_h3',
+    'h3' => 'tags_h2_h3',
+    'h4' => 'tags_h4_h5_h6',
+    'h5' => 'tags_h4_h5_h6',
+    'h6' => 'tags_h4_h5_h6',
+    'u' => 'tags_inline',
+    'b' => 'tags_inline',
+    'i' => 'tags_inline',
+    'strong' => 'tags_inline',
+    'em' => 'tags_inline',
+    'a' => 'tags_a'
+  ));
+
+  // Strip off all ignored tags.
+  $text = strip_tags($text, '<' . implode('><', array_keys($tags_to_index)) . '>');
+
+  preg_match_all('@<(' . implode('|', array_keys($tags_to_index)) . ')[^>]*>(.*)</\1>@Ui', $text, $matches);
+  foreach ($matches[1] as $key => $tag) {
+    $tag = strtolower($tag);
+    // We don't want to index links auto-generated by the url filter.
+    if ($tag != 'a' || !preg_match('@(?:http://|https://|ftp://|mailto:|smb://|afp://|file://|gopher://|news://|ssl://|sslv2://|sslv3://|tls://|tcp://|udp://|www\.)[a-zA-Z0-9]+@', $matches[2][$key])) {
+      if (!isset($document->{$tags_to_index[$tag]})) {
+        $document->{$tags_to_index[$tag]} = '';
+      }
+      $document->{$tags_to_index[$tag]} .= ' ' . apachesolr_clean_text($matches[2][$key]);
+    }
+  }
+}
+
+
+/**
+ * Returns a generic Solr document object for this entity.
+ *
+ * This function will do the basic processing for the document that is common
+ * to all entities, but virtually all entities will need their own additional
+ * processing.
+ *
+ * @param stdClass $entity
+ *   The entity for which we want a document.
+ * @param string $entity_type
+ *   The type of entity we're processing.
+ * @return ApacheSolrDocument
+ */
+function _apachesolr_indexer_process_entity_get_document($entity, $entity_type) {
+
+  list($entity_id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
+
+  $document = new ApacheSolrDocument();
+
+  $document->id = apachesolr_document_id($entity_id, $entity_type);
+  $document->site = url(NULL, array('absolute' => TRUE));
+  $document->hash = apachesolr_site_hash();
+
+  $document->entity_id = $entity_id;
+  $document->entity_type = $entity_type;
+  $document->bundle = $bundle;
+  $document->bundle_name = entity_bundle_label($entity_type, $bundle);
+
+  $path = entity_uri($entity_type, $entity);
+  $document->path = $path['path'];
+  $document->url = url($path['path'], $path['options'] + array('absolute' => TRUE));
+
+  if (empty($entity->language)) {
+    // 'und' is the language-neutral code in Drupal 7.
+    $document->language = LANGUAGE_NONE;
+  }
+  else {
+    $document->language = $entity->language;
+  }
+
+  // Path aliases can have important information about the content.
+  // Add them to the index as well.
+  if (function_exists('drupal_get_path_alias')) {
+    // Add any path alias to the index, looking first for language specific
+    // aliases but using language neutral aliases otherwise.
+    $output = drupal_get_path_alias($document->path, $document->language);
+    if ($output && $output != $document->path) {
+      $document->path_alias = $output;
+    }
+  }
+
+
+  return $document;
+}
+
+
+
+
+/**
+ * Returns an array of rows from a query based on an indexing namespace.
+ * @see apachesolr_get_nodes_to_index for old-skool version
+ */
+function apachesolr_indexer_get_entities_to_index($namespace, $limit) {
+  $rows = array();
+  if (variable_get('apachesolr_read_only', 0)) {
+    return $rows;
+  }
+
+  // set dynamic limit per entity
+  //$entity_count = variable_get('apachesolr_indexer_entity_count', 0);
+
+  // checking on empty because it could be 0
+  //if(!empty($entity_count)) {
+    // give the amount the advantage of upper rounding for better indexing
+  //  $limit = round($limit/$entity_count, 0, PHP_ROUND_HALF_UP);
+  //}
+
+  $last_change = variable_get('apachesolr_indexer_last_run', 0);
+
+
+  foreach (entity_get_info() as $type => $info) {
+    $bundles = array();
+    foreach ($info['bundles'] as $bundle => $bundle_info) {
+      if ($bundle && isset($info['bundles'][$bundle]['apachesolr']['index']) && $info['bundles'][$bundle]['apachesolr']['index']) {
+        $bundles[] = $bundle;
+      }
+    }
+
+    // If we're not checking any bundles of this entity type, just skip them all.
+    if (empty($bundles)) {
+      continue;
+    }
+
+    if (isset($info['apachesolr']['index_table'])) {
+      $table = $info['apachesolr']['index_table'];
+    }
+    else {
+      $table = 'apachesolr_indexer_entities';
+    }
+
+    $last_entity_id = variable_get('apachesolr_indexer_last_run_id_' . $type, 0);
+
+    // Find the next batch of entities to index for this entity type.  Note that
+    // for ordering we're grabbing the oldest first and then ordering by ID so
+    // that we get a definitive order.
+
+    $query = db_select($table, 'aie')
+      ->fields('aie', array('entity_type', 'entity_id', 'changed'))
+      ->condition('aie.status', 1)
+      ->condition('aie.entity_type', $type)
+      ->condition('aie.bundle', $bundles)
+      ->condition(db_or()->condition('aie.changed', $last_change, '>')
+                         ->condition('aie.changed', $last_change)
+                         ->condition(db_and()->condition('aie.entity_id', $last_entity_id, '>')))
+      ->orderBy('aie.changed')
+      ->orderBy('aie.entity_id')
+      ->range(0, $limit);
+
+    $records = $query->execute()->fetchAll();
+
+    // @todo This assumes an int ID, which technically the entity system
+    // doesn't require.  Fix this later.
+    $max_id = 0;
+    foreach ($records as $record) {
+      $rows[] = $record;
+      $max_id = max($max_id, $record->entity_id);
+    }
+
+    //do not set it to 0 because this would enable reindexing of all the types
+    if (!empty($max_id)) {
+      variable_set('apachesolr_indexer_last_run_id_' . $type, $max_id);
+    }
+  }
+
+  return $rows;
+}
+
+/**
+ * Implements hook_entity_insert().
+ */
+function apachesolr_indexer_entity_insert($entity, $type) {
+  // For our purposes there's really no difference between insert and update.
+  return apachesolr_indexer_entity_update($entity, $type);
+}
+
+/**
+ * Implements hook_entity_update().
+ */
+function apachesolr_indexer_entity_update($entity, $type) {
+
+  if (apachesolr_entity_should_index($entity, $type)) {
+    $info = entity_get_info($type);
+    list($id, $vid, $bundle) = entity_extract_ids($type, $entity);
+
+    $status_callback = apachesolr_entity_get_callback($type, 'status callback');
+    $status = 0;
+    if (is_callable($status_callback)) {
+      $status = $status_callback($entity, $type);
+    }
+
+    $indexer_table = apachesolr_indexer_get_indexer_table($type);
+
+    // If we haven't seen this entity before it may not be there, so merge
+    // instead of update.
+    db_merge($indexer_table)
+      ->key(array(
+      'entity_type' => $type,
+      'entity_id' => $id,
+      ))
+      ->fields(array(
+        'bundle' => $bundle,
+        'status' => $status,
+        'changed' => REQUEST_TIME,
+      ))
+      ->execute();
+  }
+}
+
+/**
+ * Implements hook_entity_delete().
+ *
+ * @see apachesolr_node_delete().
+ */
+function apachesolr_indexer_entity_delete($entity, $type) {
+  if (apachesolr_indexer_delete_entity_from_index($type, $entity)) {
+    // There was no exception, so delete from the table.
+    list($id) = entity_extract_ids($type, $entity);
+    $indexer_table = apachesolr_indexer_get_indexer_table($type);
+    db_delete($indexer_table)
+      ->condition('entity_type', $type)
+      ->condition('entity_id', $id)
+      ->execute();
+  }
+}
+
+/**
+ * Delete an entity from the indexer.
+ */
+function apachesolr_indexer_delete_entity_from_index($entity_type, $entity) {
+  static $failed = FALSE;
+  if ($failed) {
+    return FALSE;
+  }
+  try {
+    list($id) = entity_extract_ids($entity_type, $entity);
+    $solr = apachesolr_get_solr();
+    $solr->deleteById(apachesolr_document_id($id, $entity_type));
+    apachesolr_index_set_last_updated(REQUEST_TIME);
+    return TRUE;
+  }
+  catch (Exception $e) {
+    watchdog('Apache Solr', nl2br(check_plain($e->getMessage())), NULL, WATCHDOG_ERROR);
+    // Don't keep trying queries if they are failing.
+    $failed = TRUE;
+    return FALSE;
+  }
+}
+
+function apachesolr_indexer_get_indexer_table($type) {
+      $defaults = apachesolr_indexer_get_entity_defaults();
+    if (isset($defaults[$type]['index_table'])) {
+      $indexer_table = $defaults[$type]['index_table'];
+    }
+    else {
+      $indexer_table = 'apachesolr_indexer_entities';
+    }
+    return $indexer_table;
+}
+/**
+ * Sets what bundles on the specified entity type should be indexed.
+ *
+ * @param string $core
+ *   The Solr core for which to index entities.
+ * @param string $entity_type
+ *   The entity type to index.
+ * @param array $bundles
+ *   The machine names of the bundles to index.
+ */
+function apachesolr_indexer_set_bundles($core, $entity_type, array $bundles) {
+
+  $transaction = db_transaction();
+  try {
+    db_delete('apachesolr_indexer_bundles')
+      ->condition('core', $core)
+      ->condition('entity_type', $entity_type)
+      ->execute();
+
+    if ($bundles) {
+      $insert = db_insert('apachesolr_indexer_bundles')
+        ->fields(array('core', 'entity_type', 'bundle'));
+
+      foreach ($bundles as $bundle) {
+        $insert->values(array(
+          'core' => $core,
+          'entity_type' => $entity_type,
+          'bundle' => $bundle,
+        ));
+      }
+
+        $insert->execute();
+    }
+
+  }
+  catch (Exception $e) {
+    $transaction->rollback();
+    watchdog_exception('Apache Solr', $e);
+  }
+}
+
+/**
+ * Gets a list of the bundles on the specified entity type that should be indexed.
+ *
+ * @param string $core
+ *   The Solr core for which to index entities.
+ * @param string $entity_type
+ *   The entity type to index.
+ * @return array
+ *   The bundles that should be indexed.
+ */
+function apachesolr_indexer_get_bundles($core, $entity_type) {
+  return db_query("SELECT bundle FROM {apachesolr_indexer_bundles} WHERE core = :core AND entity_type = :entity_type", array(
+    ':core' => $core,
+    ':entity_type' => $entity_type,
+  ))->fetchCol();
+}
+
+/**
+ * Implements hook_hook_info().
+ */
+function apachesolr_indexer_hook_info() {
+
+  $hooks['apachesolr_indexer_document_build'] = array(
+    'group' => 'apachesolr',
+  );
+  $hooks['apachesolr_indexer_document_alter'] = array(
+    'group' => 'apachesolr',
+  );
+/*
+
+  foreach (entity_get_info() as $entity_type => $info) {
+    $hooks['apachesolr_indexer_document_' . $entity_type . '_build'] = array(
+      'group' => 'apachesolr',
+    );
+    $hooks['apachesolr_indexer_document_' . $entity_type . '_alter'] = array(
+      'group' => 'apachesolr',
+    );
+    foreach ($info['bundles'] as $bundle => $bundle_info) {
+      $hooks['apachesolr_indexer_document_' . $entity_type . '_' . $bundle . '_build'] = array(
+        'group' => 'apachesolr',
+      );
+      $hooks['apachesolr_indexer_document_' . $entity_type . '_' . $bundle . '_alter'] = array(
+        'group' => 'apachesolr',
+      );
+    }
+  }
+*/
+  return $hooks;
+}
+
+
+/**
+ * Implements hook_apachesolr_indexer_document_build().
+ */
+function field_apachesolr_indexer_document_build(ApacheSolrDocument $document, $entity, $entity_type) {
+  $info = entity_get_info($entity_type);
+  if ($info['fieldable']) {
+    // Handle fields including taxonomy.
+    $indexed_fields = apachesolr_entity_fields($entity_type);
+    foreach ($indexed_fields as $index_key => $field_info) {
+      $field_name = $field_info['field']['field_name'];
+      // See if the node has fields that can be indexed
+      if (isset($entity->{$field_name})) {
+        // Got a field.
+        $function = $field_info['indexing_callback'];
+        if ($function && function_exists($function)) {
+          // NOTE: This function should always return an array.  One
+          // entity field may be indexed to multiple Solr fields.
+          $fields = $function($entity, $field_name, $index_key, $field_info);
+          foreach ($fields as $field) {
+            // It's fine to use this method also for single value fields.
+            $document->setMultiValue($field['key'], $field['value']);
+          }
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_apachesolr_indexer_document_node_book_build().
+ */
+function apachesolr_indexer_apachesolr_indexer_document_node_book_build(ApacheSolrDocument $document, $entity, $entity_type) {
+  // Index book module data.
+  if (!empty($entity->book['bid'])) {
+    // Hard-coded - must change if apachesolr_index_key() changes.
+    $document->is_book_bid = (int) $entity->book['bid'];
+  }
+}
+
+// This really should be in core, but it isn't yet.  When it gets added to core,
+// we can remove this version.
+// @see http://drupal.org/node/969180
+if (!function_exists('entity_bundle_label')) {
+
+/**
+ * Returns the label of a bundle.
+ *
+ * @param $entity_type
+ *   The entity type; e.g. 'node' or 'user'.
+ * @param $entity
+ *   The entity for which we want the human-readable label of its bundle.
+ *
+ * @return
+ *   A string with the human-readable name of the bundle, or FALSE if not specified.
+ */
+function entity_bundle_label($entity_type, $bundle) {
+  $labels = &drupal_static(__FUNCTION__, array());
+
+  if (empty($labels)) {
+    foreach (entity_get_info() as $entity_type => $entity_info) {
+      foreach ($entity_info['bundles'] as $bundle => $bundle_info) {
+        $labels[$entity_type][$bundle] = !empty($bundle_info['label']) ? $bundle_info['label'] : FALSE;
+      }
+    }
+  }
+
+  return $labels[$entity_type][$bundle];
+}
+
+}
diff --git a/apachesolr_search.module b/apachesolr_search.module
index f1e7892..4d4f1bb 100644
--- a/apachesolr_search.module
+++ b/apachesolr_search.module
@@ -205,15 +205,6 @@ function apachesolr_search_page_save($search_page) {
 }
 
 /**
- * Implements hook_cron(). Indexes nodes.
- */
-function apachesolr_search_cron() {
-  $cron_limit = variable_get('apachesolr_cron_limit', 50);
-  $rows = apachesolr_get_nodes_to_index('apachesolr_search', $cron_limit);
-  apachesolr_index_nodes($rows, 'apachesolr_search');
-}
-
-/**
  * Implements hook_apachesolr_types_exclude().
  */
 function apachesolr_search_apachesolr_types_exclude($namespace) {
