Upgrade Your Drupal Skills

We trained 1,000+ Drupal Developers over the last decade.

See Advanced Courses NAH, I know Enough

How to limit the taxonomy terms in 'Exposed Drupal Views filters', to the tags that are used in included nodes, in multiple Views

Parent Feed: 

Last month we implemented the 'Resources' page on iias.asia, as you can see: you can filter the Resource nodes on this page in the right of the screen. This is a Drupal View with exposed filters, which are placed via a block via Twig Tweak module.

There is a 'Region' Filter and a 'Tags' taxonomy reference field, which are also used in other content types. 

We only wanted to show used terms in the drop downs.

So, there are other pages (Views) that also implemented this tag as a filter (like the Alumni page). But of course: those pages have other content types, so 'used tags' are also different.

So here is how we limited the used tags, per Drupal View, this article gave us a kickstart.

YOURMODULE.module:
/**
 * Implements hook_form_alter()
 *
 */
function YOURMODULE_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
  // Id's of the forms we want to alter.
  $form_ids = [
    'views-exposed-form-resources-page-1' => 'resource',
    'views-exposed-form-reviews-page-1' => 'review',
    'views-exposed-form-available-for-review-page-1' => 'review',

  ];
  // Targeted taxonomy term fields.
  $select_fields = ['tid_2', 'field_tags_target_id'];
  // Continue only if current form_id is one in defined array.
  if (array_key_exists($form['#id'], $form_ids)) {
    // Loop through targeted fields.
    foreach ($select_fields as $select_field) {
      // Get 'terms in use', switch query on which field is currently in the loop.
      // This only works if you have 1 or 2 targeted filters.
      $available_terms = ($select_field == 'tid_2')
                        ? _get_available_terms_region($form_ids[$form['#id']], $form['#id'])
                        : _get_available_terms_tags($form_ids[$form['#id']], $form['#id']);
      // Continue if $available_terms exists.
      if (isset($available_terms)) {
        // Unset the existing list.
        unset($form[$select_field]['#options']);
        // Build new list with 'terms in use'.
        $form[$select_field]['#options']['All'] = '- Any -';
        foreach ($available_terms as $available_term) {
          $tid = $available_term[0];
          $name = $available_term[1];
          $form[$select_field]['#options'][$tid] = $name;
        }
      }
    }
  }
}
/**
 * Custom function to query and build new filter list.
 *
 * @param $node_type
 * @param $exposed_block_id
 * @return array
 */
function _get_available_terms_region($node_type, $exposed_block_id) {
  // Table name of tags field.
  $node_tags_table = 'node__field_profile_region';
  // Query data.
  $query = \Drupal::database()->select($node_tags_table, 'nft');
  $query->distinct();
  $query->join('taxonomy_term_field_data', 'tname', 'tname.tid = nft.field_profile_region_target_id');
  $query->join('node', 'node', 'node.nid = nft.entity_id');
  $query->fields('nft', ['field_profile_region_target_id']);
  $query->fields('tname', ['name']);
  $query->orderBy('tname.name');
  // Dynamically query node type.
  $query->condition('node.type', $node_type);
  if($exposed_block_id == 'views-exposed-form-available-for-review-page-1') {
    $query->join('node__field_boolean_1', 'available', 'available.entity_id = nft.entity_id');
    $query->condition('available.field_boolean_1_value', 1);
  }
  $result = $query->execute();
  // Build term list.
  $term_list = [];
  while ($row = $result->fetchAssoc()) {
    array_push($term_list, [$row['field_profile_region_target_id'], $row['name']]);
  }
  // Return term list.
  return $term_list;
}

/**
 * Custom function to query and build new filter list.
 *
 * @param $node_type
 * @param $exposed_block_id
 * @return array
 */
function _get_available_terms_tags($node_type, $exposed_block_id) {
  // Table name of tags field
  $node_tags_table = 'node__field_tags';
  // Query data.
  $query = \Drupal::database()->select($node_tags_table, 'nft');
  $query->distinct();
  $query->join('taxonomy_term_field_data', 'tname', 'tname.tid = nft.field_tags_target_id');
  $query->join('node', 'node', 'node.nid = nft.entity_id');
  $query->fields('nft', ['field_tags_target_id']);
  $query->fields('tname', ['name']);
  $query->orderBy('tname.name');
  // Dynamically query node type.
  $query->condition('node.type', $node_type);
  if($exposed_block_id == 'views-exposed-form-available-for-review-page-1') {
    $query->join('node__field_boolean_1', 'available', 'available.entity_id = nft.entity_id');
    $query->condition('available.field_boolean_1_value', 1);
  }
  $result = $query->execute();
  // Build term list.
  $term_list = [];
  while ($row = $result->fetchAssoc()) {
    array_push($term_list, [$row['field_tags_target_id'], $row['name']]);
  }
  // Return list.
  return $term_list;
}

Custom functions in the block above, we put these in the same .module file, but maybe it's better to place it in a Drupal service for example. Of course you can always refactor this into one function -more dynamic. But I'll leave that up to you :)

I hope this gives you a head start, please let me know if you have any questions or improvements.

Drupal code Planet Drupal
Written by Joris Snoek | Jun 07, 2021

Join the conversation

Author: 
Original Post: 

About Drupal Sun

Drupal Sun is an Evolving Web project. It allows you to:

  • Do full-text search on all the articles in Drupal Planet (thanks to Apache Solr)
  • Facet based on tags, author, or feed
  • Flip through articles quickly (with j/k or arrow keys) to find what you're interested in
  • View the entire article text inline, or in the context of the site where it was created

See the blog post at Evolving Web

Evolving Web