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.


  • 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


Although a very late answer but maybe it helps somebody. Here's a great write up with the solution to above use case: How to combine two facets

| improve this answer | |
  • You should always include the answer and put the link only as a reference, now the link is broken and we don't know what that solution was – wranvaud Oct 9 at 20:58
  • Uops ..you are right. I'm sorry. The following link within drupal.stackexchange shows a solution to a very similar use case. Hope this may help. drupal.stackexchange.com/questions/159596/… – jbiechele Oct 10 at 22:21

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';
| improve this answer | |

The link in the accepted answer is no longer working, so I don't know how it accomplished the task. But for anyone else trying to solve this issue, I used hook_facetapi_realm_info() to create a realm, hook_facetapi_widgets() to alter the html output from the link, hook_facetapi_url_processors() to define an url processor based on facetapi pretty paths. The whole module can be found here: https://github.com/Coyote6/drupal-7-combined-facet-block

| improve this answer | |

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'])) {

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

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

        // Remove `article` facet instance.

    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.

| improve this answer | |

I proposed a generic solution to be part of the feature module per se: https://www.drupal.org/project/facets/issues/3133309

Basically it exposes a new processor MergeNodeTypes to allow dynamic facets groups based on available content types.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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