2

I have a search page with a faceted filter on 'Content Type' field.

I basically need to merge some of the content types into one single facet.

Example:

  • Content Type A
  • Content Type B
  • Content Type C

Should be turned into:

  • Content Type AB
  • Content Type C

How can I achieve this?

My Drupal setup for this scenario is the following:

Search API + Search API Solr + Facetapi + Views

1
  • I proposed a generic solution to be part of the feature module per se: drupal.org/project/facets/issues/3133309 Basically it exposes a new processor MergeNodeTypes to allow dynamic facets groups based on available content types.
    – keboca
    May 4, 2020 at 3:40

3 Answers 3

1

I wrote this articule: "Drupal 8 - Combine two facets" https://www.keboca.com/drupal-8-combine-two-facets

Where I am exposing a new processor plugin then I am able to merge both.

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);
  }
}

PD: I'm not pretty sure how this thing about posting solution or stuff works. I got my last previous commnented deleted. So I am just sharing it again. If it works fine, otherwise I am not sure how it supposes to do. From what I can see the first comment is an URL which's pointing to a resource what does not event exits, tho. Any feedback is more than welcome BTW.

2
  • Meanwhile @keboca has provided a patch for facets, so that you don't have to implement this solution by yourself: drupal.org/project/facets/issues/3133309. Mar 16, 2022 at 8:23
  • The module "Facets form" implements the links and query in different ways. This causes a warning in if (!in_array($filter, $query['sitewide'])) { ("$query['sitewide']" is null).
    – dxvargas
    Nov 30, 2022 at 12:19
0

I fact all you need is

hook_facet_items_alter(&$build, &$settings);

There you can change the queries and hide/show other facets like

      $build['A']['#markup'] = 'NewA';
      $build['A']['#count']  = $build['A']['#count'] + $build['B']['#count'];
      $size = count($build);
      $build['A']['#query']['f'][$size] = 'field_filter:B';
0

I ended up using a field for the nodes, "Content type filter", hidden from display and edition. Content of type A and B will have default value AB, content C has default value C. Then I can use this field in the facet. It is a very basic approach but also very easy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.