---
title: 'Drupal 8: дефолтный поиск и типы содержимого'
url: 'https://graker.ru/news/2018/07/06/drupal-8-core-search-and-content-types'
language: ru
type: post
author: 'Роман Грачев'
published: '2018-07-06T14:14:00+03:00'
updated: '2018-07-06T14:24:01+03:00'
categories:
  - Программирование
  - Друпальчики
---

# Drupal 8: дефолтный поиск и типы содержимого

В Drupal 8 у дефолтного поиска отсутствует возможность исключить из индексации тот или иной тип содержимого. [Иссуй есть](https://www.drupal.org/project/drupal/issues/111744), а возможности — нет.

Можно сразу удариться в [Search API](https://www.drupal.org/project/search_api), но для небольших сайтов может быть проще добавить ограничение по типам. Это не так уж трудно. Есть [способ](https://www.metaltoad.com/blog/search-content-type-drupal-8-custom-module-tutorial), подразумевающий вставку условий через хук query\_alter по тегу `search_node_search`, добавляемому в поисковые запросы. Правда, тогда материалы не будут выводиться, а индексироваться — будут.

Но можно и запретить индексацию. Посколько D8 весь оопнутый и прогрессивный, отбросим теплые ламповые хуки и сделаем свой нанотехнологичный плагин поиска, унаследовав его от дефолтного `NodeSearch`.

Для этого создадим новый класс в нашем модуле в `mymodule/src/Plugin/Search/NodeRestrictedSearch` и наследуем его от уже существующего плагина. Это удобно, не нужно копировать ничего лишнего, достаточно добавить новое свойство, перечисляющее типы, которые мы ограничиваем (в данном примере это ноды типа `store` и `secret_content`):

```
<?php

namespace Drupal\mymodule\Plugin\Search;

use Drupal\Core\Access\AccessibleInterface;
use Drupal\node\Plugin\Search\NodeSearch;
use Drupal\search\Plugin\SearchIndexingInterface;

/**
 * @SearchPlugin(
 *   id = "node_restricted_search",
 *   title = @Translation("Content Restricted")
 * )
 */
class NodeRestrictedSearch extends NodeSearch implements AccessibleInterface, SearchIndexingInterface {

  protected $restrictedTypes = ['store', 'secret_content'];
```

И переопределить пару методов. Во-первых, метод, отбирающий ноды для индексации — мы скопируем код метода из родителя и добавим проверку типа материала:

```
  /**
   * {@inheritdoc}
   */
  public function updateIndex() {
    // Interpret the cron limit setting as the maximum number of nodes to index
    // per cron run.
    $limit = (int) $this->searchSettings->get('index.cron_limit');

    $query = $this->database->select('node', 'n', ['target' => 'replica']);
    $query->addField('n', 'nid');
    $query->leftJoin('search_dataset', 'sd', 'sd.sid = n.nid AND sd.type = :type', [':type' => $this->getPluginId()]);
    $query->addExpression('CASE MAX(sd.reindex) WHEN NULL THEN 0 ELSE 1 END', 'ex');
    $query->addExpression('MAX(sd.reindex)', 'ex2');
    $query->condition(
      $query->orConditionGroup()
        ->where('sd.sid IS NULL')
        ->condition('sd.reindex', 0, '<>')
    );
    // ПРОВЕРКА ТИПА:
    $query->condition('n.type', $this->restrictedTypes, 'NOT IN');
    $query->orderBy('ex', 'DESC')
      ->orderBy('ex2')
      ->orderBy('n.nid')
      ->groupBy('n.nid')
      ->range(0, $limit);

    $nids = $query->execute()->fetchCol();
    if (!$nids) {
      return;
    }

    $node_storage = $this->entityManager->getStorage('node');
    foreach ($node_storage->loadMultiple($nids) as $node) {
      $this->indexNode($node);
    }
  }
```

Во-вторых (для порядку), переопределим метод, который показывает в админке, сколько материалов проиндексировано и сколько осталось:

```
  /**
   * {@inheritdoc}
   */
  public function indexStatus() {
    $total = $this->database->select('node', 'n')
      ->fields('n', ['nid'])
      // ПРОВЕРКА ТИПА:
      ->condition('n.type', $this->restrictedTypes, 'NOT IN')
      ->countQuery()
      ->execute()
      ->fetchField();

    $query = $this->database->select('node', 'n');
    $query->distinct()
      ->fields('n', ['nid'])
      ->leftJoin('search_dataset', 'sd', 'sd.sid = n.nid AND sd.type = :type', [':type' => $this->getPluginId()]);
    // ПРОВЕРКА ТИПА:
    $query->condition('n.type', $this->restrictedTypes, 'NOT IN');
    $query->condition(
      $query->orConditionGroup()
        ->where('sd.sid IS NULL')
        ->condition('sd.reindex', 0, '<>')
    );
    $remaining = $query->countQuery()->execute()->fetchField();
    return ['remaining' => $remaining, 'total' => $total];
  }
```

Останется только почистить кэш, пройти в админку, добавить поисковую страницу с новым плагином и отключить старый.
