diff --git a/src/Entity/Index.php b/src/Entity/Index.php
index fc50125..fab491f 100644
--- a/src/Entity/Index.php
+++ b/src/Entity/Index.php
@@ -688,7 +688,16 @@ public function setProcessors(array $processors) {
   /**
    * {@inheritdoc}
    */
-  public function preprocessIndexItems(array &$items) {
+  public function alterIndexedItems(array &$items) {
+    foreach ($this->getProcessorsByStage(ProcessorInterface::STAGE_ALTER_ITEMS) as $processor) {
+      $processor->alterIndexedItems($items);
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function preprocessIndexItems(array $items) {
     foreach ($this->getProcessorsByStage(ProcessorInterface::STAGE_PREPROCESS_INDEX) as $processor) {
       $processor->preprocessIndexItems($items);
     }
@@ -951,9 +960,6 @@ public function indexSpecificItems(array $search_objects) {
     $items = array();
     foreach ($search_objects as $item_id => $object) {
       $items[$item_id] = Utility::createItemFromObject($this, $object, $item_id);
-      // This will cache the extracted fields so processors, etc., can retrieve
-      // them directly.
-      $items[$item_id]->getFields();
     }
 
     // Remember the items that were initially passed, to be able to determine
@@ -962,7 +968,13 @@ public function indexSpecificItems(array $search_objects) {
     $rejected_ids = array_combine($rejected_ids, $rejected_ids);
 
     // Preprocess the indexed items.
+    $this->alterIndexedItems($items);
     \Drupal::moduleHandler()->alter('search_api_index_items', $this, $items);
+    foreach ($items as $item) {
+      // This will cache the extracted fields so processors, etc., can retrieve
+      // them directly.
+      $item->getFields();
+    }
     $this->preprocessIndexItems($items);
 
     // Remove all items still in $items from $rejected_ids. Thus, only the
diff --git a/src/IndexInterface.php b/src/IndexInterface.php
index 41b5276..8cb6bb7 100644
--- a/src/IndexInterface.php
+++ b/src/IndexInterface.php
@@ -408,14 +408,24 @@ public function removeProcessor($processor_id);
   public function setProcessors(array $processors);
 
   /**
+   * Alter the items to be indexed.
+   *
+   * Lets all enabled processors for this index alter the indexed items.
+   *
+   * @param \Drupal\search_api\Item\ItemInterface[] $items
+   *   An array of items to be indexed, passed by reference.
+   */
+  public function alterIndexedItems(array &$items);
+
+  /**
    * Preprocesses data items for indexing.
    *
    * Lets all enabled processors for this index preprocess the indexed data.
    *
-   * @param array $items
+   * @param \Drupal\search_api\Item\ItemInterface[] $items
    *   An array of items to be preprocessed for indexing.
    */
-  public function preprocessIndexItems(array &$items);
+  public function preprocessIndexItems(array $items);
 
   /**
    * Preprocesses a search query.
diff --git a/src/Plugin/search_api/processor/NodeStatus.php b/src/Plugin/search_api/processor/NodeStatus.php
index 00cba86..e565ef4 100644
--- a/src/Plugin/search_api/processor/NodeStatus.php
+++ b/src/Plugin/search_api/processor/NodeStatus.php
@@ -14,8 +14,8 @@
  *   label = @Translation("Node status"),
  *   description = @Translation("Exclude unpublished nodes from node indexes."),
  *   stages = {
- *     "preprocess_index" = -50
- *   }
+ *     "alter_items" = 0,
+ *   },
  * )
  */
 class NodeStatus extends ProcessorPluginBase {
@@ -35,7 +35,7 @@ public static function supportsIndex(IndexInterface $index) {
   /**
    * {@inheritdoc}
    */
-  public function preprocessIndexItems(array &$items) {
+  public function alterIndexedItems(array &$items) {
     // Annoyingly, this doc comment is needed for PHPStorm. See
     // http://youtrack.jetbrains.com/issue/WI-23586
     /** @var \Drupal\search_api\Item\ItemInterface $item */
diff --git a/src/Plugin/search_api/processor/RoleFilter.php b/src/Plugin/search_api/processor/RoleFilter.php
index fb31db6..5d44243 100644
--- a/src/Plugin/search_api/processor/RoleFilter.php
+++ b/src/Plugin/search_api/processor/RoleFilter.php
@@ -17,8 +17,8 @@
  *   label = @Translation("Role filter"),
  *   description = @Translation("Filters out users based on their role."),
  *   stages = {
- *     "preprocess_index" = -50
- *   }
+ *     "alter_items" = 0,
+ *   },
  * )
  */
 class RoleFilter extends ProcessorPluginBase {
@@ -92,7 +92,7 @@ public function submitConfigurationForm(array &$form, FormStateInterface $form_s
   /**
    * {@inheritdoc}
    */
-  public function preprocessIndexItems(array &$items) {
+  public function alterIndexedItems(array &$items) {
     $selected_roles = array_combine($this->configuration['roles'], $this->configuration['roles']);
     $default = (bool) $this->configuration['default'];
 
diff --git a/src/Processor/FieldsProcessorPluginBase.php b/src/Processor/FieldsProcessorPluginBase.php
index 9b74a88..3f8ad6b 100644
--- a/src/Processor/FieldsProcessorPluginBase.php
+++ b/src/Processor/FieldsProcessorPluginBase.php
@@ -84,7 +84,7 @@ public function validateConfigurationForm(array &$form, FormStateInterface $form
   /**
    * {@inheritdoc}
    */
-  public function preprocessIndexItems(array &$items) {
+  public function preprocessIndexItems(array $items) {
     // Annoyingly, this doc comment is needed for PHPStorm. See
     // http://youtrack.jetbrains.com/issue/WI-23586
     /** @var \Drupal\search_api\Item\ItemInterface $item */
diff --git a/src/Processor/ProcessorInterface.php b/src/Processor/ProcessorInterface.php
index 714cf72..0d8fae0 100644
--- a/src/Processor/ProcessorInterface.php
+++ b/src/Processor/ProcessorInterface.php
@@ -27,26 +27,44 @@
 
   /**
    * Processing stage: add properties.
+   *
+   * @see \Drupal\search_api\Processor\ProcessorInterface::getPropertyDefinitions()
+   * @see \Drupal\search_api\Processor\ProcessorInterface::addFieldValues()
    */
   const STAGE_ADD_PROPERTIES = 'add_properties';
 
   /**
    * Processing stage: preprocess index.
+   *
+   * @see \Drupal\search_api\Processor\ProcessorInterface::preIndexSave()
    */
   const STAGE_PRE_INDEX_SAVE = 'pre_index_save';
 
   /**
+   * Processing stage: alter indexed items.
+   *
+   * @see \Drupal\search_api\Processor\ProcessorInterface::alterIndexedItems()
+   */
+  const STAGE_ALTER_ITEMS = 'alter_items';
+
+  /**
    * Processing stage: preprocess index.
+   *
+   * @see \Drupal\search_api\Processor\ProcessorInterface::preprocessIndexItems()
    */
   const STAGE_PREPROCESS_INDEX = 'preprocess_index';
 
   /**
    * Processing stage: preprocess query.
+   *
+   * @see \Drupal\search_api\Processor\ProcessorInterface::preprocessSearchQuery()
    */
   const STAGE_PREPROCESS_QUERY = 'preprocess_query';
 
   /**
    * Processing stage: postprocess query.
+   *
+   * @see \Drupal\search_api\Processor\ProcessorInterface::postprocessSearchResults()
    */
   const STAGE_POSTPROCESS_QUERY = 'postprocess_query';
 
@@ -157,12 +175,20 @@ public function addFieldValues(ItemInterface $item);
   public function preIndexSave();
 
   /**
+   * Alter the items to be indexed.
+   *
+   * @param \Drupal\search_api\Item\ItemInterface[] $items
+   *   An array of items to be indexed, passed by reference.
+   */
+  public function alterIndexedItems(array &$items);
+
+  /**
    * Preprocesses search items for indexing.
    *
    * @param \Drupal\search_api\Item\ItemInterface[] $items
-   *   An array of items to be preprocessed for indexing, passed by reference.
+   *   An array of items to be preprocessed for indexing.
    */
-  public function preprocessIndexItems(array &$items);
+  public function preprocessIndexItems(array $items);
 
   /**
    * Preprocesses a search query.
diff --git a/src/Processor/ProcessorPluginBase.php b/src/Processor/ProcessorPluginBase.php
index c10de94..25341d2 100644
--- a/src/Processor/ProcessorPluginBase.php
+++ b/src/Processor/ProcessorPluginBase.php
@@ -314,7 +314,12 @@ protected function extractItemValues(array $items, array $required_properties, $
   /**
    * {@inheritdoc}
    */
-  public function preprocessIndexItems(array &$items) {}
+  public function alterIndexedItems(array &$items) {}
+
+  /**
+   * {@inheritdoc}
+   */
+  public function preprocessIndexItems(array $items) {}
 
   /**
    * {@inheritdoc}
diff --git a/src/Tests/HooksTest.php b/src/Tests/HooksTest.php
index 16c4487..6be4622 100644
--- a/src/Tests/HooksTest.php
+++ b/src/Tests/HooksTest.php
@@ -2,6 +2,8 @@
 
 namespace Drupal\search_api\Tests;
 
+use Drupal\search_api_test\PluginTestTrait;
+
 /**
  * Tests integration of hooks.
  *
@@ -9,6 +11,8 @@
  */
 class HooksTest extends WebTestBase {
 
+  use PluginTestTrait;
+
   /**
    * {@inheritdoc}
    */
@@ -41,7 +45,16 @@ public function setUp() {
 
     // Create an index and server to work with.
     $this->getTestServer();
-    $this->getTestIndex();
+    $index = $this->getTestIndex();
+
+    // Add the test processor to the index so we can make sure that all expected
+    // processor methods are called, too.
+    /** @var \Drupal\search_api\Processor\ProcessorInterface $processor */
+    $processor = $index->createPlugin('processor', 'search_api_test');
+    $index->addProcessor($processor)->save();
+
+    // Reset the called methods on the processor.
+    $this->getCalledMethods('processor');
 
     // Log in, so we can test all the things.
     $this->drupalLogin($this->adminUser);
@@ -51,51 +64,67 @@ public function setUp() {
    * Tests various operations via the Search API's admin UI.
    */
   public function testHooks() {
-    // hook_search_api_backend_info_alter was triggered.
+    // hook_search_api_backend_info_alter() was invoked.
     $this->drupalGet('admin/config/search/search-api/add-server');
     $this->assertText('Slims return');
 
-    // hook_search_api_datasource_info_alter was triggered.
+    // hook_search_api_datasource_info_alter() was invoked.
     $this->drupalGet('admin/config/search/search-api/add-index');
     $this->assertText('Distant land');
 
-    // hook_search_api_processor_info_alter was triggered.
+    // hook_search_api_processor_info_alter() was invoked.
     $this->drupalGet($this->getIndexPath('processors'));
     $this->assertText('Mystic bounce');
 
+    // Saving the index should trigger the processor's preIndexSave() method.
+    $this->drupalPostForm(NULL, array(), $this->t('Save'));
+    $processor_methods = $this->getCalledMethods('processor');
+    $this->assertEqual(array('preIndexSave'), $processor_methods);
+
     $this->drupalGet($this->getIndexPath());
-    $this->drupalPostForm(NULL, [], $this->t('Index now'));
+    $this->drupalPostForm(NULL, array(), $this->t('Index now'));
+
+    // During indexing, alterIndexedItems() and preprocessIndexItems() should be
+    // called on the processor.
+    $processor_methods = $this->getCalledMethods('processor');
+    $expected = array('alterIndexedItems', 'preprocessIndexItems');
+    $this->assertEqual($expected, $processor_methods);
 
-    // hook_search_api_index_items_alter was triggered, this removed node:1.
-    // hook_search_api_query_TAG_alter was triggered, this removed node:3.
+    // hook_search_api_index_items_alter() was invoked, this removed node:1.
+    // hook_search_api_query_TAG_alter() was invoked, this removed node:3.
     $this->assertText('There are 2 items indexed on the server for this index.');
     $this->assertText('Successfully indexed 4 items.');
     $this->assertText('Stormy');
 
-    // hook_search_api_items_indexed was triggered.
+    // hook_search_api_items_indexed() was invoked.
     $this->assertText('Please set me at ease');
 
-    // hook_search_api_index_reindex was triggered.
+    // hook_search_api_index_reindex() was invoked.
     $this->drupalGet($this->getIndexPath('reindex'));
-    $this->drupalPostForm(NULL, [], $this->t('Confirm'));
+    $this->drupalPostForm(NULL, array(), $this->t('Confirm'));
     $this->assertText('Montara');
 
-    // hook_search_api_data_type_info_alter was triggered.
+    // hook_search_api_data_type_info_alter() was invoked.
     $this->drupalGet($this->getIndexPath('fields'));
     $this->assertText('Peace/Dolphin dance');
-    // The implementation of hook_search_api_field_type_mapping_alter has
+    // The implementation of hook_search_api_field_type_mapping_alter() has
     // removed all dates, so we can't see any timestamp anymore in the page.
     $url_options['query']['datasource'] = 'entity:node';
     $this->drupalGet($this->getIndexPath('fields/add'), $url_options);
     $this->assertNoText('timestamp');
 
     $this->drupalGet('search-api-test');
-    // hook_search_api_query_alter was triggered.
+    // hook_search_api_query_alter() was invoked.
     $this->assertText('Funky blue note');
-    // hook_search_api_results_alter was triggered.
+    // hook_search_api_results_alter() was invoked.
     $this->assertText('Stepping into tomorrow');
-    // hook_search_api_results_TAG_alter was triggered.
+    // hook_search_api_results_TAG_alter() was invoked.
     $this->assertText('Llama');
+
+    // The query alter methods of the processor were called.
+    $processor_methods = $this->getCalledMethods('processor');
+    $expected = array('preprocessSearchQuery', 'postprocessSearchResults');
+    $this->assertEqual($expected, $processor_methods);
   }
 
 }
diff --git a/tests/search_api_test/src/Plugin/search_api/processor/TestProcessor.php b/tests/search_api_test/src/Plugin/search_api/processor/TestProcessor.php
index 27b3cea..d0d5cb6 100644
--- a/tests/search_api_test/src/Plugin/search_api/processor/TestProcessor.php
+++ b/tests/search_api_test/src/Plugin/search_api/processor/TestProcessor.php
@@ -29,6 +29,27 @@ public function supportsStage($stage_identifier) {
   /**
    * {@inheritdoc}
    */
+  public function preIndexSave() {
+    $this->logMethodCall(__FUNCTION__, func_get_args());
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function alterIndexedItems(array &$items) {
+    $this->logMethodCall(__FUNCTION__, func_get_args());
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function preprocessIndexItems(array $items) {
+    $this->logMethodCall(__FUNCTION__, func_get_args());
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function preprocessSearchQuery(QueryInterface $query) {
     $this->logMethodCall(__FUNCTION__, func_get_args());
   }
@@ -44,7 +65,9 @@ public function postprocessSearchResults(ResultSetInterface $results) {
    * {@inheritdoc}
    */
   public function calculateDependencies() {
-    return $this->configuration;
+    $dependencies = $this->configuration;
+    unset($dependencies['weights']);
+    return $dependencies;
   }
 
   /**
diff --git a/tests/src/Unit/Plugin/Processor/NodeStatusTest.php b/tests/src/Unit/Plugin/Processor/NodeStatusTest.php
index 455b5d2..ca30bfd 100644
--- a/tests/src/Unit/Plugin/Processor/NodeStatusTest.php
+++ b/tests/src/Unit/Plugin/Processor/NodeStatusTest.php
@@ -103,7 +103,7 @@ public function testSupportsIndexUnsupported() {
    */
   public function testNodeStatus() {
     $this->assertCount(2, $this->items, '2 nodes in the index.');
-    $this->processor->preprocessIndexItems($this->items);
+    $this->processor->alterIndexedItems($this->items);
     $this->assertCount(1, $this->items, 'An item was removed from the items list.');
     $published_nid = Utility::createCombinedId('entity:node', '2:en');
     $this->assertTrue(isset($this->items[$published_nid]), 'Correct item was removed.');
diff --git a/tests/src/Unit/Plugin/Processor/RoleFilterTest.php b/tests/src/Unit/Plugin/Processor/RoleFilterTest.php
index dcb15a1..47b69c5 100644
--- a/tests/src/Unit/Plugin/Processor/RoleFilterTest.php
+++ b/tests/src/Unit/Plugin/Processor/RoleFilterTest.php
@@ -91,7 +91,7 @@ public function testFilterInclusive() {
     $configuration['default'] = 0;
     $this->processor->setConfiguration($configuration);
 
-    $this->processor->preprocessIndexItems($this->items);
+    $this->processor->alterIndexedItems($this->items);
 
     $this->assertTrue(!empty($this->items[Utility::createCombinedId('entity:user', '1:en')]), 'User with two roles was not removed.');
     $this->assertTrue(!empty($this->items[Utility::createCombinedId('entity:user', '2:en')]), 'User with only the authenticated role was not removed.');
@@ -106,7 +106,7 @@ public function testFilterExclusive() {
     $configuration['default'] = 1;
     $this->processor->setConfiguration($configuration);
 
-    $this->processor->preprocessIndexItems($this->items);
+    $this->processor->alterIndexedItems($this->items);
 
     $this->assertTrue(empty($this->items[Utility::createCombinedId('entity:user', '1:en')]), 'User with editor role was successfully removed.');
     $this->assertTrue(!empty($this->items[Utility::createCombinedId('entity:user', '2:en')]), 'User without the editor role was not removed.');
