19

I want to add/modify a filter criteria programmatically.

For example, for a view, I added an "Email Address" filter whose value is needed to change dynamically, it is needed to set to the current logged in user's email id.

How to achieve that? Please see attached image for more details. Please help.

enter image description here

7 Answers 7

27

Use the Devel module and dpm($view) and dpm($query) after you put like "[email protected]" into the "value" field found in your pic. See the object/array structure of the view and query from the devel output.

Then use the function hook_views_query_alter(&$view, &$query) in your module to target the WHERE condition filter condition and set it to the value you want.

Something like:

function MYMODULE_views_query_alter(&$view, &$query) {
  global $user;
  dpm($view, __FUNCTION__);
  dpm($query, __FUNCTION__);
  if ($view->name === 'your_view_machine_name') {
    // This will only work as-is if you always have something in the filter by
    // default, I guess. This hook runs always so you could just put
    // '[email protected]' as the email to filter by in views and this
    // will always override it. I'm sure there is a cleaner way to put
    // the filter dynamically at runtime. But i think thats more complex
    // php that customizes a view.
    //
    // The index 2 below is the index of the condition for the email filter.
    // Your $query structure may be different in your dpm() of the View $query.
    $query->where[1]['conditions'][2]['field']['value'] = $user->email;
  }
}
4
  • 1
    Many thanks! Can you please tell me where do I first, write dpm($view);?
    – Shafiul
    Commented Mar 25, 2012 at 17:30
  • 1
    you make a custom module and place the above function it in. the hook will fire if views are enabled and you will see the $view and $query at the top of the page once you've enabled the custom module and the Devel module. Then just change my code to have your view's machine name it in ... and making the $query values work with your exact query ...
    – tenken
    Commented Mar 25, 2012 at 17:39
  • 1
    That's a great answer. In Drupal 7 you actually do: $query->where[1]['conditions'][2]['value'] = $user->email Commented Apr 12, 2016 at 8:12
  • 1
    Personally I think the answer using the hooks below is much better drupal.stackexchange.com/a/200870/9634
    – kbrinner
    Commented Jan 10, 2019 at 19:01
7

Here's an alternative:

$view = views_get_view('view_machine_name');
$view->init_display('default');
$view->display_handler->display->display_options['filters']['your_filter_name']['default_value'] = 'your_value';
$view->is_cacheable = FALSE;  
$view->execute();
print $view->render();

I know you should probably set this using some esoteric, convoluted method, but if you just want quick and dirty access without messing around this will get you there.

7

It would be preferable to alter these in hooks rather than at render time so that you are not undermining site performance and caching. Took me age to figure out that hook_views_pre_build() fires too late, you need hook_views_pre_view().

I found reference to using $view->add_item() but struggled for examples, below was my solution for filtering a set of taxonomy terms to only include certain vocabs:

function MODULENAME_views_pre_view(&$view, &$display_id, &$args) {

  if ($view->name == 'VIEWNAME' && $display_id == 'DISPLAYID') {
    // Add all the terms of a vocabulary to the terms listing widget select field
    $vids = array();
    $vocab = taxonomy_vocabulary_machine_name_load('vocab_name');
    $vids[ $vocab->vid ] = $vocab->vid;

    // Get the existing filters
    $filters = $view->display_handler->get_option('filters');

    if (empty($filters['vid'])) {
      // There is no vid filter so we have to add it
      $view->add_item(
        $view->current_display,
        'filter',
        'taxonomy_term_data',
        'vid',
        array(
          'operator' => 'in',
          'value' => $vids,
          'group' => 1
        )
      );
    }
    else {
      // Add to pre-existing filter
      foreach($vids as $vid) {
        $filters['vid']['value'][ $vid ] = $vid;
      }
      $view->display_handler->override_option('filters', $filters);
    }
  }
}

Edit note: This comment on d.o group helped me figure out how to get the views filters using $view->display_handler->get_option('filters') and to then override them using $view->display_handler->override_option('filters', $filters);.

4

I've had a similar issue but where trying to pass in multiple arguments to a filter. I have used the "views_get_view" method, but passing in arguments to the view. I hope it helps someone. You can substitute any argument type or value for your needs:

I have added contextual filters to the view itself (from the advance view settings fieldset). The first one is a "content: has taxonomy term ID". The 2nd one is "content: nid" with "allow multiple" checked and "exclude" checkbox checked (from the 'more' fieldset in the contextual filter pop-up).

args[] = '1'; // Term ID
args[] = '1+2+3'; // Node IDs to exclude/include

$view = views_get_view($view_name);
$view->init();
$view->set_display($display);
$view->set_arguments($args);
$view->execute();
$view->result

Update: I forgot to mention, within the contextual filter values, you may need to select php code and return the view arguments passed in. Eg:

return $view->args[1];
3

In Drupal 8 you can use ViewExecutable::setHandler($display_id, $type, $id, $item) to set a filter programmatically.

1
  • 7
    This answer could be a bit more verbose about why this works. Often I like to link and quote the documentation pages. This would help the asker learn more about the Drupal API and help find information for themselves in the future.
    – mradcliffe
    Commented Sep 2, 2016 at 10:01
1

Here's an example on how filter criteria can be added programmatically in Drupal 8:

/**
 * @param ViewExecutable $view
 * @param QueryPluginBase $query
 *
 * Sets a custom custom filter criteria (takes current language into account)
 */
function MODULE_views_query_alter(ViewExecutable $view, QueryPluginBase $query) {
  if ($view->storage->id() === 'my_view_id') {
    $query->addWhere(0, 'node__field_custom_criteria.field_custom_criteria_value', \Drupal::languageManager()->getCurrentLanguage()->getId(), '=');
  }
}

The above query will add a criteria that filters nodes where the field_custom_criteria field equals the currently selected language.

More info can be found in the docs: hook_views_query_alter

1

Based on @Duncanmoo's answer above that I felt was best, I added the following filters to my view - thought these would be useful examples in case you weren't trying to filter based on a referenced taxonomy but instead on a referenced entity or a NID:

function [MYMODULE]_views_pre_view(&$view, &$display_id, &$args) {
  if (($view->name == '[your view name]') && ($display_id == '[your display id]')) {
    // Get referenced service - example for entity reference.
    $node = menu_get_object();
    $node_wrapper = entity_metadata_wrapper('node', $node->nid);
    $referenced_service = $node_wrapper->field_service_ref->value();
    // Add service id as a filter to view.
    $filters = $view->display_handler->get_option('filters');
    if (empty($filters['field_service_ref_target_id'])) {
      // Only display operations nodes that reference the same service.
      $view->add_item(
        $display_id,
        'filter',
        'field_data_field_service_ref',
        'field_service_ref_target_id',
        array(
          'operator' => '=',
          'value' => ['value' => $referenced_service->id],
          'group' => 1
        )
      );
    }
    // Add nid as a filter to view - example for NID filter
    if (empty($filters['nid'])) {
      // Don't include current operation in list of related operations.
      $view->add_item(
        $display_id,
        'filter',
        'node',
        'nid',
        array(
          'operator' => '!=',
          'value' => ['value' => $node->nid],
          'group' => 1
        )
      );
    }
  }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.