Removing invalid query string parameters passed to a view
As a Drupal site administrator, you may notice in the website logs that there might be a large number of repeated log messages along the lines of "An illegal choice has been detected. Please contact the site administrator." We recently had this problem on a Drupal site that was upgraded from Drupal 7 to Drupal 9 which featured a product search that was built using Views.
Due to slight differences in the way in which the view and facets were built in the Drupal 9 site, this resulted in slightly different URLs being used when the user would filter the search results. For a standard site user who would be interacting with the form elements to filter the view, this was not a problem. However, search engines that had indexed these older URLs from the Drupal 7 site were still trying to crawl the search page regularly, with (what are now) invalid query string parameters.
At the times when the search engines were crawling these pages, this would result in hundreds if not thousands of log messages being logged. Although not anything that would directly impact the users of the site, it’s not ideal to have so many log messages polluting the site logs. Having so many log messages makes it harder to track down and find actual more pressing issues that may need to be addressed.
It makes sense to try and eliminate the cause of this issue and stop so many error messages from being logged. This can be easily accomplished by the following snippet of code which uses hook_views_pre_build().
use Drupal\views\ViewExecutable;/** * Implements hook_views_pre_build(). */function my_module_views_pre_build(ViewExecutable $view) { if ($view->id() === 'my_view_name') { /** @var \Symfony\Component\HttpFoundation\Request $request */ $request = $view->getRequest(); /** @var \Drupal\Core\Http\InputBag $query */ $query = $request->query; if ($sort_by = $query->get('sort_by')) { // Compare to the list of allowed values to see if it's valid. // If it's not, then remove the sort_by from the query completely. $view_sorts = $view->sort; if (!isset($view_sorts[$sort_by])) { $query->remove('sort_by'); } } }}
Let's quickly break down the code example above. For a custom module named my_module, we are implementing the hook_views_pre_build hook inside of the my_module.module file. We then check the view ID of our view to see if it’s the one we are trying to target and then get the HTTP request object from the view, checking the query string values of the request.
The query string value we are interested in (which was causing the error messages) is named sort_by. We get the list of allowed sort values from the view and then compare this to the value in the query string. If the value trying to be used isn’t a valid value for our view, we then unset this from the query.
Of course, if you were looking to target a particular display of the view and not all of them then you’d need to add some additional logic to check the current_display of the view. For example, change the line:
if ($view->id() === 'my_view_name') {
to if ($view->id() === 'my_view_name' && $view->current_display === 'page_1') {
which will restrict the code block to only run for the page_1 display.