Drupal 8 - Combine two facets

kenneth

Authored on

Image
munchen

Once upon a time I was asked to use `Facets` module to expose new facets based on content types. I made them and it worked properly but a requeriment was to combine two specific ones into a single facet, let's say `article` and `page` content types need to be together. In order to solve it I decided to create a new facet processor plugin.

Then I create a new custom module named `keboca_search` where I included a new plugin into `src` folder at the following path: `Plugin/facets/processor/MergeArticlePage.php`

namespace Drupal\keboca_search\Plugin\facets\processor;


use Drupal\facets\Annotation\FacetsProcessor;
use Drupal\facets\FacetInterface;
use Drupal\facets\Processor\BuildProcessorInterface;
use Drupal\facets\Processor\ProcessorPluginBase;

/**
 * Class MergeArticlePage which's merging two hard-coded content types.
 *
 * @package Drupal\keboca_search\Plugin\facets\processor
 *
 * @FacetsProcessor(
 *   id = "keboca_search_merge_article_page",
 *   label = @Translation("Merge Articles and Pages together."),
 *   description = @Translation("An integration to force put together Articles
 *   and Pages into a single facet."),
 *   stages = {
 *     "build" = 60
 *   }
 * )
 */
class MergeArticlePage extends ProcessorPluginBase implements BuildProcessorInterface {

  /**
   * {@inheritdoc}
   */
  public function build(FacetInterface $facet, array $results) {
    /** @var \Drupal\facets\Result\Result[] $facets */
    $facets = array_reduce($results, function ($carry, $item) {
      /** @var \Drupal\facets\Result\Result $item */
      $carry[$item->getRawValue()] = $item;
      return $carry;
    }, []);

    /** @var \Drupal\facets\Result\Result $article */
    $article = $facets['article'] ?? NULL;
    /** @var \Drupal\facets\Result\Result $page */
    $page = $facets['page'] ?? NULL;

    // Parse `page` facet instance.
    if (!is_null($page)) {
      /** @var \Drupal\Core\Url $url */
      $url = $page->getUrl();
      /** @var array $query */
      $query = $url->getOption('query');

      // Init flag variables.
      $updated = FALSE;
      $filter = 'content_type:article';

      // Look-up for query string.
      if (!in_array($filter, $query['sitewide'])) {
        // Inject filter to current query.
        $updated = TRUE;
        $query['sitewide'][] = $filter;
      }
      // Verify when current facet is active.
      elseif ($page->isActive()) {
        // Remove duplication filter values.
        $updated = TRUE;
        $query['sitewide'] = array_filter($query['sitewide'], function ($param) use ($filter) {
          return $param != $filter;
        });

        // Remove whole query string when there are not filters.
        if (empty($query['sitewide'])) {
          unset($query['sitewide']);
        }
      }

      // Overwrite URL options then define it back to facet.
      if ($updated) {
        $url->setOption('query', $query);
        $page->setUrl($url);
      }

      // Update facet count value when article facet was found.
      if (!is_null($article)) {
        $page->setCount($page->getCount() + $article->getCount());

        // Remove `article` facet instance.
        unset($facets['article']);
      }
    }

    return array_values($facets);
  }
}

Finally I jumped into my content type facet edit form (`/admin/config/search/facets/content_type/edit`) where I enabled the new processor into "Facet settings" section:

merge_article_page_procesor

I've also review "Advanced Settings" section to be sure the build stage section was defining the new processor at the very end. 

That said, I hope it helps you at some point somehow!

Happy coding!