I want to alter contextual filter before executing the sql query of views. Is there any way to get current contextual filter in hook_views_query_alter or hook_views_pre_execute? Or which is the better hook to alter contextual filter for views?
3 Answers
The contextual filters are in $view->args.
$view->args is an array of arguments (contextual filters).
So you can do things like this:
/**
* Implements hook_views_pre_execute().
*/
function MODULENAME_views_pre_execute(&$view) {
// Set the first contextual filter value.
$view->args[0] = 1;
}
Using hook_views_pre_view() may be more reliable than hook_views_pre_execute(). Based on https://www.drupal.org/node/2438623, hook_views_pre_execute() is too late in the query build processs. In contrast, https://codedrop.com.au/blog/programatically-altering-contextual-filters-views-drupal-7 provides an example of hook_views_pre_view().
For my own situation, the below code works:
/**
* Implements hook_views_pre_view().
*/
function mymodule_views_pre_view(&$view, &$display_id, &$args) {
if ($view->name == 'VIEWNAME' && $view->current_display == 'DISPLAYNAME') {
$url = arg();
if (isset($url[1])) {
// YOU MIGHT HAVE TO ADJUST $url[1] TO MATCH YOUR URL ALIAS.
if ($normal_path = drupal_get_normal_path($url[1])) {
$path_args = explode('/', $normal_path);
}
}
if (isset($path_args[1])) {
$view->args[0] = $path_args[1];
}
}
}
-
1Note that the above code determines the contextual filter arguments from the URL because
hook_views_pre_view()
is too early to find them in$args
or$view->args
as usual. You can however fill$view->args
as demonstrated, and Drupal will not overwrite it later.– taniusJan 10, 2017 at 15:19 -
I don't know that using
hook_views_pre_view()
is a better choice - see the views API at api.drupal.org/api/views/views.api.php/function/… "Allows altering a view at the very beginning of processing a preview. This hook is only triggered when the one of the following are invoked:$view->execute_display()
$view->preview()
... Likely,hook_views_pre_build()
orhook_views_pre_execute()
are much better choices for most use cases since they are always invoked, not just when previewing a display."– kbrinnerJan 10, 2019 at 17:09
I think the best option is use hook_views_pre_execute
Below I share a code that alters the contextual filter by a field that comes from a node:
function hooks_views_pre_build(\Drupal\views\ViewExecutable $view) {
// Get the node entity by the URL parameter
$node = \Drupal::routeMatch()->getParameter('node');
if ($view->id() == 'ViewName' && $view->getDisplay()->display['id'] == 'DisplayName') {
$filterValue = $node->get('field')->first()->get('entity')->getTarget()->getValue();
$view->args[0] = $filterValue;
}
}
And that's it!