The submit button on Exposed filters breaks embedding of the view onto another page.
(Specifically, I've just used a view to render Category module's node-lists, as suggested and supported by that module, while using Exposed filters on the embedded view. The default page has the URL of Category, where the view is embedded, but submitting the filters take me to the URL for the view itself - so it shows up alone, without being embedded into the Category page, and what's worse, not given the argument filtering for that Category.)
My solution is to just mirror existing 'q' URL-argument on submit button (rather than constructing new one from the view) so that it always reflects the correct URL of any parent page calling the view. Works fine on my live site for weeks.
The only downside of my solution is, that the filtered page link doesn't have URL-alias anymore, but I don't think it's a problem, with all the mess of entity-encoded filter-values in the URL anyway.
Another fix on the submit button is its displayed label: Submitting contents to the Drupal site and filtering node-lists are both fairly different tasks, so the button names should not be the same. This caused a lot of trouble with localization, where an universal word for both the tasks doesn't exist in some languages, so with identical English labels, the translation is virtually impossible.
Patch attached (originally designed for Views 4.7.x-1.5, tested on 4.7.x-1.6-beta5, seems to apply on all recent versions)
| Comment | File | Size | Author |
|---|---|---|---|
| #15 | exposed-url.patch | 939 bytes | JirkaRybka |
| #9 | views-embed-url.patch | 488 bytes | JirkaRybka |
| views-submit-button.patch | 1.02 KB | JirkaRybka |
Comments
Comment #1
merlinofchaos commentedWhen embedding a view, the 'solution' is to modify $view->url just prior to calling views_build_view to point the view where you want it to go. In general I think this is an easier, if slightly confusing to the developer, method of embedding views in places they do not expect to be.
Comment #2
JirkaRybka commentedAh, I didn't know that. I'm not a developer, I just wanted to make my site work. Said that, this is probably a bug in Category package, which I'm probably unable to track down and report correctly.
But wouldn't it be much more simple for everyone, if my patch was used instead of requiring other modules to do tricky things? I'm afraid that very few module developers are thinking specifically about Exposed filters while embedding. My patch works well in all cases, I believe.
If this is rejected for a good reason - right. But I'm afraid that the situation is quite hard to solve at all, then. (Requiring all embedding module's authors to cooperate, I mean.)
Comment #3
JirkaRybka commentedChanging to "code needs work", assuming that my simple patch is not much welcome here.
After more checking, I noticed that on my Category+View embed only the Exposed filters button breaks, not the click-sortable table headers. I seem unable to find where these titles are generated for reference, but this is at least inconsistant. Clearly the URLs are constructed some other way on table headings (and good, even with URL aliases working), which should be used on Exposed filters submit also. Then no need to other modules modifying $view->something
The change of button-label for localization compatibility - no change of my opinion at all. Necessary.
Comment #4
merlinofchaos commentedHmm. I'm not so sure about 'Use filter'; filter is one of those terms that the end user isn't like to necessarily understand. I left it as Submit and, in general, that's themable (tho form theming is tricky but that's a Drupal issue). However, it is very generic for localization purposes and I agree that some other term might work better. Nothing immediately comes to mind, however.
Your patch does raise a point that perhaps using 'action' could get rid of that awful 'q' hack entirely, which is worth thinking about.
The reason this patch cannot be accepted is that sometimes $_GET['q'] is not the appropriate URL for the filters. For example, if I've themed the filters to appear in a block, I want the search button to take me to the actual view. That means that if a view is embedded, it must become the developer's responsibility to assign URL appropriately. It's entirely possible than an embedded view should go to the view.
Comment #5
JirkaRybka commentedI would rather think that an Exposed filter is merely a tool to control the node-listing behaviour, just like the clickable table-titles.
For the name of button, another suggestion might be "Search" or something like that, which is the case on my site. I'm not native English speaker, not much help here. BTW - end-user-confusing terms are all over Drupal.
Comment #6
JirkaRybka commentedOkay, submitting a new Issue to the Category module project, to fix my problem at the right place.
Just for reference - it's here: http://drupal.org/node/159378
Comment #7
JirkaRybka commentedBTW - the passing of URL to view->url while embedding is a bit strange thing, due to the filtering arguments (when used):
--- If URL alias is passed in, it breaks, because Views append the arguments to the URL. (In my case I passed 'url_alias_for_category', and the Submit button pointed to 'url_alias_for_category/###&filter_values', where ### is the third argument given to views_build_view. This URL doesn't work.
--- Luckily, in this case the argument is just node-ID, which is present in un-aliased URL already (but what if the argument was calculated by the embedding module, not present in the URL at all - heh?) So I sent 'node/###' to view->url ... And got 'node/###/###&filter_values' ! This one works, okay, but stil is not fully correct.
--- So finally I found out, that I should send 'node/$arg' to get just 'node/###&filter_values'.
My comments:
--- Can't find this in documantation (adding a comment now)
--- The URL on Submit button my not be aliased.
--- There should be a way to pass-in URLs, where the given arguments are not necessarily present. So we need some mechanism to leave passed-in URL untouched, if the view is embedded! (This whole problem is about view->url to view->real_url change.)
Comment #8
JirkaRybka commentedOk, the URL-problem is now fixed in category_views module ( http://drupal.org/node/159378 ), so this part is closed.
Changing the title now, to reflect remaining things to be solved somehow:
--- Submit button label to allow sensible localization
--- Discuss URL arguments affecting passed-in URL on embedded views
Comment #9
JirkaRybka commentedThe URL's on embedded View with Exposed filters AND arguments:
Passing URL's into embedded View via $view->url is currently insufficient, if there is some Argument given (third argument to views_build_view() ). Views always encode the Argument into the URL, either replacing "$arg" placeholder or just appending to the end, making it impossible to correctly embed into a page with URL not containing the argument (URL alias especially).
In the source code I read a comment on $type: " 'embed' -- Use this if you want to embed a view onto another page, and don't want any block or page specific things to happen to it." I think that URL-modifications should be also disabled by 'embed'.
So I created a simple patch (attached), resulting in the following behaviour:
--- If the View IS NOT the 'embed' type, all works just like before.
--- If the View IS 'embed', and the supplied URL contains the '$arg' placeholder, then the argument is encoded just like it was before (giving '$arg', the embedding module clearly wants the encoding to be done).
--- If the View IS 'embed', and there's NO '$arg', then the given URL is used without change (no encoding), allowing ANY url to be used, even if it doesn't contain the given arguments.
Comment #10
socialnicheguru commentedsubscribing
Comment #11
asak commentedactivelyOUT: I just found this thread too ;)
subscribing.
Comment #12
sunIs there a reason why would not want to check whether $view->url contains an $arg in any case?
Also, this patch does not adhere to http://drupal.org/coding-standards
Comment #13
Aar0n commentedsubscribing
Comment #14
abramo commentedSubscribing
Comment #15
JirkaRybka commentedNow on 6.x-2.x :
The problem of URL handling on Exposed filters' submit button in the case of embedded views still stands as it was in Views 1.x.
To summarize - once a view embedded on another page have Exposed filters, the submit button points to the view page (not the page where it's embedded), so just applying a filter to the shown list of nodes takes you to entirely different page. That's not desirable (in most cases, if not all).
Back on 1.x I was told to set $view->url explicitly to override the path - now it's renamed to $view->override_path, having quite the same function, and the same problem too: If arguments are given to the view (by passing them as function arguments while embedding), Views code still inserts the values into the path (either by replacing placeholders '%' [was '$arg' on 1.x], or appending to the end). This is fine on dedicated pages of the views, but with an external path override it breaks the path. If the argument values are present in the original [embedding page] url, somewhere, then we can work around the problem by passing a path with dummy placeholders for Views to replace, but while passing arbitrary arguments [not present in the actual URL], no luck at all. There's currently no way to pass an arbitrary path as override, without having it changed by Views.
Additionally, we now have a nice wrapper function views_embed_view() for easy embedding. This function is in the position
if a view is embedded, it must become the developer's responsibility to assign URL appropriatelyper #4, it'smeant to be called from PHP snippets, should one wish to embed a view in a node or something. It's meant to provide the simplest solution and doesn't really offer a lot of optionsper it's phpdoc, but still it lacks any handling of the embedding path, becoming unusable on views with exposed filters.(As a sidenote, the views_embed_view() documantation is misleading - it accepts a numeric ID of the view as first argument, not name.) EDIT: It accepts both, sorry for my misunderstanding.
-------------------------------
Example use-case (skip if scared of wall-of-text):
Let's say, I was writing a few articles about topics corresponding to Taxonomy terms on another content type, and wanted to embed lists of these related nodes somewhere in the article, also allowing the viewer to further filter the list. I'll create a View, and embed it through a snippet pasted to each of these articles. The View will have a few Exposed filters for additional filtering criteria, and an Argument [taxonomy term ID] in order to re-use the same View in all these articles, without the overhead of creating and maintaining a separate View for each taxonomy term.
Let's say article 'node/2' was about taxonomy term 3, and the re-usable view [ID=1] was called 'myview'. The snippet pasted to article 'node/2' is then:
<?php print views_embed_view(1, 'default', 3); ?>. It shows nicely in the article, but once the user tries to filter the list using Exposed filter, he is sent from 'node/2' to 'myview/3?filter_values_here...', so he is facing the filtered list alone. The article 'node/2' vanished from his screen.Since there's currently no way to pass a path override through views_embed_view(), we'll break it into pieces, and paste to 'node/2':
Now, if the user submits exposed filter, he is sent from 'node/2' to 'node/2/3?filter_values_here...'. The View is still embedded in the article, but URL got changed. You see - the argument value (3) is hardcoded in the snippet, and doesn't appear anywhere in the URL. Still, Views append it to the path, creating something weird. (Coincidentally, I had a comment #3 somewhere else on the site, and now it suddenly shows under the article 'node/2' where it shouldn't be.)
If I was passing the node ID that's in the URL already (i.e. '2' for 'node/2'), I can write
$view->override_path = 'node/%';, and let Views to replace '%' with whatever I passed as argument, but in this example I'm passing an arbitrary value there's no place for in the URL. Unsolvable problem.------------------------------
Proposed fix:
The attached patch makes two tiny changes:
- views_embed_view() pass the current path (from $_GET['q']) as an override, to ensure that embedded View always send the user back to the same page on filter submits. I know that #4 mentions edge cases, where $_GET['q'] might be inappropriate, but views_embed_view() is supposed to be the simplest solution for snippets, with not many options, right? This makes it work as expected. Note that the second fix (below) is needed for this to work well.
- If a path override is present, the arguments are only inserted to the path in place of placeholders. With no override (i.e. the native path of the view used), nothing changes, and the arguments get appended, as this is how the native Views' paths work. But the presence of path_override indicates, that the caller code took over the path which is therefore external and unknown-format to views.
While it's callers business to provide argument values for the view through function call arguments on embed, we can't know where and how he got the values from. If he decoded them from URL somehow, it's also his business to handle the reverse process, by indicating argument positions in path override using placeholders. If he got the values in some different way (like hardcoded value in the example above), we shouldn't touch the override path provided (we can't make assumptions about the embedding page behavior regarding path format/arguments).
It boils down to:
view_path/%-->view_path/arg_valueview_path-->view_path/arg_valueoverride_path/%-->override_path/arg_valueoverride_path-->override_pathComment #16
JirkaRybka commentedI would swear I changed the status, but apparently I didn't :-O
Comment #17
socialnicheguru commentedI tried this in a panel and it didn't work. I am not sure if this is a views or panels issue though. still investigating.
Comment #18
merlinofchaos commentedI disagree that it is not desirable for a views exposed filter to go back to the actual path of the view. In fact, I very much consider it the exception that you might not want to go back to the view path. So I am not currently in favor of this patch.
Your solution about 'views_path/%' vs 'views_path' also does not work. The presence of absense of % has meaning, because arguments can be optional and not appear. If the % appears, then the argument cannot be optional. So that change would cause breakage.
The one part I will agree with is that an override path might actually need to not utilize the arguments. In that case, I would be willing to accept a patch that allows $view->override_path_args() to use that instead of $view->args for determining the proper path. I do not, however, believe that embedding a view should automatically default to 'q' as the current path. While it is the case in your use cases, it is not the case in all use cases, and I prefer the current behavior.
Comment #19
JirkaRybka commentedI'll stick with overrides and workarounds then ;-) Just wanted to help improving this module, where the embedding stuff seemed flawed to me (I was really unable to imagine, what might be the other use cases you mention), but now this issue evolved to areas where I'm not much of a help. So be the use case recorded here for future reference, and I'm moving to more useful work.
Have a nice day.
Comment #20
hefox commentedcouldn't find anything about override_path_args or quite understand how'd that work.
Hmm.. simplicity sake, wouldn't introducing a new variable $view->override_url be a solution? IE. if that value is set in $view->get_url() return it without any further processing.
The change to implement that would be
Along with that with that could 'cache' the url at the end of get_url
It wouldn't help with the views_embed_view issue, however it'd be easier otherwise to change the URL when doing it before $view->preview()
ie easy for people to write:
Another issue is exposed filters in blocks (ie only the filter blocks) aren't effected since they're not made via the embed view but separately.
(However that was easy to fix in a form_alter, and was what I ended up doing personally).
Comment #21
Crell commentedExtra data point here:
I was trying to implement merlin's suggestion for messing with override_path for views_attach by putting the following into my display plugin's execute method:
That did work, but with one caveat. Since views_attach uses arguments but does not take them from the URL, I ended up with a very strange bug where the action property of the form when on node/5 was set to "node/5/5". :-)
I discussed this with merlin, and he suggested possibly adding a method to the display plugin interface to say "yes, tack on arguments when building the URL", which could then be called from view::get_url(). That's out of scope for what I'm working on, but I'm mentioning it here for reference in case anyone else decides to work on this. :-)
Comment #22
mghatiya commentedI put a "view with exposed filter" in a block, and when i click 'apply', it takes me to home page.
After going through this thread, I realized it is something to do url, so I checked the address bar and it showed url as:
http://localhost/gasalarm/?tid%5Bhsid%5D=50&tid%5Bhierarchical_select%5D%5Bselects%5D%5B0%5D=22&tid%5Bhierarchical_select%5D%5Bselects%5D%5B1%5D=42&tid%5Bhierarchical_select%5D%5Bselects%5D%5B2%5D=45&tid%5Bflat_select%5D%5B%5D=22&tid%5Bflat_select%5D%5B%5D=42&tid%5Bflat_select%5D%5B%5D=45&hs_form_build_id=hs_form_53684c6e0254a66b83d0a2e023ecdb5e
So I changed the url to
http://localhost/gasalarm/node/4/?tid%5Bhsid%5D=50&tid%5Bhierarchical_select%5D%5Bselects%5D%5B0%5D=22&tid%5Bhierarchical_select%5D%5Bselects%5D%5B1%5D=42&tid%5Bhierarchical_select%5D%5Bselects%5D%5B2%5D=45&tid%5Bflat_select%5D%5B%5D=22&tid%5Bflat_select%5D%5B%5D=42&tid%5Bflat_select%5D%5B%5D=45&hs_form_build_id=hs_form_53684c6e0254a66b83d0a2e023ecdb5e
I did this because the page on which my view was present was http://localhost/gasalarm/node/4/
But I am not sure if I have understood what changes to make in code to make it work always. Could someone please guide me?
To me also it looks like this is something that should be handled by Views Module itself. If there is some use case in which this behaviour is not desirable, then there should be some option or some such for that.
If I have misunderstood anything, please enlighten me.
I am using Drupal 6 and Views 2, and hierarchy_select module.
Thanks,
Mukesh
Comment #23
mghatiya commentedForgot to mention : When I make the above mentioned change to url, and paste it in address bar, it works.
Comment #24
mghatiya commentedI saw some similar issue in following pages.
http://drupal.org/node/578672
http://drupal.org/node/510356
But my view is already Ajax enabled. But it is still not working :(
Comment #25
mattez commented+1 Subscribing
Comment #26
crea commentedSubscribing.
Comment #27
esmerel commentedNobody's done work on this patch in months.
Comment #28
JirkaRybka commentedThis is sad, but what can I do... It smells like a misunderstanding - the maintainer wrote (#18):
This patch attempted to do exactly the same, i.e. avoid exposed filters going somewhere else. The misunderstanding, as I see it, is in the fact, that the "actual path of the view" is in fact the page embedding the view (in the case of embeds), not the page of the view alone (which is different from what the user normally see, incomplete in the case that view is intended to be just a subpart of something). I might even suggest to remove the page of the view alone, which is duplicate and broken in context of a view created for the sole purpose of embedding somewhere else.
I see no solution in the situation, where the only use case for a feature (that I can imagine), is broken, but still maintainer calls it edge case and just an exception not worth to be considered. There's no work I can do on the patch, except throw it to recycle bin, or reroll and ask for it to be reconsidered (which I already did enough times). Our opinions are obviously somehow incompatible... I can't do anything about that. So this is the end, I suppose, there's no point to argue.
Comment #29
brandy.brown commentedCan't delete, but my comment wasn't meant for this page.