Problem/Motivation
View exposed filters and contextual filters cannot be used together. The contextual filter is ignored when the exposed filters are used.
Steps to reproduce
Create a View with both exposed filters and contextual filters. Try to use the exposed filters.
Proposed resolution
Pass the existing contextual filter arguments to the View when exposed filters are used.
Remaining tasks
Finalize implementation.
User interface changes
None except that the filters will work as expected.
API changes
None.
Data model changes
None.
Release notes snippet
| Comment | File | Size | Author |
|---|
Issue fork drupal-2821962
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
screon commentedComment #3
sukanya.ramakrishnan commentedI am facing a similar issue. What i am seeing is that, in your example. the 'webinar' value is changing to 'all' so the contextual filter doesnt get applied.
Debugged a bit further and it seems that the request attributes are lost. (The arguments are got from the '_raw_variables' attribute from the request) Not sure why that is happening. Bumping the issue to major so someone can take a look.
Thanks
Sukanya
Comment #4
sukanya.ramakrishnan commentedComment #5
nedjoThis issue describes two bugs that are related but slightly different.
Both likely originate in
ViewExecutable::getUrl(), which is called byViewsExposedForm::buildForm()to set the#actionkey, which determines the path that the exposed form submits to.In that method, the URL info is returned if there isn't a path or if no arguments are fed in. See the following lines:
Otherwise, for every argument that isn't fed in, a default parameter is set. See the following lines:
So what appears to happen on a page that has both contextual filters and exposed filters is and a path that includes an argument, such as
node/%node/example:/all). So, when the form is submitted (even if no change is made), fallback behaviours are not triggered, leading to different (unexpected) results.For example, if a contextual filter is set to default to the value of the current user's ID, results will be filtered to the current user for the first page load, but after the filter form is submitted the results will be for all users.
Comment #6
joegl commentedI am also having the same issue. I have a view with a path of:
store/category/%/%
With exposed filters for sorting options in a block. When I have "all" as an exception in the contextual filter, the exposed filters submits to:
store/category/all?sort_by=...
With "all" removed from the exceptions, the exposed filters form submits to:
store/category/%2A/%2A
It doesn't matter what arguments I have, it always redirects to "all" or %2A.
Comment #7
mroycroft commentedThis still happens in the latest dev version of Drupal 8.
Here is a patch with a test that demonstrates the issue. A follow-up patch with the proposed fix included will be posted shortly.
Comment #8
mroycroft commentedHere's a patch with the proposed fix.
Comment #9
mroycroft commentedComment #10
damontgomery commentedWhen we added this patch, we got critical errors when the argument values were null. I tried to update this along these lines,
If you try to call $view->getUrl with an empty array, you don't get the url back, so there is a check for that as well.
Unfortunately, this doesn't seem to address our issue and I'll have to keep digging. By the time we load this form, our URL parameter has been lost from the view argument.
Comment #11
damontgomery commentedIt doesn't address this issue, but we are going with the following approach.
Use the exposed form in the view (not as a block)
Add facet blocks to the view header (Rendered Content - Block)
Wrap the two together in the view template. There is a `header` and an `exposed` variable to work with
We originally wanted to split the exposed filter into a block for flexibility in theming, but moving everything into the view seems viable as well and doesn't have the issue mentioned above. I'm not sure that this is the same issue as what others were mentioning, but there aren't many tickets I could find and maybe this will help someone else who has a similar issue.
Comment #13
geek-merlin@damontgomery #16;:
> When we added this patch, we got critical errors when the argument values were null.
Thanks for the report! Alas, without a backtrace and further info we can only guess if this is a problem of this patch or of your site. This info is important.
Comment #14
Wisamx commentedI didn't know this problem is 2 years old!
I have asked a question related to this problem trying to solve it by altering exposed form or hook into views pre render, But I failed.
https://drupal.stackexchange.com/questions/264262/setting-exposed-filter...
Hope there is a solution.
Comment #15
geek-merlinThe patch in #8 looks good to me but after trying in can confirm there are issues with it :-(.
Here's the backtrace in our case:
The website encountered an unexpected error. Please try again later.Symfony\Component\Routing\Exception\InvalidParameterException: Parameter "arg_0" for route "view.h4c_map.map" must match "[^/]++" ("" given) to generate a corresponding URL. in Drupal\Core\Routing\UrlGenerator->doGenerate() (line 204 of core/lib/Drupal/Core/Routing/UrlGenerator.php).
Drupal\Core\Routing\UrlGenerator->getInternalPathFromRoute('view.h4c_map.map', Object, Array, Array) (Line: 293) Drupal\Core\Routing\UrlGenerator->generateFromRoute('view.h4c_map.map', Array, Array, 1) (Line: 105) Drupal\Core\Render\MetadataBubblingUrlGenerator->generateFromRoute('view.h4c_map.map', Array, Array, ) (Line: 753) Drupal\Core\Url->toString() (Line: 122) Drupal\views\Form\ViewsExposedForm->buildForm(Array, Object) call_user_func_array(Array, Array) (Line: 514) Drupal\Core\Form\FormBuilder->retrieveForm('views_exposed_form', Object) (Line: 271) Drupal\Core\Form\FormBuilder->buildForm('views_exposed_form', Object) (Line: 135) Drupal\views\Plugin\views\exposed_form\ExposedFormPluginBase->renderExposedForm(1) (Line: 2569) Drupal\views\Plugin\views\display\DisplayPluginBase->viewExposedFormBlocks() (Line: 34) Drupal\views\Plugin\Block\ViewsExposedFilterBlock->build() (Line: 203) Drupal\block\BlockViewBuilder::preRender(Array) call_user_func('Drupal\block\BlockViewBuilder::preRender', Array) (Line: 378) Drupal\Core\Render\Renderer->doRender(Array) (Line: 450) Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 195) Drupal\Core\Render\Renderer->render(Array) (Line: 124) Drupal\blockgroup\Plugin\Block\BlockGroup->build() (Line: 203) Drupal\block\BlockViewBuilder::preRender(Array) call_user_func('Drupal\block\BlockViewBuilder::preRender', Array) (Line: 378) Drupal\Core\Render\Renderer->doRender(Array) (Line: 450) Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 195) Drupal\Core\Render\Renderer->render(Array) (Line: 490) Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 118) __TwigTemplate_5739f58f4e0d1f47bd1e953fd2526475a97d2cdbe6a91a1bca565a98be44f522->block_sidebar_first(Array, Array) (Line: 215) Twig_Template->displayBlock('sidebar_first', Array, Array) (Line: 73) __TwigTemplate_5739f58f4e0d1f47bd1e953fd2526475a97d2cdbe6a91a1bca565a98be44f522->block_main(Array, Array) (Line: 215) Twig_Template->displayBlock('main', Array, Array) (Line: 63) __TwigTemplate_d84548ac530e850f0e4cfd1162ead857057599dfef445fba2733bfa582a65887->doDisplay(Array, Array) (Line: 432) Twig_Template->displayWithErrorHandling(Array, Array) (Line: 403) Twig_Template->display(Array, Array) (Line: 50) __TwigTemplate_5739f58f4e0d1f47bd1e953fd2526475a97d2cdbe6a91a1bca565a98be44f522->doDisplay(Array, Array) (Line: 432) Twig_Template->displayWithErrorHandling(Array, Array) (Line: 403) Twig_Template->display(Array) (Line: 411) Twig_Template->render(Array) (Line: 64) twig_render_template('themes/contrib/enzian/src/templates/system/page--map.html.twig', Array) (Line: 384) Drupal\Core\Theme\ThemeManager->render('page', Array) (Line: 437) Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 195) Drupal\Core\Render\Renderer->render(Array) (Line: 490) Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 84) __TwigTemplate_cdeba3f10bdc34526b86687e71a4a8ed261ad5e6729461146d02b3f2683427d2->doDisplay(Array, Array) (Line: 432) Twig_Template->displayWithErrorHandling(Array, Array) (Line: 403) Twig_Template->display(Array) (Line: 411) Twig_Template->render(Array) (Line: 64) twig_render_template('themes/contrib/bulma/templates/system/html.html.twig', Array) (Line: 384) Drupal\Core\Theme\ThemeManager->render('html', Array) (Line: 437) Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 195) Drupal\Core\Render\Renderer->render(Array) (Line: 147) Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 582) Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 148) Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90) Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object) call_user_func(Array, Object, 'kernel.view', Object) (Line: 111) Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch('kernel.view', Object) (Line: 156) Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 68) Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 57) Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 47) Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 99) Drupal\page_cache\StackMiddleware\PageCache->pass(Object, 1, 1) (Line: 78) Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 47) Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 50) Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23) Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 664) Drupal\Core\DrupalKernel->handle(Object) (Line: 19)Comment #16
hannessComment #17
geek-merlinOK for the records: when i backtrace in ViewsExposedForm::buildForm, i see
a) when the exposed form is rendered inside the view, it sees the argument
b) when the exposed form is rendered in the block, it seems not to see the argument
see below both backtraces.
Comment #19
5n00py commentedAfter few hours of digging found some useful details.
\Drupal\views\Routing\ViewPageController::handle
In this controller Views build
argsthat will be passed to Views executable.In case of bock we don't have this piece of work, views executed without arguments...
I write simple patch to fix issue on my sites. This problem should be fixed in proper way:
Currently (last patch) tests are incorrect. Test view shouldn't provide default value for contextual filter because it pull arg from current route instead of views path.
Comment #21
marcuschristopher commentedI stumbled over this only recently (working with 8.6.14), when combining a contextual filter for taxonomy terms with additional exposed filters. And it took me almost two days to finally find this issue (didn't know, if this was actually a bug or if I was doing anything wrong). Are there any news on this?
Anyway, thanks @damontgomery: The workaround in #11 turned out to be a great idea. Not sure, what was meant by "facet blocks"... I solved the issue by using a template file
views-view--taxonomy-term.htmland adding the sidebar with...there. Thanks for the suggestion.
Comment #22
N1ghteyes commentedIt is possible to use a form alter to fix the form action for exposed filters. I'm using Better Exposed filters, but you can remove that check if you like.
Comment #23
N1ghteyes commentedIt is possible to use a form alter to fix the form action for exposed filters. I'm using Better Exposed filters, but you can remove that check if you like.
Comment #24
beanjammin commentedUntil there's a fix N1ghteyes' approach of correcting the form action via hook_form_alter() provides full functionality with the exposed filter in a block.
Comment #25
stevenlafl commentedPatch #19 causes taxonomy feeds to show no content. D8.6.16
Comment #27
stevenlafl commentedA followup to this, I used patch #19 under buildForm of ViewsExposedFilter, I replaced the
with
and that appears to have solved it.
More information: Drupal 8.6.16. Using the Panels IPE to change the Block configuration of a Taxonomy Feed with contextual filter "Has Taxonomy ID". The "Content: Has Taxonomy ID" shows up in the Block configuration with 2 options: "" (blank, with a value of
@panelizer.entity_context:entity, the contextual filter) and "- None -". When I switch it to "- None -", the page errors out with"Parameter "arg_0" for route "view.taxonomy_term.feed_1" must match "[^/]++" ("" given) to generate a corresponding URL."I don't know whether this is a problem with panels/panelizer or core.
That said, even more information about how the value of "- None -" causes that error:
panels_ipeprovides "Content: Has Taxonomy Term" field by usingaddContextAssignmentElement. Upon saving, I get "Illegal choice detected" This is because theContextDefinitiondoes not have a label. To explain: the#optionsarray provided topanels_ipeis["@panelizer.entity_context:entity": null]As such, when it gets toFormValidator, the validation fails on!isset($options[$elements['#value']]) fails becauseissetchecks if the element is in the array AND is NOTnull. In this case, it isnull. It still saved in my case, and crashed the page on reload with a WSOD. Thenullvalue exists inarg_0causing the above error.If anyone else is having this problem, the above tweak to #19 fixed my issue.
Comment #28
edurenye commentedThe patch does not apply to 8.7.x and up,
Comment #29
stevenlafl commentedMy bad @edurenye, I meant to do that months ago.
Here it is.
Comment #30
ronaldtebrake commentedFrom a functional perspective both #19 and #27 work for me.
I personally believe it's a panels/contrib module problem.
Attached a notest path for 8.8
Comment #31
marcuschristopher commentedThanks a lot: The patch from #30 solved the problem for me. (Drupal 8.8.4)
Comment #32
ravi.shankar commentedHere I am trying to fix the failed tests.
Comment #34
nikitagupta commentedComment #35
hardik_patel_12 commentedSolving failed test cases.
Comment #37
rolki commentedThis patch is not ideal and creates another big issue, see
https://www.drupal.org/project/drupal/issues/3152554
I'll close that related ticket and fix the issue here.
Comment #38
rolki commentedThe patch that fixes the issue https://www.drupal.org/project/drupal/issues/3152554 here:
Comment #39
rolki commentedIt should be better now.
Comment #40
hardik_patel_12 commentedSolving failed test cases, kindly follow a new patch.
Comment #42
hardik_patel_12 commentedKindly follow a new patch , forgot to move
$map = $route->hasOption('_view_argument_map') ? $route->getOption('_view_argument_map') : [];inside theif ($route instanceof Route) {.Kindly follow a new patch.
Comment #43
hudriPatch #42 did not work for me (having the exposed filter in a block), contextual filters were gone after the first exposed form submit.
Comment #45
jeroendegloire commentedI confirm that on version 8.9, only the patch in #30 is working.
Comment #46
kivicky commentedNevermind - removing that comment since it was not caused by the same issue.
Comment #47
bobooon commentedPatch #42 only works if the view display is a page. Exposed forms in blocks can also be attached to block view displays.
Comment #49
ratvas commentedAlthough patch provided in #30 fixes the issue described, unfortunately it inadvertently broke the media library (which also uses Views). On version 8.9.16.
I am adding slightly updated patch with 'if' statement around the setArguments() call which still solves the original problem without breaking the media library.
Comment #50
mistrae commentedI couldn't apply the #49 patch so I created another one.
I've added some checks for empty args as it can break some functionalities such as title rewriting
Comment #52
andysipple commentedReporting this patch causes an issue when using the media library widget. Unable to select images in media library after sorting, filtering, or paging within the media lib widget.
Comment #53
ravi.shankar commentedFixed Drupal CS issue of patch #50.
Comment #55
gillesv commentedPatch #53 also breaks Media Library functionality, as mentioned in #49.
Comment #58
khiminrm commentedI've reviewed the patches and tried to create one which contains different conditions.
Comment #59
khiminrm commentedComment #60
khiminrm commentedAfter re-testing I see that the patch from #59 doesn't fix the issue.
Update: after re-testing again. It looks like the exposed filters in block work with contextual filter by using the patch from #59. Maybe I had some caching issues localy.
Comment #61
lugir commentedTried patch #42 and #59, still got same error messages after drush cr:
Comment #63
javitan commented#59 solves the issue for me using Drupal 9.5.5. I'm using a view with a contextual filter and I'm exposing the filters with Better Exposed Filters. Also the Media Library is working normally. Anyway, I removed an empty
if.Comment #64
javitan commentedUps, my fault. I fixed my last change. I cleaned
buildArgs()function.Comment #65
liam morlandRe-roll of #64 for 11.x.
This patch is also in the merge request.
Comment #67
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue.
While you are making the above changes, we recommend that you convert this patch to a merge request. Merge requests are preferred over patches. Be sure to hide the old patch files as well. (Converting an issue to a merge request without other contributions to the issue will not receive credit.)
Comment #68
liam morlandComment #69
smustgrave commentedThere's no issue summary. Please use the standard issue template.
Comment #70
liam morland.
Comment #71
liam morlandComment #72
smustgrave commentedLeft some comments on MR.
Will need some test coverage to show the issue.
Hiding patches for clarity.
Comment #73
liam morlandThanks; changes in comments committed
Comment #74
rollins commentedI tested the code from MR and got the next error:
Fatal error: Type of Drupal\views\Form\ViewsExposedForm::$routeMatch must not be defined (as in class Drupal\Core\Form\FormBase) in /var/www/html/web/core/modules/views/src/Form/ViewsExposedForm.php on line 21Comment #75
liam morlandI have removed using of constructor property promotion which should resolve the
$routeMatcherror.Another possibility would be to replace the use of
$this->routeMatchwith$this->getRouteMatch()and not inject it at all.Comment #76
smustgrave commentedThanks for keeping this going
Was previously tagged for tests so moving back to NW for that.
Left a comment about using promotion that should simplify things.
Comment #77
liam morlandI removed the constructor property promotion because when it is used, the property has a type declared. That type doesn't match the parent and so you get the error shown in #74.
To avoid all this, I just updated the merge request to use
::getRouteMatch().Comment #78
socialnicheguru commentedThis was available for Drupal 7, https://www.drupal.org/project/filter_harmonizer
Comment #79
vensiresThe changes from the latest MR solved the problem for me. Thank you!
Setting it as RTBC.
Comment #80
lendudeThis still needs automated test coverage before it can be committed.
Comment #81
vensiresIn my latest change I allowed the inclusion of parameters with the
allvalue.Without this change, URLs like
/foo/bar/[arg_0]/[arg_1]/[arg_2]throw an exception if [arg_2] has a value but [arg_1] isall.Comment #82
kevinquillen commentedNot sure if this is related to this issue, but I wound up in the same area of code that the patch is addressing but for another reason.
My case: I have a Views REST display with a path of api/v1/foo/bar/%node. It has two contextual filters. The first one uses the URL value to load a node for the contextual filter. The second one uses the currently logged in user.
The admin View UI preview works fine by just passing a node id in "Preview with contextual filters". However, if I am trying to assemble the URL to pass along for a decoupled React app, Views requires the two arguments:
If I visit api/v1/foo/bar/(node id) directly, I get results without needing the additional argument in the URL. If I curl the URL (with an authenticated cookie value from my session) I get a value.
I can alternatively do this:
but that is not so great to read or maintain. Should the URL be the equivalent of the path? How is that interpreted?