Needs work
Project:
Drupal core
Version:
main
Component:
routing system
Priority:
Major
Category:
Bug report
Assigned:
Unassigned
Issue tags:
Reporter:
Created:
11 Jun 2015 at 17:31 UTC
Updated:
28 Sep 2025 at 16:59 UTC
Jump to comment: Most recent, Most recent file
Comments
Comment #1
dawehnerI'm confused. These are part of the URL, how would you want to remove them?
Comment #2
effulgentsia commentedI think MainContentViewSubscriber should have a public method like getRequestWrapperFormat() around a protected variable, and subscribe to the REQUEST event where it sets that protected variable and then does:
$request->query->remove(static::WRAPPER_FORMAT).Similar for the
_ajax_formparameter, but not sure what service should wrap that one.Comment #3
effulgentsia commented#2 answers the "how?" question from #1, but if you meant "why?", then because that these are query parameters is a workaround to unfortunate implementation limitations. In an ideal setup, they wouldn't be query params, so cleaning up $request to match that more ideal setup would be a good thing, I think, and allow various link generation code elsewhere to not have to worry about it.
Comment #4
effulgentsia commentedDownside of that is then $main_content_renders need to be constructed that early. Maybe a separate service would be good then.
Comment #5
mondrakeA test-only patch, mostly taken from work done in #2182555: On Ajax-enabled forms with a pager, pager is disappearing on form validation error and on Ajax form reload.
Since #2263569: Bypass form caching by default for forms using #ajax. was committed, #2182555: On Ajax-enabled forms with a pager, pager is disappearing on form validation error and on Ajax form reload has been fixed as well as AJAX forms no longer get cached.
This patch now demonstrates how, on AJAX rendered forms, the
_wrapper_formatandajax_formparameters leak in the page links.EDIT: #2263569: Bypass form caching by default for forms using #ajax. was committed.
Comment #6
dawehnerI actually disagree, well at least in the current architecture, the controller returns a result and KernelEvents::VIEW convert that result into a request object.
Well, maybe the issue title is just chosen not perfectly. I think we should never alter the incoming request, its a detail you should not change, but yes, there should be a service which returns you all the query parameters, maybe the route match could hold such information, for example.
Comment #10
effulgentsia commentedThat's a good point. These query params are part of the request, so we shouldn't remove them from $request.
That's the problem that needs solving. We have various code that does stuff like
UrlHelper::filterQueryParameters(\Drupal::request()->query->all(), .... I wonder if we want to change filterQueryParameters() to automatically add _wrapper_format and _ajax_form to the exclude list. But should that list then be extensible (i.e., for contrib to use their own custom query params that they don't want bleeding into links)?Comment #11
dawehnerSure, I totally agree with that part.
The UrlHelper would be a bit unfortunate though, because its static and we should avoid adding yet another public global state. What about putting it into
RequestContext->getQueryParameter()?Comment #12
tim.plunkettThis may be the fault of the form system, but I think we're leaning toward a solution within the routing system.
Comment #16
jaypanI'll give a specific use case on the 'why' these should be removed. I'm building a list of results that has a pager. The results are updated using ajax. The pager is built using a render element of #type 'pager'. When the pager is built, it pulls all the query parameters, including 'wrapper_format' and 'ajax_form'. So when the user clicks on a page, they are redirected to an ajax result, rather than the next page of results. There is no way to override this, as the URLs are built automatically based on the current GET parameters, and these values are included in the GET parameter of an #ajax call.
Comment #18
tim.plunkettThis now blocks #2905676: ajax.js overwrites WRAPPER_FORMAT when already specified
I believe the new issue title is accurate?
Comment #19
joegl commentedWe are having the same exact issue as #16. As a workaround, we're overriding the "wrapper_format" parameter in the pager render array:
It makes sense to keep query parameters from the URL for the links, but it doesn't make sense to add an AJAX wrapper format to a non-AJAX link.
Comment #20
jaypanNice workaround! I'll be sure to use that in the future.
Comment #21
joegl commentedWhile passing a "wrapper_format" parameter to the pager is working, I'm having the same problem with the "sort" headers on a table render array and cannot find a workaround. This is definitely a major issue; one cannot use AJAX on the same page as a pager, sortable table headers, etc., without breaking the resulting functionality.
Comment #22
joegl commentedI found a patch in the following issue to resolve the table pager and sort header issues but I'm not sure about the approach: https://www.drupal.org/project/drupal/issues/2925598
Comment #23
joegl commentedThis and the below issue are proving to be devastating to the app we are attempting to build (I've posted this on both, apologize for redundancy but am really looking for some creative solutions).
#2504115: AJAX forms should submit to $form['#action'] instead of <current>
We have 4-5 pages where the majority of our functionality takes place, but almost everything happens via forms, modals and AJAX.
For example, let's we have a page with a list of users. Each user has certain actions such as "edit". When you click "edit" it uses AJAX to load a form with the user's data in a modal, with save and cancel buttons. At the top of page is a checkbox called "Display only active users". When the checkbox is clicked, a global variable is set, a new user list is pulled, and the current user list is replaced via AJAX.
The Problem: The new user list was built in the AJAX callback for the checkbox, and is wrapped in all of the AJAX data, query parameters, wrappers, URL's, etc., of the checkbox. This breaks all of the AJAX functionality for the user list, including the aforementioned "edit" link. It also builds all non-AJAX links as AJAX links, which break table headers, pager links, etc.,
I want to make sure I am taking the right approach and not missing anything, because this appears to be a pretty common use-case for AJAX.
Comment #25
alexpottAnother related issue - #2933413: Improve test coverage of using bulk actions when the view has an exposed form using AJAX
Comment #26
graber commentedSolution for #2933413: Improve test coverage of using bulk actions when the view has an exposed form using AJAX should solve all the functional problems forms in AJAX views are having, but the leaking parameters in links will remain. I'd put that data in a js variable after an AJAX request instead.
Comment #27
joegl commentedI'm confused and apologize. The referenced Views issue seems to be implementing a workaround for a core issue, which is AJAX form action URL's are being written incorrectly, and reference any past AJAX request which the form was built in (https://www.drupal.org/project/drupal/issues/2934463). Am I using forms wrong?
The request query parameters for ajax_wrapper's don't seem to be consistently or properly implemented. I still don't understand why I should have to specify or strip out the wrapper format manually (ajax_form, drupal_ajax, etc.,) when I code my forms and link render arrays; shouldn't Drupal core be smart enough to build these correctly? And if it's not, how I can fix it so it is? Because I would like to help if I can.
The workaround posted in the linked issue by mukila involves:
- Specifying a button with an AJAX callback URL (from a custom route that needs to be created; can't just use a callback)
- Specifying a direct override of the $request->query ajax_form parameter (set ajax_form = 1)
Why can't we just use a regular form submit AJAX callback?
Comment #28
joegl commentedI think this related issue needs to be solved in combination with this one, in order to get the AJAX built within AJAX issue fixed.
Comment #29
alexpottSo #2798947: Views pagers include ajax metadata has resulted in this being fixed for views. However that patch is doing what we're saying we don't want. Which is changing the request. If we work on stuff here then we probably need to undo the changes that issue has made.
Comment #31
andypostComment #32
falco010Currently I am having issues with the wrapper_format bleeding through my urls in the Core modal popup, this is my scenario:
I am using Drupal core modal popup and rendering node detail in the popup.
In this popup multiple fields and entities are rendered from the node detail view. Some of these fields are rendered links, the wrapper_format is bleeding trough in all these links and when clicked I see this:

As a workaround we are going to remove the wrapper_format query parameter from all urls in the popup with javascript. Does anybody have a better solution for this? Also tried removing these query parameter with hook_link_alter(), but this doesn't work.
Comment #33
panchoFixed the title (Don't know why, but
_wrapper_formatstarts with an underscore, whileajax_formdoesn't.) and reset to "Active" as apart from a test there's not yet a patch in this issue.Comment #35
penyaskitoComment #36
pcambraJust in case someone else runs into this, I was getting this issue with custom ajax requests on views (not pager) and the solution proposed by @effulgentsia on #2 seems to work very well.
I added an Event Subscriber that strips out the wrapper format on REQUEST in a custom module, leaving it here in case it's useful for someone else.
Comment #37
joegl commentedAny progress on this? I'd like to help if I can. I am stuck on the table sort headers at the moment -- the only recourse seems to be using JavaScript to manually strip the _wrapper_format parameter out of the each table header URL whenever a table is rendered by AJAX.
EDIT: I am going to try to modify JQuery I stole from here: https://drupal.stackexchange.com/questions/214358/drupal-tableselect-in-...
EDIT 2: The ^^ above JQuery doesn't work. It does strip the parameters off the table sort URL, which is great, but for some reason the table sort header Links are using the URL for the AJAX request the table was built within, while the Pager links stick to the main page.
Comment #38
joegl commentedIt looks like views completely rewrites these in their own ViewAjaxController and references this issue in a comment:
From views\src\Controller\ViewAjaxController.php:
Views also uses JavaScript to re-write the form action paths and ajax href paths to send through this controller instead.
Comment #39
geek-merlinAfter reading this issue, it looks to me like the most promising hint to fix this is @dawehner's #11:
Unfortunately we only have RequestContext->getQueryString(), not RequestContext->getQueryParameter().
But why and under what conditions (and from which code) do query parameters go into links in the first place? Wouldn't we want a whitelist, not a blacklist?
Comment #40
geek-merlinAnswering my own question: E.g. see #3070461: Facet links in modal popup break. Where facet links add all query parameters (to e.g. preserve views exposed filters) but must drop others (e.g. pager, or wrapper_format).
Note that changing the request like (#36) breaks some ajax (e.g. in admin/config/search/search-api/index/article/fields).
So the best i can see is adding some whitelist/blacklist registry to UrlGenerator.
Comment #43
yogesh kushwaha commentedI worked on solution based on 38 and replaced ajax generated href from current url and page number.
Form class
This is not complete solution but give some idea who can't wait to get it solved and patched.
Comment #47
simeonkesmev commentedI am facing this as well and I am wondering how bad is the following:
1. In the places where FormBuilderInterface::AJAX_FORM_REQUEST is set, do instead $options['ajax'] = TRUE or something similar
2. Create an outbound path processor that clears out the "_wrapper_format" and "ajax_form", but adds ajax_form if the $options['ajax'] is set.
3. Do a dodgy backward compatibility for modules such as ctools that also does this and issue a warning. It being a check whether the query param is TRUE or 1, and remove it if it's 1, as it's not explicitly set, but rather inherited from the current request query params.
Comment #49
manoxs commentedSolution #43 works great as a work around. I tested #2925598-17 Fixed pagination and sorting of tables on pages with ajax on 9.4 and still bleeding thru.
Comment #51
sayco commentedMy issue is partially related to the topic, but still, I'm here because of that piece of code
I really need access to the original data from the request (as for many of you my $form['#action'] is incorrect).
My proposal to sort this out is to clone the request object and push it to the request stack.
Thanks to that we can still get the main/master request and the current one.
In my case, I just simply wrote the Route Subscriber and alter the `views.ajax`
route with a custom controller.
In the controller I simply do the following:
The view is working without any issues (at least seem to be working fine), and I'm able to now do whatever I want with the data from the main request by
I hope this workaround will somehow help you with finding the right solution.
Comment #53
catch#3399951: ajax_page_state leaks through request in Views Ajax may have changed things here a bit.
Comment #56
matthijsI created an MR with the changes that were also suggested in #2504709-10: Prevent _wrapper_format and ajax_form parameters from bleeding through to generated URLs. It might not be the best nor a complete solution, but it fixes our issue.
Comment #57
smustgrave commentedLeft a comment but also test is failing.
Comment #58
cp19112000 commentedI think #51 will work. In my case, I’m using a view inside another view, with the sub-view rendered in an iframe; both are AJAX-enabled. The sub-view has an export button (Views Data Export). A normal export without filters works, but when filters are applied it leads to a text area instead.
This will work. Simple: