Drupal 9 & 10: Remove the nodes marked as "noindex" from search API results

12 May.2022
Image
Search

In a project where we use the Search API to search for content, we noticed that nodes that are marked as "noindex" by the Metatag module are visible during internal searches.
Here is a ready-made solution for how to avoid this.

 

File
\modules\custom\MY_CUSTOM_MODULE\src\Plugin\search_api\processor\NodeExclude.php
<?php
 
namespace Drupal\MY_CUSTOM_MODULE\Plugin\search_api\processor;
 
use Drupal\node\NodeInterface;
use Drupal\search_api\IndexInterface;
use Drupal\search_api\Processor\ProcessorPluginBase;
 
/**
 * Class NodeExclude.
 *
 * @package Drupal\MY_CUSTOM_MODULE\Plugin\search_api\processor
 *
 * @SearchApiProcessor(
 *   id = "MY_CUSTOM_MODULE_node_exclude",
 *   label = @Translation("Node exclude"),
 *   description = @Translation("Exclude specific nodes. For example remove the
 *   nodes marked as noindex by metatag."), stages = {
 *     "alter_items" = 0
 *   }
 * )
 */
class NodeExclude extends ProcessorPluginBase {
 
  /**
   * {@inheritdoc}
   */
  public static function supportsIndex(IndexInterface $index) {
    foreach ($index->getDatasources() as $datasource) {
      if ($datasource->getEntityTypeId() === 'node') {
        return TRUE;
      }
    }
 
    return FALSE;
  }
 
  /**
   * {@inheritdoc}
   */
  public function alterIndexedItems(array &$items) {
    /** @var \Drupal\search_api\Item\ItemInterface $item */
    foreach ($items as $item_id => $item) {
      $object = $item->getOriginalObject()->getValue();
      $exclude = FALSE;
      if ($object instanceof NodeInterface) {
        if ($object->hasField('field_meta_tags')
          && !$object->get('field_meta_tags')->isEmpty()) {
          $metaTags = $object->get('field_meta_tags')->getString();
          $metaTags = unserialize($metaTags);
          if (isset($metaTags['robots'])) {
            $robots = explode(', ', $metaTags['robots']);
            if (in_array('noindex', $robots)) {
              $exclude = TRUE;
            }
          }
        }
      }
 
      if ($exclude) {
        unset($items[$item_id]);
      }
    }
  }
 
}