Drupal 8 + Search API: Exclude Content from Index Based on Field Value

Oksana Cyrwus
Software Solutions Architect
February 06, 2020

The Drupal 8 Search API UI allows us the freedom to configure numerous settings for our specific indexing requirements. We have a choice to index or omit specific content types, select indexed fields, apply various processors, etc. The Search API module is rather flexible and presents many options for manual configuration.

Happiness.

But what if we need to exclude an entity from index based on one of its field values?

The Search API UI does not provide controls for this level of granularity, so you’ll need to write a custom processor.

Search API Processors can function at many locations in the overall Search API process. In our case specifically, a processor should alter an array of items to be indexed by removing the specific item identified by its field value before the actual indexing takes place. To accomplish this, we’ll use one of the Search API ProcessorInterface methods - alterIndexedItems().

Processors are search backend agnostic. This means that no matter which search backend you use (Apache Solr, Elastic, database or other), a processor you write will apply to any backend.

Let’s take it step-by-step.

Scenario: Any node of type Staff Profile, for which the boolean field “field_inactive” is checked, should not be indexed.

Step 1 - Create the Processor

Create a custom module and write the Processor logic. Place the Processor file in the following location

custom_module/src/Plugin/search_api/processor/SearchApiExcludeItemsFromIndex.php

<?php

namespace Drupal\custom_search\Plugin\search_api\processor;

use Drupal\search_api\Plugin\PluginFormTrait;
use Drupal\search_api\Processor\ProcessorPluginBase;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Excludes entities marked as 'excluded' from being indexes.
 *
 * @SearchApiProcessor(
 *   id = "search_api_exclude_items_from_index",
 *   label = @Translation("Search API Exclude Items From Index - Custom Processor"),
 *   description = @Translation("Excludes inactive Staff Profiles from being indexed."),
 *   stages = {
 *     "alter_items" = -50
 *   }
 * )
 */
class SearchApiExcludeItemsFromIndex extends ProcessorPluginBase {

  use PluginFormTrait;

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    /** @var static $processor */
    $processor = parent::create($container, $configuration, $plugin_id, $plugin_definition);

    return $processor;
  }

  /**
   * {@inheritdoc}
   */
  public function alterIndexedItems(array &$items) {

    /** @var \Drupal\search_api\Item\ItemInterface $item */
    foreach ($items as $item_id => $item) {
      $object = $item->getOriginalObject()->getValue();
      $bundle = $object->bundle();

      // Remove Inactive Staff Profile from indexed items.
      // We need to be sure that the field actually exists
      // on the bundle before fetching the value to avoid
      // InvalidArgumentException exceptions.
      if ($bundle == 'staff_profile' && $object->hasField('field_inactive')) {
        $value = $object->get('field_inactive')->getValue();
        if ($value[0]['value']) {
          unset($items[$item_id]);
          continue;
        }
      }
    }
  }

}

Step 2 - Enable the Processor in the Search API UI

Clear Drupal cache and enable your processor. Remember to export updated configuration.

Enable Search API Processor for your Index.
Enable Search API Processor for your Index.

Step 3 - Test

… and enjoy!