Score:1

Programmatically set exposed filter not possible when also using contextual filter

ru flag

I've got a view, that needs to set the default value for an exposed filter based on a user entity field. This basically works:

function MYMODULE_views_pre_build(\Drupal\views\ViewExecutable $view) {
  if ($view->current_display !== 'MY_VIEW_DISPLAY') {
    return;
  }
  $exposedFilterValues = $view->getExposedInput();
  if (!array_key_exists('MY_FIELD', $exposedFilterValues)) {
    $personalizedDefaultValue = $someUserEntity->getMyCustomDefaultFilterValue();
    $view->setExposedInput(array_merge($exposedFilterValues, ['MY_FIELD' => $personalizedDefaultValue] );
    $view->element['#cache']['tags'] = Cache::mergeTags($view->element['#cache']['tags'] ?? [], $someUserEntity->getCacheTags());
  }
}

BUT:

This views page also has a contextual filter filtering a completely different field. As soon as a contextual filter value is present in the URL, the code above is still executed, but it has no effect on the frontend. Without a contextual filter value, it works perfectly.

Why doesn't the code for the exposed field work when a completely different field's contextual value exists?

sonfd avatar
in flag
When you say this code executes, do you mean even the code inside this if statement: `if (!array_key_exists('MY_FIELD', $exposedFilterValues))`? I'm wondering if your exposed filter gets a value (empty string) when the contextual filter is present - maybe the contextual filter triggers some filter processing that wouldn't otherwise happen at this stage.
ru flag
Using xdebug breakpoints I've verified that `setExposedInput()` inside the `if(!array_key_exists)` is correctly executed in both cases.
Pushpinder Rana avatar
us flag
Make sure Views query is not getting changed after your custom code because views_query_alter() hook runs after views_pre_build().
sonfd avatar
in flag
Ok, so here's what I did to test this: I created a view with an exposed filter, "my_filter". I then created a `mymodule_views_pre_build()` with one line of code: `$view->setExposedInput(['my_filter' => 'test']);`. I load the view and can see that my exposed filter is set to "test". I then update my view with a Content ID contextual filter, with only the default configuration, and saved. I then load my view again and my exposed filter is still set to "test". I also test with a value for my contextual filter in the URL and see that the exposed filter is still set to "test".
sonfd avatar
in flag
Also, you'll want to add a cache context for your user since you're varying the results per user. As your caching is set now, it'll get cached for the first user, and then cleared when that user is updated, but otherwise won't vary per user.
ru flag
The code does work on a vanilla Drupal installation, there has to be a problem with a contrib module. Just don't know how to find it, there are _a lot_ of custom modules in this project :-(
Pushpinder Rana avatar
us flag
Have you tried checking any other Views hooks (such as views_query_alter()) in your custom module? Enable debugging and triage the code using debug_backtrace. You should identify what other module is overriding this change. You may triage it using Devel (Admin UI) events/hooks list that gives a list of all executed function for each request. Hope it helps.
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.