Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
Generic off-shoot from #41595: All pager links have an 'active' CSS class
Problem
- If the current path is
/node
and a link to the same path but with query string is output via l(), then the link is'active'
, although it is not the current path.
Comment | File | Size | Author |
---|---|---|---|
#53 | 1410574-53.patch | 6.41 KB | kaidjohnson |
#45 | 1410574-45.patch | 6.37 KB | fietserwin |
#43 | 1410574-43.patch | 1.98 KB | fietserwin |
#39 | drupal8.l-query-active.39.patch | 6.99 KB | sun |
#36 | drupal8.l-query-active.36.patch | 6.79 KB | sun |
Comments
Comment #1
bleen CreditAttribution: bleen commentedThis patch takes care of the issue at hand, however the tests will not pass because siimpletest plays with the querystring in such a way that I cannot seem to get the existing testLActiveClass() and testLCustomClass() tests to pass.
Any advice is welcome...
Comment #3
fietserwin- Considering the performance sensitivity of this function, I would suggest to only look at the query part if the path part is equal to the current path. That is: move the code introduced by this patch into an if.
- Can the front page have a query part? I guess yes, as even the default front page uses a pager (if I'm correct, I've never used the default front page so far). If so, the query part should also be taken into account for the front page case. Combined with my previous remark, I think that this results in moving the new code into the already existing if.
- Why call url(), check_plain(), parse_url(), array check, array access, str_replace, and parse_str, to get what is directly available in $options['query'], though as an array? So it seems better to compare $options['query'] with parse_str($_SERVER['QUERY_STRING']). Please add a comment that we must use == (same key/values) and not === (same key/values, same order), and that we neither can use http_build_query($options['query']) === $_SERVER['QUERY_STRING'] for the same reason (being: different order in query is still the same resource).
Note: not passing in a query part (to the l() function) in the $options array but in the $path parameter is at your own risk and you're self responsible for encoding and such. So, IMO that is a case that we don't have to cater for here and thus this optimization is possible. Moreover, a (the only?) valid use case for passing in the query part in the $path is external URL's and they never equal the current page...
I think that in the resulting patch, any performance implications won't be on the critical performance path anymore, and thus this patch can get in more easily.
Comment #4
fietserwinI think that links to fragments in the page should also be excluded from getting the active class. Example: the "Add new comment" link to the reaction form at the end of a page (where comments are enabled). If others agree, we should change the title to something like:
Make l() respect the URL query string and fragment part before adding the 'active' CSS class
Code wise it will become only just a bit more difficult. Just check if there is a fragment entry in the $options array and if so do not add active. I think that the function documentation should be extended with a more elaborate description of what the "active" class on a link conceptually indicates.
Comment #5
sunNo, fragments need to be ignored. That's by design.
Comment #6
tim.plunkettThis is just a test, I disregarded the patch in #1 for now.
Comment #8
tim.plunkettHow about this?
Comment #9
tim.plunkettThis works, but needs a test case for when you're on a page with a query string, which I guess will need a custom module?
Comment #11
tim.plunkettOkay, added a full test case fixed above failures.
Comment #12
bleen CreditAttribution: bleen commentedGlad to see that I was kinda close on the right way to accomplish this. #11 is much cleaner and I just gave it a test drive (while watching the NYC Camp keynotes). Everything looks great.
Comment #13
sunWe might also want to revert the stop-gap fix in pager.inc that was done to theme_pager_link() in the original issue? Just reverting the functional code will let us see whether the new pager tests are passing with the proposed fix here.
Also:
Isn't this the same as $_GET ?
Comment #14
tim.plunkettEven better!
I'm removing the last assertion of UrlTest::testLCustomClass() because it duplicates UrlTest::testLActiveClass() and is also wrong.
Comment #16
tim.plunkett#14: drupal-1410574-14-combined.patch queued for re-testing.
Comment #18
tim.plunkettApparently
request()->query->all()
doesn't work on the testbot?WFM locally...
Comment #19
sunUrlTest fails with run-tests.sh, because it does not set up a Request object.
This patch passes with run-tests.sh, when combining it with #1215104: Use the non-interactive installer in WebTestBase::setUp()
Comment #20
tim.plunkettOkay, $_GET is still used in plenty of places in core, and Crell says that request() is a temporary function anyway. Might as well stick with what works.
Comment #21
sunAdded a comment and enabled the regression test.
Comment #22
tim.plunkettI guess the 'API change' tag makes this not backportable to D7? :(
But now there are no added function calls, so the performance isn't a problem anymore.
Comment #23
sunI'm... not sure. The stop-gap fix for theme_pager_link() was possible to backport, because it had a focused and controlled effect and consequences. While this technically just fixes the bug in a generic way, the change impacts all links on a site. This can mean a unexpected change in behavior, potentially making existing themes look wonky in case they rely on the current misbehavior for styling.
But aside from that - yay for even passing the pager tests! :) This looks RTBC to me.
Comment #24
tim.plunkettWell we can have that conversation with David_Rothstein at the proper time. I know I need this fix for a D7 site with links to different Search API filters all showing as active.
Comment #25
sun#21: drupal8.l-query-active.21.patch queued for re-testing.
Comment #27
danillonunes CreditAttribution: danillonunes commentedJust rerolled patch from #21.
Comment #29
sunFixed the test failures.
This patch blocks #1778990: Merge theme_pager_link*() theme functions into theme_link()
Comment #30
catchLooks good to me.
Comment #31
tim.plunkettI don't know if we should still be using $_GET here
Comment #32
sunLet's leave that conversion of $_GET to whatever-kernel-esquy to another issue and WSCCI folks to figure out, pretty please.
Comment #33
Crell CreditAttribution: Crell commentedI'm not sure that $_GET is reliable anymore now that we are sometimes firing subrequests. For now, the alternative is fortunately simple:
drupal_container()->get('request');
We can convert it to something purdy and injected later, but at least for now we should be accessing the request.
Comment #34
sunThat's needless duct-taping right now IMHO, but here you go.
Comment #36
sunSo update.php does not use the kernel yet, which means that drupal_container()->get('request') is not available.
Attached patch hacks the service definition into the update.php container in the same way we're hacking other services into the container there already; i.e., this workaround pattern is not introduced here.
Hopefully this comes back green. This patch still blocks #1778990: Merge theme_pager_link*() theme functions into theme_link(), and I need to move forward there ASAP (bound to feature-freeze).
Comment #37
sunAlright, #36 passed, which means that the injection of the request into the container in update.php works as expected.
Can we move forward here? :)
Comment #38
fietserwinThere are 3 conditions that have to be met to get the active class (path, language, query):
- Only the 3rd is extensively documented.
- The first 2 are joined in 1 if, the 3rd has its own (inner) if
So IMO it would be better to join all conditions in 1 if, with 1 extensive comment before that code that (shortly) explains the conditions to be met. OR: create 3 separate if statements with 1 comment line each.
Do we need to link the @todo's by also referring to this todo in the index.php as well? (or are there other means to take care of the @todo)
Comment #39
sunI was not really happy about the added inner condition, too, so I've rewritten the conditional logic in l() and also adjusted the comment to explain all three conditions.
There's no new @todo introduced here, thus nothing to update or reference.
Comment #40
fietserwinGreat, awaiting the test results ("test request sent" at the moment of writing), but for me this is RTBC.
Comment #41
fietserwinThe test results are in, it has been RTBC before, so for me good enough to move to RTBC again.
Comment #42
catchLooks good. Committed/pushed to 8.x.
Comment #43
fietserwinTried to backport it to D7. This patch is a mix of:
- #39
- #29 (as $_GET has to be used in D7)
- Undoing the changes from #41595-16: All pager links have an 'active' CSS class (as #39 also already did) that solved the problem for theme_pager_link() only)
The tests from #41595: All pager links have an 'active' CSS class, which are part of the test collection, should show that this patch is also working fine. I am not sure if more tests are needed.
I agree with #41595-55: All pager links have an 'active' CSS class that states that this is not an API change.
Comment #45
fietserwin- $_GET does contain 'q' in D7, so remove that in a copy of $_GET before comparing. This repaired most of the failing tests.
- The changes in testLActiveClass() from #39 are now also back-ported as in the current situation it tests without taking the query into account.
Comment #47
fietserwinWorks locally and does not seem to be related ...
Comment #48
fietserwin#45: 1410574-45.patch queued for re-testing.
Comment #49
bleen CreditAttribution: bleen commentedThat doesnt sound right...
Comment #50
fietserwinre #49: That is how Drupal (until now) works: clean URLs are "rewritten" to index.php?q=..., see this code in bootstrap.inc:
So clean URLs or not, the q parameter will always be there.
Comment #51
bleen CreditAttribution: bleen commentedblarg ... read that as "doesnt"
Ignore me
Comment #52
acbramley CreditAttribution: acbramley commentedEncountered this issue and it seems like one that definitely should be fixed. Patch #45 doesn't apply to 7.23 cleanly so I haven't had a chance to test yet.
Comment #53
kaidjohnson CreditAttribution: kaidjohnson commentedRe-rolled against latest core dev. Applies cleanly to 7.24.
+1 for this patch.
Comment #54
Crell CreditAttribution: Crell commentedhook_menu is not long for this world. MENU_CALLBACK type requests should have been using the new router exclusively for months now. Please do not add more hook_menu entries.
Comment #55
acbramley CreditAttribution: acbramley commented@Crell can you please link to some documentation that explains this? I'm still seeing MENU_CALLBACK documentation for both 7.x and 8.x (although I have heard that hook_menu is dying in 8.x). Since this is a D7 patch though I don't quite follow your comments?
Comment #56
marcvangend@acbramley: Documentation is in the WSCCI Conversion Guide. The change notice was posted in October 2012 at https://drupal.org/node/1800686. I found a simple example at http://drupal.stackexchange.com/a/80714/226.
Comment #57
tim.plunkettNo Crell and Marc, this was committed.
acbramley they are talking about d8 but the issue is for d7, carry on.
Comment #58
marcvangendThanks Tim, I stand corrected. I was just trying to answer #55 but I didn't pay attention to the context. Excuse me acbramley for the confusion.
Comment #59
Crell CreditAttribution: Crell commentedD'Oh! I missed the version tag, sorry. Ignore me!
Comment #60
acbramley CreditAttribution: acbramley commentedI can confirm the patch on #53 correctly adds the active class to links with query parameters when the url matches
Comment #61
mgifford53: 1410574-53.patch queued for re-testing.
Comment #62
devkinetic CreditAttribution: devkinetic commentedJust a note. The patch in #53 almost works for D6. Just some minor variable changes.
Comment #63
mgiffordPatch still applies nicely to the git repo.
Tested it with this on SimplyTest.me:
I don't know that it needs to be any more complicated than that. The active class appears as expected.
Comment #64
David_Rothstein CreditAttribution: David_Rothstein commentedThis is tricky because sometimes query strings meaningfully change the content of the page and sometimes they don't.
For example, if you have a View with exposed filters, this patch results in the menu item for that view losing the "active" class when the filters are selected (though "active-trail" is still there). Depending on how the theme uses those classes, this could really lead to undesired behavior.
I think we need to discuss the backport a bit more. Would it make sense to consider adding a new class for these situations but keeping the behavior of "active" the same as it is now?
This looks a little buggy; it cares about the order of the elements in $options['query'] and $real_query_params being the same (not just their contents), but the order shouldn't matter.
Is it possible $_GET['q'] was used over current_path() here to micro-optimize performance in this heavily called function? Doesn't look like the patch needed to change this if() statement at all, anyway.
Comment #65
BarisW CreditAttribution: BarisW at LimoenGroen commentedI would love to have this in. This is a real bugger when using search to make listings. For example, one could have an overview with articles by pointing to
search?type%3Aarticle
and another overview with news items by pointing tosearch?type%3Anews
. If both these overviews are linked to from the main menu, both will get the active class.Comment #70
marcvangendShouldn't the status be "fixed"? Or am I missing something?
Comment #71
fietserwin#70: not yet fixed in 7.x?