Mr Treublaan 1-3
1097 DP Amsterdam
The Netherlands

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

Programmatically in multiple Views
07 Jun, 2021 Drupal

Home Blog How to limit the taxonomy...

drupal views exposed filter filtered

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
Let's Talk

Please tell me all about your project!
Mail , or send a message:

Got some more time?

Related content
09 May, 2023 Drupal

Save time, frustration, and potential content loss.


02 Jun, 2021 Drupal


25 May, 2021 Drupal

With new features like: @-mentions, drag-and-drop images & general settings.