How can I filter child terms in an exposed filter by parent term from contextual filter? I have a vocabulary of Districts with nested taxonomy terms like below.



I have a view of taxonomy terms in Drupal 8 which has an exposed filter of all terms with parent and child. What I want is that when I add a contextual filter of term parent the exposed filter should only show child terms matching the parent term in the contextual filter.

For example, if the URL contains Deoghar, then the exposed filter (like below filter) should only show the term Karon as option.
I've done this recently in a project of mine using MYMODULE_form_views_exposed_form_alter. The code assumes you've a view with the term ID on first position as contextual filter, e.g. domain.com/myview/123

&lt;?php
function MYMODULE_form_views_exposed_form_alter(&amp;$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
  $view = $form_state-&gt;getStorage('view');
  $display_id = $view['view']-&gt;current_display;

  if ($form_id == 'views_exposed_form' &amp;&amp; $view['view']-&gt;id() == 'MY_VIEW' &amp;&amp; $display_id == 'MY_VIEWDISPLAY') {
    if (!empty($view['view']-&gt;args) &amp;&amp; $view['view']-&gt;args[0]) {
      //get the term ID from the contextual filter
      $contextTermId = $view['view']-&gt;args[0];
      $entriesToRemove = [];

      $currentFilterValue = $form_state-&gt;getUserInput()['FIELD_FILTER_TAXONOMY'];
      foreach ($form['FIELD_FILTER_TAXONOMY']['#options'] as $idx =&gt; $entry) {
        if ($idx === 'All') {
          //remove the old root '- Any -' option
          $entriesToRemove[] = $idx;
        }
        //the next line is a bit shaky might need rework:
        //sometimes filter entries are a stdClass, 
        //but I've also seen entries as array in other exposed forms (grouped filters?)
        elseif ($entry instanceof stdClass &amp;&amp; is_array($entry-&gt;option)) {
          $termId = key($entry-&gt;option);
          $termName = current($entry-&gt;option);
          //the context filter term is our new root, so we change its label to '- Any -'
          if ($termId == $contextTermId) {
            $form['FIELD_FILTER_TAXONOMY']['#options'][$idx]-&gt;option = [$termId =&gt; t('- Any -')];
            if (empty($currentFilterValue) || $currentFilterValue == 'All') {
              //we've removed the default empty/All entry, reset it to our newly created, faked '- Any -' category
              $form_state-&gt;setUserInput(['FIELD_FILTER_TAXONOMY' =&gt; $contextTermId]);
            }
          }
          else {
            //this is the core part: for each filter option load the term
            //and check if it is a child of the contextual filter term
            $parents = \Drupal::entityTypeManager()
              -&gt;getStorage('taxonomy_term')
              -&gt;loadParents($termId);
            if (!in_array($contextTermId, array_keys($parents))) {
              $entriesToRemove[] = $idx;
            }
            else {
              //optional: we are in a sub-filter now,so we no longer need the leading '-' to indicate hierarchy
              $form['FIELD_FILTER_TAXONOMY']['#options'][$idx]-&gt;option = [$termId =&gt; trim(preg_replace('/^-/', '', $termName))];
            }
          }
        }
      }
      foreach ($entriesToRemove as $idx) {
        unset($form['FIELD_FILTER_TAXONOMY']['#options'][$idx]);
      }
      //optional: if there is only 1 entry left, hide the filter
      if (count($form['FIELD_FILTER_TAXONOMY']['#options']) == 1) {
        $form['FIELD_FILTER_TAXONOMY'] = [
          '#type' =&gt; 'hidden',
          'value' =&gt; $contextTermId
        ];
      }
    }
  }
}


A word of caution: Don't to this on huge taxonomies, my code loads every taxonomy term to decide if it needs to be removed.