diff --git a/src/Plugin/facets/processor/MergeNodeTypes.php b/src/Plugin/facets/processor/MergeNodeTypes.php
new file mode 100644
index 0000000..1a16a09
--- /dev/null
+++ b/src/Plugin/facets/processor/MergeNodeTypes.php
@@ -0,0 +1,357 @@
+entityTypeManager = $entity_type_manager;
+    $this->urlProcessorManager = $url_processor_manager;
+  }
+
+  /**
+   * Creates an instance of the plugin.
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    return new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      $container->get('entity_type.manager'),
+      $container->get('plugin.manager.facets.url_processor')
+    );
+  }
+
+  /**
+   * Extract all available node types, then map them as valid options.
+   *
+   * @return array
+   *
+   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
+   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
+   */
+  protected function getNodeTypes(): array {
+    /** @var array $nodeTypes */
+    $nodeTypes = array_map(function ($nodeType) {
+      /** @var \Drupal\node\Entity\NodeType $nodeType */
+      return $nodeType->label();
+    }, $this->entityTypeManager->getStorage('node_type')->loadMultiple());
+
+    return $nodeTypes;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildConfigurationForm(array $form, FormStateInterface $form_state, FacetInterface $facet) {
+    /** @var array $config */
+    $config = $this->getConfiguration()['facet_groups'];
+
+    // Gather the number of groups present in the form.
+    $groups = $form_state->get('groups');
+
+    // Ensure that there is at least one group.
+    if (is_null($groups)) {
+      $groups = count($config);
+      $form_state->set('groups', $groups);
+    }
+
+    // Prepare form widget.
+    $build['#tree'] = TRUE;
+    $build['container_open']['#markup'] = '
';
+
+    // Iterate over available groups.
+    for ($i = 0; $i < $groups; $i++) {
+
+      // Build details wrapper for each group.
+      $build['facet_groups'][$i] = [
+        '#type' => 'details',
+        '#title' => $this->t('Facet group'),
+        '#open' => FALSE,
+      ];
+
+      // Include field to overwrite facet name.
+      $build['facet_groups'][$i]['facet_name'] = [
+        '#type' => 'textfield',
+        '#title' => $this->t('New Facet name'),
+        '#default_value' => $config[$i]['facet_name'] ?? NULL,
+      ];
+
+      // Expose all available content types.
+      $build['facet_groups'][$i]['content_types'] = [
+        '#type' => 'checkboxes',
+        '#title' => $this->t('Content types to be grouped.'),
+        '#options' => $this->getNodeTypes(),
+        '#default_value' => $config[$i]['content_types'] ?? [],
+      ];
+    }
+
+    // Close container element.
+    $build['container_close']['#markup'] = '
';
+
+    // Setup $.ajax buttons.
+    $build['actions'] = [
+      '#type' => 'actions',
+    ];
+    $build['actions']['add_group'] = [
+      '#type' => 'submit',
+      '#value' => $this->t('Add another group'),
+      '#submit' => [
+        [$this, 'addOne'],
+      ],
+      '#ajax' => [
+        'callback' => [$this, 'addMoreCallback'],
+        'wrapper' => 'facet-group-fieldset-wrapper',
+      ],
+    ];
+
+    // If there is more than one group, add the remove button.
+    if ($groups > 1) {
+      $build['actions']['remove_group'] = [
+        '#type' => 'submit',
+        '#value' => $this->t('Remove last group'),
+        '#submit' => [
+          [$this, 'removeOne'],
+        ],
+        '#ajax' => [
+          'callback' => [$this, 'addMoreCallback'],
+          'wrapper' => 'facet-group-fieldset-wrapper',
+        ],
+      ];
+    }
+
+    return $build;
+  }
+
+  /**
+   * Submit handler for the "Add another group" button.
+   *
+   * Increments the max counter and causes a rebuild.
+   *
+   * @param array $form
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   */
+  public function addOne(array &$form, FormStateInterface $form_state) {
+    $groups = $form_state->get('groups');
+    $add_button = $groups + 1;
+    $form_state->set('groups', $add_button);
+
+    // Since our buildForm() method relies on the value of 'num_names' to
+    // generate 'name' form elements, we have to tell the form to rebuild. If we
+    // don't do this, the form builder will not call buildForm().
+    $form_state->setRebuild();
+  }
+
+  /**
+   * Submit handler for the "Remove last group" button.
+   *
+   * Decrements the max counter and causes a form rebuild.
+   *
+   * @param array $form
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   */
+  public function removeOne(array &$form, FormStateInterface $form_state) {
+    $groups = $form_state->get('groups');
+    if ($groups > 1) {
+      $remove_button = $groups - 1;
+      $form_state->set('groups', $remove_button);
+    }
+
+    // Since our buildForm() method relies on the value of 'num_names' to
+    // generate 'name' form elements, we have to tell the form to rebuild. If we
+    // don't do this, the form builder will not call buildForm().
+    $form_state->setRebuild();
+  }
+
+  /**
+   * Callback for both ajax-enabled buttons.
+   *
+   * Selects and returns the fieldset with the names in it.
+   *
+   * @param array $form
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *
+   * @return array
+   */
+  public function addMoreCallback(array &$form, FormStateInterface $form_state) {
+    /** @var array $facet_groups */
+    $facet_groups = NestedArray::getValue($form, [
+      'facet_settings',
+      'facets_merge_node_types',
+      'settings',
+      'facet_groups',
+    ]);
+
+    // Recreate container wrapper.
+    $facet_groups['#prefix'] = '';
+    $facet_groups['#suffix'] = '
';
+
+    return $facet_groups;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submitConfigurationForm(array $form, FormStateInterface $form_state, FacetInterface $facet) {
+    $form_state->unsetValue('actions');
+    parent::submitConfigurationForm($form, $form_state, $facet);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function defaultConfiguration() {
+    return [
+      'facet_groups' => [
+        [
+          'facet_name' => '',
+          'content_types' => [],
+        ],
+      ],
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function build(FacetInterface $facet, array $results) {
+    /** @var array $facet_groups */
+    $facet_groups = $this->getConfiguration()['facet_groups'];
+
+    /** @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;
+    }, []);
+
+    $url_processor = $this->urlProcessorManager->createInstance($facet->getFacetSourceConfig()
+      ->getUrlProcessorName(), ['facet' => $facet]);
+    $filter_key = $url_processor->getFilterKey();
+    $field_name = $facet->getUrlAlias();
+
+    array_walk($facet_groups, function ($config) use ($results, &$facets, $filter_key, $field_name) {
+      /** @var array $types */
+      $types = array_filter($config['content_types']);
+      if (empty($types)) {
+        return;
+      }
+
+      /** @var array $filtered */
+      $filtered = array_filter($types, function ($type) use ($facets) {
+        return array_key_exists($type, $facets);
+      });
+      if (empty($filtered)) {
+        return;
+      }
+
+      /** @var string $key */
+      $key = array_shift($filtered);
+      /** @var \Drupal\facets\Result\Result $first */
+      $first = &$facets[$key];
+
+      // Overwrite label if new facet name was defined.
+      if (!empty($config['facet_name'])) {
+        $facet_name = $this->t($config['facet_name']);
+        $first->setDisplayValue($facet_name);
+      }
+
+      // Init flag variables.
+      $updated = FALSE;
+
+      /** @var \Drupal\Core\Url $url */
+      $url = $first->getUrl();
+      /** @var array $query */
+      $query = $url->getOption('query');
+
+      // Walk through all remaining filtered types.
+      foreach ($filtered as $item) {
+        // Setup dynamic filter.
+        $filter = "{$field_name}:{$item}";
+
+        // Look-up for query string.
+        if (empty($query[$filter_key]) || !in_array($filter, $query[$filter_key])) {
+          // Inject filter to current query.
+          $updated = TRUE;
+          $query[$filter_key][] = $filter;
+        }
+        // Verify that current facet is active.
+        elseif ($first->isActive()) {
+          // Remove duplication filter values.
+          $updated = TRUE;
+          $query[$filter_key] = array_filter($query[$filter_key], function ($param) use ($filter) {
+            return $param != $filter;
+          });
+
+          // Remove whole query string when there are not filters.
+          if (empty($query[$filter_key])) {
+            unset($query[$filter_key]);
+          }
+        }
+
+        // Overwrite URL options then define it back to facet.
+        if ($updated) {
+          $url->setOption('query', $query);
+          $first->setUrl($url);
+        }
+
+        // Update facet count value when lab facet was found.
+        $first->setCount($first->getCount() + $facets[$item]->getCount());
+
+        // Remove facet instance.
+        unset($facets[$item]);
+      }
+    });
+
+    return array_values($facets);
+  }
+
+}