Views Query

Adding a new option in an exposed filter:

<?php

/**
 * Implements hook_form_FORM_ID_alter().
 */
function mymodule_form_views_exposed_form_alter(&$form, $form_state, $form_id) {
  $view_storage = $form_state->getStorage('view');
  $view = $view_storage['view'];

  if ($view->id() == 'user_admin_people' && $view->current_display === 'page_1') {
    // Add a new option.
    $form['role']['#options']["none"] = t('None');
  }
}

Altering the query for the new option:

<?php

/**
 * Implements hook_views_query_alter().
 */
function mymodule_views_query_alter(ViewExecutable $view, QueryPluginBase $query) {
  if ($view->id() == 'user_admin_people' && $view->current_display === 'page_1') {
    if ($view->exposed_raw_input['role'] == 'none') {

      // Change inner join to left join.
      $table = $query->getTableInfo('user__roles');
      if (isset($table['join']->type) && $table['join']->type === 'INNER') {
        $table['join']->type = 'LEFT';
      }

      // Replace the exposed filter's "none" condition with a custom one.
      foreach ($query->where as &$condition_group) {
        foreach ($condition_group['conditions'] as &$condition) {
          if ($condition['field'] === 'user__roles.roles_target_id = :user__roles_roles_target_id') {
            $condition = [
              'field' => 'user__roles.roles_target_id',
              'value' => NULL,
              'operator' => 'IS NULL'
            ];
          }
        }
      }
    }
  }
}

Resources