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

17 Dec.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) {
        // Review it because oldest version of the Metatag module used field_meta_tags instead of field_metatag.
        if ($object->hasField('field_metatag')
          && !$object->get('field_metatag')->isEmpty()) {
          $metaTags = $object->get('field_metatag')->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]);
      }
    }
  }
 
}