Problem/Motivation
We removed theme_link() #1985470: Remove theme_link() as part of a push to stop dedicating theme functions to tiny, single tag chunks of markup because it's overkill and would only get worse if we were to create a Twig template.
For links in particular, there have been many theme functions that are almost identical sort of piling up #1595614: [meta] Remove all the theme functions and templates in core that simply output a link. Replace with #type 'link' render arrays.
theme_more_link() is one of these functions that should not be converted to a Twig template.
Proposed resolution
Create #type 'more_link' that works much as #type 'link', but with a few extra default attributes set.
Remaining tasks
Commit patch.
User interface changes
n/a
API changes
Use #type 'more_link' instead of #theme 'more_link' in renderable arrays. The render array keys have changed as well to be in line with #type 'link'.
Original report by @thedavidmeister
Here is the current code for theme_more_link():
function theme_more_link($variables) {
return '<div class="more-link">' . l(t('More'), $variables['url'], array('attributes' => array('title' => $variables['title']))) . '</div>';
}
In order to reproduce this with #type = link, we need to make a render array with the following structure:
$more_link = array(
'#type' => 'link',
'#href' => 'admin/content',
'#title' => t('More'),
'#attributes' => array(
'#title' => t('Show more content'),
),
'#theme_wrappers' => array('container'),
'#wrapper_container_attributes' => array(
'class' => array('more-link'),
),
);
Comment | File | Size | Author |
---|---|---|---|
#142 | interdiff.txt | 1.32 KB | joelpittet |
#142 | 2031301-type-more-link-142.patch | 8.95 KB | joelpittet |
#140 | interdiff.txt | 854 bytes | joelpittet |
#140 | 2031301-type-more-link-140.patch | 8.93 KB | joelpittet |
#136 | type-more-link-2031301-136.patch | 8.93 KB | joelpittet |
Comments
Comment #1
jenlamptonWe may need to get this done before July 1st.
Comment #2
thedavidmeister CreditAttribution: thedavidmeister commentedI'm just about to go to bed. @jenlampton, would you mind rolling a patch for this?
Comment #2.0
thedavidmeister CreditAttribution: thedavidmeister commentedrela
Comment #2.1
jenlamptoncode
Comment #3
jenlamptonfirst go
Comment #5
jenlamptonmissed one
Comment #6
ericrdb CreditAttribution: ericrdb commentedChecked on following blocks
There is a "More" link on all blocks. Works.
Comment #7
star-szrNeeds some code style touchups, thanks for giving this a test @ericrdb :)
Extra space between => and drupal_render()
Trailing whitespace should be removed per http://drupal.org/coding-standards#indenting.
Comment #8
thedavidmeister CreditAttribution: thedavidmeister commentedminor whitespace cleanup only as requested from Cottser. RTBC as per #6.
Comment #9
thedavidmeister CreditAttribution: thedavidmeister commentedAs I mentioned in #1833932: Convert theme_system_compact_link() into a #type link, I do think there could be value in adding a central function that builds a render array for a "more link" but I think this should be a followup rather than something done here. It's probably something that would end up under #1804488: [meta] Introduce a Theme Component Library.
Comment #10
YesCT CreditAttribution: YesCT commentedThis issue was RTBC and passing tests on July 1, the beginning of API freeze.
Comment #11
Fabianx CreditAttribution: Fabianx commentedUhm, why?
Doesn't that defeat our lazy-render purpose?
Comment #12
thedavidmeister CreditAttribution: thedavidmeister commented#children needs to be a string if you want it to be set before sending it to drupal_render().
Changing:
'#children' => drupal_render($more_link);
to
'more_link' => $more_link;
Would probably work equally well.
Comment #13
catchYes let's do #12.
Comment #14
PanchoYes but let's first get the API change in #8 committed before API freeze coming into effect, and do the rest in a followup.
Comment #15
catchNo that's OK. We've explicitly said that some theme function -> template conversions can happen for a bit longer, and minor one-off theme function removal I think is OK for a little while too. API freeze was yesterday so this already slipped technically.
According to drupalcontrib no contrib modules use this at all http://drupalcontrib.org/api/drupal/drupal%21includes%21theme.inc/functi...
Comment #16
PanchoOK, so removing tag.
It's really hard to figure out what is allowed for "a bit longer" and what isn't. :)
Comment #17
catchWith something like this it's going to have to be case by case. This specific issue has the 'RTBC July 1st' tag on it, so it's definitely OK for a bit longer regardless of anything else anyway.
Comment #18
Eric_A CreditAttribution: Eric_A commentedWouldn't implementing the container theme hook as a #theme_wrappers property be even better? Or did that property got discouraged recently?
Either way #2031305: Remove theme_more_help_link() and replace with a #type link render array needs a follow-up I guess.
Comment #19
Eric_A CreditAttribution: Eric_A commentedAh, we have attributes on both the child element and the container. Thus no #theme_wrappers.
Here's #12 done, then.
Comment #20
Eric_A CreditAttribution: Eric_A commentedMissed one in forum.module...
Comment #21
Eric_A CreditAttribution: Eric_A commentedSo in fact in #19 I accidentally touched the pre-existing $container variable in forum_help() instead of the new container in forum_block_view_pre_render(). This bonus one-liner fix is still there in #20, not sure if it should be. Any big issues in the queue touching forum_help() that are ready and which would break because of this line?
Comment #22
Eric_A CreditAttribution: Eric_A commentedNevermind, it pre-existed since yesterday, and in fact this one-line would be the mentioned follow-up for #2031305: Remove theme_more_help_link() and replace with a #type link render array. Might as well do it here?
Comment #24
Eric_A CreditAttribution: Eric_A commentedComment #25
Eric_A CreditAttribution: Eric_A commentedYay, patch is green now.
Since theme_container() doesn't render child elements we do need to use '#theme_wrappers' instead of '#theme' when the container render array has child elements.
From drupal_render():
Comment #26
thedavidmeister CreditAttribution: thedavidmeister commentedUgh. #theme_wrappers and #theme sharing #attributes so you can't use them together in the same element. so broken... that means you couldn't convert theme_more_link() into #type 'more_link' and set container and link attributes separately as defaults.
I mean, it's nice that we're cleaning up the theme system, but we're paying for it in duplicated code :/
Anyway, review of the patch. I applied it cleanly, coding standards look good.
Why are we touching this? I don't think we should do this here. You are right though, 'container' should be #theme_wrappers only and we should be putting our new link render arrays in child elements to workaround the conflict with #attributes rather than early-rendering into #children.
Patch misses this comment in system.theme.css
Other than that, I think this looks good.
Comment #27
thedavidmeister CreditAttribution: thedavidmeister commentedfwiw #2042285: #theme_wrappers should be able to have a unique set of variables per wrapper hook.
Comment #27.0
thedavidmeister CreditAttribution: thedavidmeister commentedoutput
Comment #27.1
jenlamptonupdate code
Comment #28
Fabianx CreditAttribution: Fabianx commentedThis is really broken (the patch is nice, but theme wrappers will kill us more in the future than help),
We should have a #type => container, #content => 'inner render element' instead ...
Comment #29
jenlamptonBased on https://drupal.org/node/2042285#comment-7668681, what should we do here?
Comment #30
Fabianx CreditAttribution: Fabianx commentedI think getting #2042285: #theme_wrappers should be able to have a unique set of variables per wrapper hook in would be good to make this simpler.
Comment #31
Fabianx CreditAttribution: Fabianx commented.
Comment #32
jenlamptonokay, postponing until #2042285: #theme_wrappers should be able to have a unique set of variables per wrapper hook is in
Comment #33
thedavidmeister CreditAttribution: thedavidmeister commentedIt's in, so CNW.
As I said in #26, I'd personally actually like to see #theme 'more_link' converted to #type 'more_link' as we new should be able to build everything required for a "more link" in a single element without conflict from #attributes or forced nesting of child elements.
Comment #34
thedavidmeister CreditAttribution: thedavidmeister commentedThis introduces #type 'more_link' and uses the new #theme_wrappers syntax. I think it's a lot cleaner than what we've previously had to do here.
Comment #36
star-szr#34: 2031301-34.patch queued for re-testing.
Comment #37
jibranCode looks good to me nice clean up. I like new
#type
more_link
.I think we can add tests to check the output.
Minor issue
Can we make this one liner for readability?
Other then this is RTBC for me.
Comment #38
thedavidmeister CreditAttribution: thedavidmeister commentedI think tests should go in the file introduced here #2058761: PHP notice when #attributes is not set with #theme_wrappers 'container' - if/when it lands I'll do a re-roll here.
Comment #39
Fabianx CreditAttribution: Fabianx commentedIssue summary needs to be updated.
Comment #40
star-szrAlso needs a reroll.
Comment #41
thedavidmeister CreditAttribution: thedavidmeister commentedwe can totally add tests for this.
Sorry, I completely forgot this was postponed on that other issue. In my head it was waiting for a review >.<
Comment #42
trogels CreditAttribution: trogels commentedPatch rerolled. Didn't do anything for test though.
Comment #43
danquah CreditAttribution: danquah commentedI believe #42 accidentally used the wrong feed-id reference that got changed back in fd9804d88, attached updated patch should fix this.
Comment #44
joelpittet@jibran re #37 I don't think a one-liner in that case makes this more readable, I could be wrong, would you mind showing an example snippet?
@thedavidmeister re #41 which tests would you expect of these, I'll gladly write some.
This patch is looking really good, thanks for all who are involved!
Comment #45
jibran@joelpittet I think it should look like this.
I think it should look like this
Comment #46
thedavidmeister CreditAttribution: thedavidmeister commentedsee /core/modules/system/lib/Drupal/system/Tests/Common/RenderElementTypesTest.php for examples for tests.
Needs work until "Needs issue summary update" and "Needs tests" are cleaned up.
Comment #47
robynlgreen CreditAttribution: robynlgreen commentedChange made in attached patch
Comment #48
robynlgreen CreditAttribution: robynlgreen commentedComment #49
thedavidmeister CreditAttribution: thedavidmeister commentedStill needs work as per #46, but thanks for that update @robynlgreen :)
Would you be able to have a shot at updating the issue summary?
Comment #49.0
thedavidmeister CreditAttribution: thedavidmeister commentedoutput
Comment #50
joelpittet47: 2031301-47.patch queued for re-testing.
Comment #51
star-szrTagging for reroll.
Comment #52
BarisW CreditAttribution: BarisW commentedI'm pretty sure we don't need a wrapper div around the link. Please have a look here for that discussion: #2099289: Do we need a div around a more link?
Comment #53
joelpittetI'd like to say that too, just add the class to the link and call it a day. display: block that class if you need it to be a block element. More flexible and less divs.
Anybody disagree? I'll do that after the reroll if not.
Comment #54
joelpittetHere's the re-roll for #47
Comment #55
joelpittetI've added a test, @thedavidmeister will this suffice or does this test not work?
Comment #56
joelpittet@BarisW This is the change to get rid of the div... though the test I wrote clobbers the link's default attribute class. This is because the passed in definition of #attributes takes over in the array union. I could write a new pre_render and some workaround property but that feels like overkill... any suggestions to make what I have here work?
Comment #58
joelpittetComment #61
BarisW CreditAttribution: BarisW commentedWow @joelpittet, that was quick! :)
The proposal in the related issue is to use the class 'more' instead of 'more-link' (as the a element is obviously a link already). I have no idea why the tests fail, will look at it later today.
Comment #62
thedavidmeister CreditAttribution: thedavidmeister commentedNowpe, you can't avoid doing that. It is indeed a limitation in what #type can be used achieve and this highlights that #type has the potential in the future to be a lot more useful than it currently is - you can't even use it to provide a few default CSS classes on an element alongside existing classes.
Adding a pre_render would be a perf hit and increase the complexity of "more links" a fair bit, so no, that's not any more desirable than keeping the wrapper IMO.
I suspect this limitation is more likely the reason we still have wrapper DIVs for links than the wrappers themselves being desirable HTML.
As I understand, to achieve useful more links in both the sense of a consistent "template" for the structure of the links without making them inflexible, we need the wrapper OR to modify/extend how the #type system works.
Comment #63
Eric_A CreditAttribution: Eric_A commentedMerging your #attributes with the defaults can be done by leveraging element_info_property(), just like field_ui_field_edit_form() merges #pre_render properties.
Of course attributes is a deeper structure, so you'll need to choose the correct deep merging to get it right.
Comment #64
joelpittet@Eric_A where would you do this? Could you provide an example or maybe give this a try?
Comment #65
joelpittet@thedavidmeister, maybe if I had a #default_attributes that I merge in the drupal_pre_render_link?
Comment #66
joelpittetHow about this?
Comment #69
joelpittet66: 2031301-66-type-more-link.patch queued for re-testing.
Comment #71
joelpittetI've run these tests locally in the CLI and they both pass
"Drupal\system\Tests\Common\RenderElementTypesTest"
and "Drupal\image\Tests\ImageFieldDisplayTest"
So I'm going to retest again.
Comment #72
joelpittet66: 2031301-66-type-more-link.patch queued for re-testing.
Comment #73
joelpittetIf this fails the only thing I can think is the attributes are merged out of order and may need to change that to xpath or something else.
Comment #75
joelpittetOk can anybody else confirm test bot failures? Seems one of the failures went away from those retests but still two remain which I think has to do with what I wrote in #73
Comment #76
star-szr66: 2031301-66-type-more-link.patch queued for re-testing.
Comment #78
mariacha1 CreditAttribution: mariacha1 commented(Cleaning up the the tags that are no longer relevant.)
Tests are succeeding for me, although the patch didn't apply cleanly since the theme_node_recent_block function from node.module doesn't seem to exist anymore.
Rerolling the patch without that bit.
If this latest patch fails (which seems likely), I'll try the xpath method suggested in [#73].
Comment #80
joelpittet@mariacha1 thanks for re-rolling this, yeah the attribute/class order is likely to blame. If you need a hand I can take another stab. Good luck:)
Comment #81
joelpittetHere's the xpath stuff with another test.
Comment #83
joelpittet81: 2031301-type-more-link-81.patch queued for re-testing.
Comment #85
joelpittet81: 2031301-type-more-link-81.patch queued for re-testing.
Comment #86
joelpittetI'm curious about the testbot here... this passes in the UI and CLI locally.
php ./core/scripts/run-tests.sh --url http://d8.dev --verbose --color --class "\Drupal\system\Tests\Common\RenderElementTypesTest"
Comment #87
joelpittetProofs
Comment #89
thedavidmeister CreditAttribution: thedavidmeister commented81: 2031301-type-more-link-81.patch queued for re-testing.
Comment #91
joelpittet81: 2031301-type-more-link-81.patch queued for re-testing.
Comment #93
tim.plunkettI'm now getting a conflict on core/modules/system/tests/modules/theme_test/lib/Drupal/theme_test/EventSubscriber/ThemeTestSubscriber.php, and it seems to be failing me consistently locally.
Comment #94
joelpittetRe-rolled and fixed ThemeTestSubscriber.php. Crossing fingers.
Comment #96
joelpittetNot testing the path system, likely testbot is on a subdir. Thanks @larowlan and @timplunkett for helping me.
Comment #97
tim.plunkettWell we should have at least one with an internal path, and one with route names... Because it sounds like there is a real bug here.
Comment #98
joelpittet@tim.plunkett we should probably add those, to type=>link tests if they don't exist already as this just wraps that, don't ya think? We could try to get those working here too as a test to see what's up.
I guess instead of xpath I could actually make a type=>link equivalent to this extension and just render and compare outputs. May be mildly faster maybe and better suited test for this.
Comment #99
joelpittetComment #100
joelpittetMore tests, I think this should clear up any doubts of bugs. @tim.plunkett let me know.
Comment #101
joelpittetI think we covered our bases on the tests and the fails were likely just an oversight of how the tests were setup on my part originally but I'm assigning to @tim.plunkett to have a second look just incase he still sees that potential bug mentioned in #97 and let me know if we still need those extra tests or should I slim them back down and leave those to #type=>link tests?
Comment #102
tim.plunkettThe coverage looks good, but it no longer applies.
This can be \Drupal::url().
I don't see any added docs for #default_attributes, those should be added to hook_element_info().
Finally, this may have been discussed before, but why is this not just 'link__more' or something? Is the extra type worth it?
Comment #103
joelpittet@tim.plunkett thanks for reviewing.
Removed here #1985470: Remove theme_link()
Comment #104
tim.plunkett103.2, as I said, see hook_element_info.
103.3, that kinda sucks. Suggestions like that were really useful :(
Comment #105
joelpittet103.2, I see it now, for some reason that was tricky to find... not sure why:S
103.3. Mostly a performance issue, though I agree it was useful, maybe we should look at adding it back? Would like to see @thedavidmeister's take on that and maybe @c4rl and @Cottser too. It has implication for suggestions here as well: #2151107: Convert theme_system_compact_link() to Twig which I was recommending going the route of this issue, but if theme_link was back and used for #type=>link we could use it though that would mean defining it like:
Would need to be:
Which feels a bit more janky? Or do #type's take the same __ suggestion syntax?
Comment #106
star-szrJust tagging for reroll.
Comment #107
mark.labrecqueComment #108
mark.labrecqueTry this one
Comment #109
mark.labrecqueComment #111
mark.labrecqueComment #112
mark.labrecqueComment #114
thedavidmeister CreditAttribution: thedavidmeister commentedJust in response to #103 and #105.
theme_link() was never intended to be called directly, if you look at the internals of l() in D7 it performs sanitisation that was never in the theme function #1187032: theme_link needs to be clearer about saying not to call it directly so using #theme in this case skips some important "preprocessing" (not actual theme preprocessing, because there is no preprocess for links, for performance reasons).
If you've ever used #theme => 'link' in a renderable array you've been "doing it wrong" ;)
There are also performance implications of using #theme over #type, and the performance hit for trying to create a Twig template for individual links has caused multiple issue threads to become very long.
#1922454: Gut l(), fix theme('link'), have a working framework for consistently generated links inside and outside of Twig also has some relevant discussion.
I opened #2272577: Make #base_type a standard way to extend #type in renderable arrays. as well, which is tangentially related to those two comments.
Comment #115
joelpittetReroll, @thedavidmeister, mind giving this a review if it comes back green?
RenderElementTypesTest comes back green locally so crossing fingers. @mark.labrecque thanks for giving that a try, maybe you can jump on some other theme conversion reviews when we get to Austin?
Comment #116
thedavidmeister CreditAttribution: thedavidmeister commentedSeems fine to me. I've updated the issue summary as well.
Comment #118
xjmReroll for #2247991: [May 27] Move all module code from …/lib/Drupal/… to …/src/… for PSR-4.
Comment #120
andypost118: 2031301-psr4-reroll.patch queued for re-testing.
Comment #121
andypostComment #122
star-szrThanks for the PSR-4 reroll @xjm :D
Minor doc fixup and assigning to @joelpittet who I am sprinting with to write up a small change record :)
Comment #123
joelpittetChange record here. https://drupal.org/node/2281851
Needs a screenshot because we changed the markup by removing the div.
Comment #124
joelpittetThis clearfix would make this work but right now with the more-link without a container it's difficult to align it to the right without float: right;
I know mortendk loves killing divs. The div is killed so the CSS needs to be adjusted to keep it from zombie re-appearing to get this patch in.
Comment #125
andypostAlso there's
core/modules/views/templates/views-more.html.twig
with the same issue but without patchbecause its content the same (without DIV)
<a href="{{ more_url }}" class="more-link">{{ link_text }}</a>
so css could be fixed in own issue
Comment #126
tim.plunkett@andypost Those screenshots show a regression, that needs to be fixed here.
Comment #127
joelpittet@BarisW or @andypost we can add the div back in. That shouldn't be a problem. But I'll let someone stab at that regression first before I hastily add that back in.
Comment #128
lokapujyaThe more link needs to be a block element so that it's space is counted as part of the height of the gray background of the block. Since we are changing the text alignment from left to right, it actually needs to be inline but inside a block element, so we need the container div. We can't use float on the anchor tag because that removes it from the block height calculation.
Comment #129
joelpittet@lokapujya thanks, I agree, too bad we couldn't get rid of that div. So we have a fork in the road. We could try to hack this into #type link with a wrapper or something...
Though I think more straight forward would be to just convert the theme function to twig template. What do you think?
Comment #130
joelpittetOk so nobody has a solution, so going to plan B, straight conversion.
Sorry for the long way around...
Comment #132
andypostYou need to update
drupal_common_theme()
tooTested manually - no regressions
Just need profiling
Comment #133
joelpittetThanks for fixing that andypost!
Scenario:
11 more links on the page from 11 blocks. 1 Active forum topics and 10 aggregator feeds on the homepage.
http://www.lionsad.de/xhprof-kit/xhprof/xhprof_html/?run1=53d4352fc0c61&...
http://www.lionsad.de/xhprof-kit/xhprof/xhprof_html/?run1=53d4352fc0c61&...
Comment #134
alexpottSo the issue summary needs an update an maybe we need more consensus on converting to a twig template - which was introduced in #130
Comment #135
joelpittet@thedavidmeister and the other followers, any objections to just theme to twig template? If so please provide some reason and know that we went hard to make this a #type until about #126 where that superfluous div became necessary from a theming structural perspective.
Leaving the Issue Summary until a few people review what transpired.
Comment #136
joelpittetRerolled #122 with a suggestion from @thedavidmeister to use #theme_wrappers.
And moved the definition to a class called MoreLink, which was pretty cool because I can extend Link!
Comment #137
thedavidmeister CreditAttribution: thedavidmeister commentedI like the patch in #136, it's like an OO version of #34:)
Comment #138
thedavidmeister CreditAttribution: thedavidmeister commentedAlso, I'd like to re-iterate what I said in chat, which is that if we decide we've reached the point the only way to cleanly wrap a data structure in a div with an attribute is to write up a whole new Twig template, that's a Drupal-wtf fail.
Comment #139
star-szrWow this looks really great to me. The OO render element stuff is awesome. One thing held me back from the RTBC button:
drupal_render() instead of render() please.
Edit: Also I revised the change record to reflect the latest patch a bit better.
Comment #140
joelpittetrender to drupal_render as per #139 Thanks @Cottser.
Comment #141
star-szrThanks @joelpittet!
Nice test coverage and docs and I just updated the issue summary to reflect the latest patch. One more thing:
I missed these before, can these both use $this->t()?
Comment #142
joelpittetHmm it should be able to... it extends from StringTranslationTrait:)
Comment #143
star-szrIf the bot likes it so do I!
Comment #144
webchickNice clean-up, and test coverage, too!
Committed and pushed to 8.x. Thanks!
Comment #147
fgmThis breaks #1136680: #type 'more_link' - previously theme_more_link() - should have more context, which seem to still be relevant. Adding reference to it.