Split out of #2214249: Fields classes - what do we actually need & want in Drupal8 twig:
Problem/Motivation
All classes are produced in a preprocess that makes it hard for a themer to manipulate these into whatever you need.
I propose we remove them all from the preprocess and move them into the template file, so its easy to find and manipulate.
(twig template at the end)
Proposed resolution
Remove class creation from the preprocess functions and add them in the Twig templates using the addClass() attribute method and the clean_class filter.
Preprocess Functions Modified
core/includes/theme.inc: template_preprocess_field
core/modules/comment/comment.module: comment_preprocess_field
core/themes/bartik/bartik.theme: bartik_preprocess_field
Twig Templates Modified
core/modules/system/templates/field.html.twig
core/modules/system/templates/field--comment.html.twig
core/modules/system/templates/field--node--title.html.twig
core/themes/bartik/templates/field--taxonomy-term-reference.html.twig
Test instructions
Create a new node.
Add a comment.
Make a note of the markup that a field produces.
Apply the patch.
Now check the markup of the field again it should match the markup from before the patch was applied.
Beta phase evaluation
Issue category | Task because it improves the Themer Experience. |
---|---|
Issue priority | Normal because it should not affect many people. |
Unfrozen changes | Unfrozen because it changes markup. |
Prioritized changes | The main goal of this issue is usability of the new Twig theming layer, and since it adjusts markup it must be completed prior to RC. |
Disruption | Disruptive for core/contributed and custom themes because it is part of the Consensus Banana to move CSS classes from preprocess to twig templates. (#2322163) |
Comment | File | Size | Author |
---|---|---|---|
#224 | 2217731-224.patch | 12.94 KB | seantwalsh |
#218 | 2217731-218.patch | 12.92 KB | lauriii |
#218 | interdiff.txt | 4.67 KB | lauriii |
#207 | move_field_classes_out-2217731-207.patch | 11.84 KB | davidhernandez |
#201 | interdiff.txt | 642 bytes | lauriii |
Comments
Comment #1
mortendk CreditAttribution: mortendk commentedYES Thanx for dragging this out of the what classes do we want inside of a fields div :)
i especially love the {{ attributes.class }} this will make it easy for a module to add in a required class - best of both wolds.
This also forces the field.html.twig file & makes it easy for the themer to understand what goes on.
Comment #2
LewisNymanThis patch only works if you apply it on top of the patch in #1987398: field.module - Convert theme_ functions to Twig. Once that's committed this will be ready for testing. Feel free to give it a code review though.
Comment #3
LewisNymanOops wrong patch
Comment #4
barraponto CreditAttribution: barraponto commentedI think it adds complexity. I mean, if I look at markup and see a class, I expect to see it in hook_preprocess_template.
Of course next thing I check is the template. But if someone wants to see what classes my theme is removing, it'd be better if he/she only needed to check one place.
Comment #5
rteijeiro CreditAttribution: rteijeiro commentedLet's test it! :)
Comment #7
mortendk CreditAttribution: mortendk commentedThe reason that we wants to expose the variables directly in the template is to make it clear & visibile to the themer to work with it - we dont want to "hide" thes things inside php, out in twig with it, so the themers dont even have to know its php ;)
Comment #8
mortendk CreditAttribution: mortendk commentedwe discussed today at the codesprint in stockholm, that it would be a good idea to have the names as a keyed array instead and save a bit of memory.
class="{{ attributes.class.foo }} {{ attributes.class.bar }} {{ attributes.class.baz }} {{ attributes.class
}}"Comment #9
barraponto CreditAttribution: barraponto commentedI'd like to hear more about that, I didn't know the attributes class variable was keyed.
Comment #10
mortendk CreditAttribution: mortendk commentedThey are not keyed at the moment, but afaik that would be a huge win & not freak out the developers that were gonna transport each var as a single variable and not just 1 array :)
Comment #11
barraponto CreditAttribution: barraponto commentedSo instead of
$attributes['class'][] = 'new-thingie';
I'd have to write$attributes['class']['new_thingie'] = 'new-thingie';
? Ugh.Comment #12
mortendk CreditAttribution: mortendk commentedif you want to add new-thingie class you would do
easier for the themer :)
Comment #13
barraponto CreditAttribution: barraponto commentedyeah, but I'm a module writer half of the time ;)
Comment #14
LewisNymanI think it's easier to decide what is best if we focus on a certain user objectively. Does something like that exist for the Twig initiative?
I'd imagine it would be for the benefit of non-module developers who don't use php, which makes the decision here simple.
Comment #15
mortendk CreditAttribution: mortendk commentedwe have had discussions about this for 2 years - im gonna see if i can find all the documents & minuts that was written down from the many many meetings that have been done. -but yes one objective was to make it as awesome for the themer as possible.
Thats one of the core values of shifting to twig, its about empowering the themer. :)
Comment #16
barraponto CreditAttribution: barraponto commentedWould
class="{{attributes.class.foo}}"
break iffoo
was removed from a preprocess?Comment #17
pakmanlh3: drupal-field-classes-templates-2217731-3.patch queued for re-testing.
Comment #18
pakmanlhI rerolled the patch by adding classes inside ['class'] variables to make them available by separate and I added the comments on twig template. I hope it was the expected result.
Comment #19
rteijeiro CreditAttribution: rteijeiro commentedSome changes:
Maybe
$variables['attributes']['class']['entity_type_css'] = 'field-' . strtr($element['#entity_type'], '_', '-');
should be$variables['attributes']['class']['entity_type_css'] = strtr($element['#entity_type'], '_', '-');
Maybe
$variables['attributes']['class']['field_name_css'] = $variables['attributes']['class']['entity_type_css'] . '-' . strtr($element['#field_name'], '_', '-');
should be$variables['attributes']['class']['field_name_css'] = 'field-name-' . strtr($element['#field_name'], '_', '-');
Comment #21
pakmanlhRerolled adding @rteijeiro modifications and considering the new preprocess_field function location.
Comment #23
pakmanlh21: drupal-field-classes-templates-2217731-21.patch queued for re-testing.
Comment #24
LewisNymanI think there's a simpler way to document keyed items in an array using indentation.
Comment #25
pakmanlhDocumentation included in few indented lines and I recovered the example classes removed from the #3 patch.
Comment #26
mortendk CreditAttribution: mortendk commentedcan we please remove clearfix completely ?
it will be done with sass in the future & theres no reason that drupalcore puts that out (sorry im ranting but i hate it)
im thinking that we should do this with the set command in twig instead makes it easier to look at :
in the twig template:
then we can call that cssclass (or whatever we call it)
Comment #27
jjcarrionComment #28
jjcarrionI have remove the clearfix, but to avoid that the feature of the inline breaks the field display I have added to the system.theme.css the same lines that we got in the .clearfix selector to the .field-position-inline selector.
Right now we are not going to put the class 'hidden' neither 'above' because we think that it's not neccesary to show that information.
Comment #30
jjcarrionSorry for my previous patch, here is again.
Comment #31
jjcarrionComment #32
XanoThis issue is about moving the classes and not about changing them at the same time. Let's add or remove classes in a follow-up and focus on the actual move here.
These are not styles, but classes.
I believe this value is one of a set, so it's probably a good idea to document this set here so people know what values to expect.
Comment #33
barraponto CreditAttribution: barraponto commented@mortendk no, we can't act as if SASS/Compass is in core. We can make it easy to remove classes you don't use (which is usually accomplished with preprocess). If you move the classes to the templates, then you have to copy over the templates and modify them.
Comment #34
mortendk CreditAttribution: mortendk commented#facepalm wrong filename
Comment #35
mortendk CreditAttribution: mortendk commentedadded in clearfix to the template - were removing it in a follow up issue :)
Comment #36
mortendk CreditAttribution: mortendk commentedComment #38
star-szr36: 2217731-drupal-field-classes-templates-34.patch queued for re-testing.
Comment #39
jjcarrionI have delete the part of the clearfix from this patch, so it can be worked in another issue.
Here is the new patch and the interdiff.txt
Comment #40
jjcarrionComment #41
RainbowArrayRemove extra whitespace?
Change to:
I don't think we need those extra spaces, based on my understanding of Twig whitespace handling. Always possible I'm wrong.
Comment #42
mortendk CreditAttribution: mortendk commentedA question here woudnt it be better for the theme if the [class] variables is a regular variables so we can test on that inside of the field ?
preprocess:
template
The good thing here would be that the theme then could do test on the field_type etc so giving the theme more power.
im gonna check if we can grap that data out somewhere else of the string though
Comment #43
mortendk CreditAttribution: mortendk commentedI looked a bit more on the patch and we actually have all the data available right now - you just have to look for it the right place.
This patch graps the data fx {{ element['#entity_type'] }} and used that instead & then in the template do a replace on the new lines & the _ to -
thats pretty awesome imho & we dont end up having to do a lot of preprocess stuff now that we alreayd have the data + its easy to read as well with all the classes + removing what you dont want :)
Comment #44
LewisNymanWasn't this issue supposed to make it really easy and simple to change classes? This is no longer easy to understand and change without fear of breaking something. We might as well keep this in a preprocess if this is what we have to do to put it in a twig file.
Comment #45
mortendk CreditAttribution: mortendk commentedI don't understand the fear here - we have as a core value that we dont wanna dump it down ;) - and honestly what is it thats not to understand here.
{{ element['#entity_type'] }}
{{ element['#entity_type'] }} is the value that drupal puts out, the only reason that we dont write is as {{ element.entity_type }} is because of the issue of not beeing able to drill into #, as twig understands this as a comment - this is a general issue that we have, which is sucky.
After thinking a bit about i dont think it make sense to have a specific attributes.class.foo ( $variables['attributes']['class']['entity_type_css'] = strtr($element['#entity_type'], '_', '-');) it makes the strings very long {{ attibutes.class.entity_type_css }} & we adding this data in, when we already have it in {{ element['#entity_type'] }}.
if we do the strstr in the preprocess (and i can see the reason for that), we should not hide it down in {{ attibutes.class.entity_type_css }} then lets add them at a higherlevel instead fx {{ entitytype_safe }} if we wanna make it easier to read
Doing a filter on the class that we have set, is normal twiging, thats a feature in the language:
{% filter replace({'\n': ' ', '_': '-'}) %}
the replace \n is to make the {{ cssclass }} more readable by having each part of the class on its own line, to make it very easy to read & understand whats the values are available instead of one long string.Comment #46
mortendk CreditAttribution: mortendk commentedok after sleeping a bit on it it comes down to the problem, that we have a lot of classet atm thats added to a field, and we still havent taken the disucssion about what we actually want there (and that will be a seperate issue - so dont start it here) so it quickly gets confusion whats actually going on here
i see 2 approaches to this :
set class
inside the template - here were using what fields already provide to us form fields & everythings is done with twig. It do look a bit more scary, but its epic power, each class is split into a new line to make it easy to figure out whats going on.
Preprocess some & add vars
The other approach would be to preprocess the _ to - to make it a bit cleaner and put them out into vars - not the {{attributes.class.entitype}} it gets way to long imho & is not easier to read.
preprocess:
then the template would be something like this:
or do a combination
Its 3 different approaaches that gives the themer a ton of flexibility & we dont break modules ability to add in classes if its neede
Comment #47
LewisNyman<div class="field field-{{ entitytype_css }} field-{{ entitytype_css }}--{{fieldname_css}} field-name--{{ fieldname_css }} field-type-{{ fieldtype_css }} {{ label_display_css }} {{ attributes.class }}" " {{ attributes }}>
I think we could remove the "_css" after each variable name. I don't think it's important to know how they are formatted. Themers should assume all variables we pass to tempaltes are CSS safe, right?
Comment #48
RainbowArrayPersonally, I prefer the preprocess approach. That still gives us variables we can use to construct classes within the template, it's just that the messy work with strings isn't right out in the open.
I don't see a compelling use case for being able to handle that string manipulation within the template. If there are specific examples of how that epic power would be wielded, I'm glad to listen. I do think that one of the other principles is trying to solve problems for 80% of the people, and I think that creating the variable names in preprocess gets much closer to that sweet spot.
I'm fairly familiar with how Twig works now, and I find that string manipulation code intimidating. I think that new people are even more likely to be nervous when they see that and get worried they might break something.
The people who wouldn't be intimidated by that are also probably people who wouldn't be intimidated by looking at preprocess functions, so I think they'll still be able to do powerful things if they'd like to do so.
I'd suggest tweaking the variable names to be a little more friendly. I agree that the css isn't needed: that's a bit confusing, as what these are is elements of class names. We don't want people getting confused and thinking that somehow some css is in the variable.
Here's my suggestion for the approach:
Preprocess
Template
It's entirely possible that I'm missing something, and that it isn't okay to have a variable key within $variables that has the same name as a key within $elements. If not, though, I think this is pretty clear.
Overall, this is a great idea. I'd be very happy to across this template when working on a theme, as it would make it super easy to delete all those awful class names as quickly as possible. :)
Comment #49
mortendk CreditAttribution: mortendk commenteda reroll and back to simpler times
theme.inc:
Comment #50
mortendk CreditAttribution: mortendk commentednew patch removed entity view stuff ;)
Comment #52
aboros CreditAttribution: aboros commentedmissing space after field_name and field_type.
Comment #53
aboros CreditAttribution: aboros commentedThis is just putting spaces where they were missing from.
Comment #54
emma.mariaComment #55
joshua.boltz CreditAttribution: joshua.boltz commentedWhen I apply this patch, the markup is slightly different that the before-patch markup.
1. class .field-label-hidden is no longer showing in the string of classes on the main wrapper div.field.
2. There may be some minor whitespace-type cleanup to do (2 whitespaces, instead of just one)
Hope that helps.
Comment #57
aczietlow CreditAttribution: aczietlow commentedComment #58
aczietlow CreditAttribution: aczietlow commentedI'm going to take an attempt at this.
Comment #59
aczietlow CreditAttribution: aczietlow commentedFixed trailing white space in twig file for simpletest.
Comment #60
LewisNymanComment #61
LewisNymanGood news, I tested it manually and the markup is identical. I would like to mark this RTBC but we still need to document these new variables in the template.
Comment #62
aczietlow CreditAttribution: aczietlow commentedComment #63
aczietlow CreditAttribution: aczietlow commentedHow's this? Added an interdiff to make it easy to review.
Comment #64
dcam CreditAttribution: dcam commentedGo, Testbot!
Comment #65
sarahjean CreditAttribution: sarahjean commentedTested this manually, the markup and the documentation of the variables in the file comment both look good.
Comment #66
yched CreditAttribution: yched commentedSorry for kicking this back, but :
That's not true, strtr($field_name, '_', '-') is not "the field name".
If we put the "CSS friendly strings with _ replaced by -" in the $variables available in the template, we have to give them non-misleading names, and we shouldn't lie in their description in the template doc :-)
Comment #67
jstollerAny problem with this?
Comment #68
aczietlow CreditAttribution: aczietlow commentedI'm not a fan of prepending the variables with 'css_'. I can't see many cases where you would need the variable name with the '-' and the css friendly variable name with the '_' in the twig file. I think we should leave the variable names as is.
I do like the proposed descriptions though.
Can someone else confirm this?
Comment #69
yched CreditAttribution: yched commentedJust using $entity_type, $field_name ... as var names would still be lying. +1 on #67
Comment #70
jstollerI'm not actually sold on the clarification in the variable name being necessary, but it doesn't bother me either way. I would just hate to see this issue held up by a minor semantic issue.
Comment #71
Ec1ipsis CreditAttribution: Ec1ipsis commentedPersonally I think that the variables would be better named without the prefix. The prefix doesn't really add any clarification in this context (there isn't an unfriendly version here to get it confused with), and detailed documentation is immediately above their usage. As a very minor point, keeping variable names concise and unique is a win for being able to quickly read over the template file and knowing precisely what is going on.
Comment #72
yched CreditAttribution: yched commentedSorry, I still disagree. If we start applying the pattern of "print classes directly in templates" to other templates than field.html.twig, then naming the CSS-friendly variants of "things" the same name as the "thing" would end up very confusing.
We prepare
$variables['some_var'] = strtr($element['#field_name'], '_', '-');
only because $some_var is specifically intended to end up in a "class" attributes. It's not "the field name" as a generic-purpose string, and it's not "the field name" as the rest of the code flow uses it. It's "the field name specifically massaged to be usable as a CSS class". Accuracy of non-misleading var names wins over saving 4 chars in a var name.Comment #73
Ec1ipsis CreditAttribution: Ec1ipsis commentedI think you make a good point regarding consistency in other areas. Consistency is good for sanity, and sanity is good for programmers. Point conceded, I think your suggested naming is the correct path forward.
Comment #74
aczietlow CreditAttribution: aczietlow commentedI see your point. I will re-roll the patch with the suggested changes in #67. Thanks for the feedback.
Comment #75
yched CreditAttribution: yched commentedWell, also, #2004252: node.html.twig template just went in, which did this to node.html.twig :
http://cgit.drupalcode.org/drupal/diff/core/modules/node/templates/node....
So do we really want to go in the opposite direction here ? What's the global strategy regarding classes in templates ?
Comment #76
joelpittetThere is definately some merit to this idea.
Though for consistency sake, clean templates I'm not on board.
There is a lot more power and control in the preprocess to generate these classes and attributes. Also rdf and many contrib modules rely on manipulating them. As well
One key idea in twig is you aren't really supposed to create data , rather get data in and format it's output..
This brings to light two things to me, the attributes API Needs some more helpers methods to make it easier to manipulate the data. And to a lesser extent it seems also that empty attributes is not a real concern for classes.
@webchick mentioned in passing maybe we should always treat classes as the special flower they are and by looking at this approach you've all taken maybe she is right.
Comment #77
jstollerThere was a big meeting of frontenders at DrupalCon and we hashed out a plan for dealing with classes and CSS in Core. There's a picture somewhere of mortondk and JohnAlbin shaking over the plan—it was all very official—and there was supposed to be a meta issue going up here to explain it all, but it looks like that may not have happened yet.
In any case, phase 1 of the plan was to move all the default classes for all the core modules out of preprocess functions and into their respective twig templates. However, we also noted that in doing this we still need to support the classes variable, so we don't break things like RDF. There was widespread consensus that this alone would be a good thing for themers. This step is also required for the rest of the plan to work, but I'm not sure here is the best place to get into that meta issue.
Comment #78
mortendk CreditAttribution: mortendk commentedThe meta issue wil be up in a couple of days (hopefully in about 24 hours)
But yes first thing is to make sure that we move classnames out of the preprocess, where we don't have any control over them (unless we use regex) and move them into the template files instead.
Theres no reason to not have classnames inside the templates besides of "we used to have them in the preprocess".
It gives us flexibility & makes it very easy for us to build new frontend architecture where mistakes we do now, like fx using a bem naming scheme, that probably will be outdated in 18 months, is very easy to correct.
Modules will still have the power to add in whatever class the need as we keeps the {{ attributes.class }} so to me this is a no brainer & will make sure that we dont lock us self down in mistakes we think are good now (like fx having 960 grid in core, or bootstrap or whatever is the hot thing today)
Honestly this is the only way we can make the frontend flexible + this have been discussed for 5 years now, everybody have been heard.
Unless somebody can show a usecase where moving classnames into the template isnt a good idea, i really think we need to move forward and get it done.
I we dont, we can just as well drop twig and just go for headless drupal.
Comment #79
LewisNymanOne of the points that really hit home with me with the "classy" theme implementation was that if we ever want to completely change the mark up in Drupal core again we won't have to change all the module template files. We just create a new theme. That's mind blowing.
What's going on with this meta? I feel kind of anxious that, after we had over 20 frontend devs holding a big thumbs up over an openly discussed and developed plan, there's more discussion going on behind closed doors.
Comment #80
aczietlow CreditAttribution: aczietlow commentedAdding the last agreed upon changes to the patch, and marking it for testing. Though I feel this is blocked until meta issue mentioned in #78 gets posted.
Comment #81
mortendk CreditAttribution: mortendk commentedno talk behind closed doors - john is taking the lead on it & he had to fly home , and sleep first then it gets out :)
Comment #82
LewisNymanComment #83
andypostRelated, comment field rendered differently #1962846-32: Use field instance name for header of comment list, drop comment-wrapper template
Comment #84
jwilson3This probably wont be a popular observation, but I wonder what does the "css_" prefix add to themers experience? The original variables (the ones with the underscores) aren't accessible in the twig file and for all intents and purposes aren't very useful to themers, so what's the use to distinguish this in the variable name? Yes, the "css_" prefix is used to signify that we've converted underscores to hyphens, but this is already made clear in the description in the comment section of the template. Seems important to discuss this now, because this could set the precedent for use in other to-be-created issues for migrating classes into templates.
Comment #85
yched CreditAttribution: yched commented@jwilson3: see #72.
Comment #86
jwilson3What if we add a twig filter a la
{{ entity_type|c }}
, that could turn underscores into hyphens on the backend. Twig engine could replace c with a call to drupal_html_class. We could even progressively add support to the "c" filter to handle objects and arrays automatically using _toString() or similar.I know I've had needs where I want to turn a string value into a class name in the past. Would be uber-cool to have a shortcut to do this in the template itself.
Comment #87
RainbowArrayJust wanted to note that the way we're going to be adding classes to templates is being worked on in #2285451: Create addClass() and removeClass() methods on Attribute object for merging css class names..
Comment #88
star-szr@jwilson3 see #2283301: Add Twig filters for drupal_html_class() and drupal_clean_id_identifier() for that functionality.
Comment #89
jwilson3@cottser Awesome! So if that patch were to get in, would there be any reason to NOT move the "css_" prefix stuff in this patch out of preprocess into the template?
Comment #90
star-szrThe hash keys (#) are kinda yucky because you can't use Twig's dot syntax to access them.
Comment #91
davidhernandezComment #92
aczietlow CreditAttribution: aczietlow commentedWith the meta issue #2322163 now posted I think I see a path forward with this.
Comment #94
aczietlow CreditAttribution: aczietlow commentedComment #95
Ec1ipsis CreditAttribution: Ec1ipsis commentedFunctionally tested patch #94 and passed.
Comment #96
joelpittetLooking good, here's my review. Thanks for the patch @aczietlow
You can leave this at the top.
These variables shouldn't be indented. Seem to have one space infront.
Don't think #label_display needs |clean_class as it didn't before.
clean_class doesn't map to strtr() either so make sure the output is as expected with _ converted to -.
No space needed in front of the twig print statement. And don't need to add attributes.class because it already is there and it's just going to merge classes.
This is a good change because there doesn't need that if statement, thank you. Though you should just use addClass() here too.
Comment #99
seantwalshUpdated this per @joelpittet comments in 96 and the Google doc from the meta. Also updated the issue summary to include the preprocess functions and twig templates modified.
Comment #100
seantwalshTest please!!!
Comment #101
joelpittetThanks @crowdcg those I think are almost perfect accept my first comment below of the missing.
Needs a comma after the label_display, will likely fail.
Thank god for this cleanup! All those if statements are to remove the space! Completely unnecessary a ternary would have done nicely even.
Comment #103
seantwalsh@joelpittet thanks for seeing that. Added the missing comma.
Comment #105
davidhernandezThe test failed because of the whitespace introduced between the array and the markup. I'm uploading a patch with it removed to verify. Also, there were a few other spots with classes to convert.
Comment #106
joelpittetNice sleuthing. I've no problems with this patch. It looks like a very nice cleanup/improvement. And gives a strong example for the rest of the banana movement.
All good things:
Good catch! That will fix a bug if item attributes are added they'd get duplicate class attribute. Without|without:)
Love it!
Awesome!
Comment #107
RainbowArrayThis is very nice. Great work.
Comment #108
davidhernandezCottser, mdrummond and I talked about this in IRC. If everyone likes the patch this one can get committed straight away, to at least serve as a good example for changing the other preprocess functions.
Comment #109
dead_armI read through this issue and it seems like a good thing but I think there should be a change notice and succinct documentation for people to read before it goes in.
Comment #110
davidhernandezWhat would the documentation be on?
Comment #111
tim.plunkettSame as any change notice.
"This is how things were done in D7"
"This is how we do things now in D8"
Also helpful links to twig basics, like what the
~
does.Most importantly, it lets people who follow the change notice twitter account know that there is something new to learn.
Comment #112
RainbowArrayThere are going to be a couple dozen similar issues to this one, so I guess the question if we want a change notice for each one. That could make the change notices account a bit noisy. I agree that it's good to explain this new approach, just not sure if a change notice for each of these template changes would make sense.
Comment #113
tim.plunkettWell, isn't this first one? I wasn't implying this would be done for EVERY template. Just one for the new approach of doing things for templates in general.
Comment #114
davidhernandezYeah, definitely do not want to have to create a change record for every one of these changes. I was assuming we'd just make a change record to go along with the meta issue, but this is going in first, so I guess one here makes sense. I'll make one, unless someone would like to beat me to it.
Comment #115
RainbowArraySounds good if you want to write that up David.
Comment #116
davidhernandezI started drafting a change record. In the process I discovered there are couple more class changes needed.
https://www.drupal.org/node/2325067
Comment #117
seantwalshOk apparently, there are a number of things to fix in this still after a recent IRC conversation. Working on a patch now.
Comment #118
star-szrNice work on this one folks!
If we only want to do one change record for this entire shift, I don't think it should talk about field classes in the title. Something more like "Most CSS classes moved from preprocess to Twig templates" would be a more accurate description except it's not yet true. Or maybe something like "Default CSS classes will be defined in Twig templates instead of preprocess"? Either way I guess we can make it future tense and then edit the change record after we are "done".
I think @tim.plunkett is talking about https://twitter.com/drupal8changes by the way, and I think it's helpful to think of the title of the change record as something that can be made sense of on its own.
In addition to @tim.plunkett's note about linking to Twig's concatenation documentation, the change record should also link to the addClass/removeClass change record to explain that part.
Comment #119
davidhernandezI fleshed out the change record, removed Field form the title, and made the title more present tense.
https://www.drupal.org/node/2325067
Comment #120
davidhernandezAlso, added links to documentation and previous issues.
Comment #121
star-szrLooks really good, thank you so much @davidhernandez! My only nitpick is that the CR title shouldn't end in a period.
Comment #122
jwilson3Removed period.
Comment #123
joelpittet@crowdcg is on some changes still. We missed a couple class attributes in the preprocess_field for title_attributes and content_attributes. I'll do more thorough pass over the preprocess's related to this to see once he's got that patch in here.
Removed tag for needs change record.
@tim.plunkett and @dead_arm want to give the change record a boo to see if it seems it will do the trick?
https://www.drupal.org/node/2325067
Comment #124
seantwalshJust when you think your done...
Did a bunch of clean up and think I got everything. However, I'm getting a trailing whitespace when doing logic. Not sure how to get rid of it, or not get it there in the first place. Please see example below.
field.twig.html
Output
Comment #126
jwilson3I think this syntax would be better in the form:
Why? Because if you want to remove all the classes, all you have to do is copy the template to your theme and delete everything between the
{% %}
. The way it's coded now you'd have to do that plus also remove the.addClass(classes)
to have clean and logical code.Comment #127
joelpittet@jwilson3's idea sounds good, maybe you guys can discuss that a bit on IRC?
This check is not needed, bartik preprocess did that because there are no suggestions for preprocess functions.
None of these label_display need the clean_class filter because they weren't using them before. I'd avoid making that change in this patch.
You can use whitespace modifiers to remove the space.
{%
becomes{%-
to remove the whitespace before. @see http://twig.sensiolabs.org/doc/templates.html#whitespace-controlComment #128
seantwalsh@jwilson3 I can totally see the benefit of that, great idea!
@joelpittet
1. Thanks, so just changing that to add the 'field-label' since we're already in the taxonomy term reference.
2. Fair enough, just seemed inconsistent in the use of - over _ in the classes. Currently in D8 the attributes div displays the class as field-label-visually_hidden and in the title_attributes div displays as the class visually-hidden.
3. Awesome, will add those where needed. @davidhernandez also probably need to explain this in and update the change record.
I will have time to post an updated patch this afternoon, unless someone is feeling eager and wants to beat me to it!
Comment #129
davidhernandez@crowdcg, regarding 2, just make sure the class names come out the same as they were previously. We aren't changing any CSS or JS, so if something is already expecting it with the underscore we can leave it for now. Let me know if you need help with the whitespace. It looks like that is the only reason the tests failed.
If the whitespace is caused by the ternary IF in the array, that means an empty array element is being added when it evaluates to false and that results in a blank space?. Is there any way to stop that? @joelpittet, I think the whitespace problem may also go back to when addClass was added, and the array_filter was removed. I am concerned that if there is an IF in the middle, or beginning, of the array, will an extra blank space show up there as well? I'll try to test that.
Regarding #126 I don't quite agree with the reasoning that it would make things easier for people; however, it does get rid of a variable, which I am totally onboard with.
Comment #130
seantwalshChanges incorporated from 126-129.
Comment #131
seantwalshAlways forget to change status...
Comment #133
joelpittet@crowdcg I agree we should be using the clean_class a bit more consistently. But not in this issue, it becomes scope creep and the I'd rather the bare necessities now and the cleanup in a quick follow up issue that can bikeshed or deal with the test failures, etc.
Comment #134
davidhernandezWe may need to axe #126 unless we're doing something wrong or missing some other operator. It doesn't seem you can manipulate a variable separate from printing it. I could only get the following to work:
Not sure we would want to do that over just using the 'class' variable.
Also, this whitespace problem isn't going away. The modifiers are being applied to the whole attribute, not specifically to just the output of the class attribute. I think we need an array_filter in addClass or somewhere to remove the empty array elements. Unless there is a way to stop the array from adding empty elements for ones that evaluate false.
Here is a dump of the title_attribute:
Comment #135
seantwalshOk, undoing the suggested change per @jwilson3, sorry but as @davidhernandez shows above, this seems too messy.
Also, added trailing commas in arrays for @cottser, and cleaned up inaccurate comments.
Lastly, in order to get rid of the trailing spaces we really need adding-arrayfilter.patch to get in, which was pulled out before #2285451 was committed. After many attempts, we were still unsuccessful in getting rid of the extra space. This issue clearly shows the reason we need this added.
Comment #137
seantwalshJust ran the 2 failing tests locally after applying adding-arrayfilter.patch and they pass.
Comment #138
star-szrOh awesome, I'm really happy the trailing commas work, thank you @crowdcg! I know we did an upstream Doctrine patch earlier in the cycle to fix that with annotations and make those work with trailing commas.
Do the trailing commas work with the syntax proposed in #126 as well? I guess it should but I'm curious if this would work (passing multiple arguments rather than passing an array as the first argument):
Comment #139
star-szrOh I missed the part where it wouldn't work, I had suspicions about that. So nevermind :)
Comment #140
star-szrI think we need a separate issue for adding-arrayfilter.patch please. Then we can add tests and get it RTBC and committed.
Comment #141
davidhernandezAdded another issues #2326397: Add filtering to AttributeArray
Comment #142
davidhernandezThe filter is in.
#2326397: Add filtering to AttributeArray
Comment #144
star-szrComment #145
davidhernandezfield--node--title.html.twig needs the visually-hidden logic, which it normally inherits from template_preprocess_field. It is also missing the inline label logic, but I can't think of why it would need it. You can't make the comment label inline. Everything else looks good.
Comment #146
davidhernandezSorry, I meant field--comment.html.twig, not node title.
Comment #147
seantwalshUpdated per @davidhernandez's comments.
Comment #148
davidhernandezOk, anything else we can find wrong? If not, I'm inclined to RTBC.
Comment #149
RainbowArrayThis is looking good to me.
Maybe we should do some manual testing to make sure we're getting the source code output?
Comment #150
star-szrComment #151
mortendk CreditAttribution: mortendk commentedgonna get some bodys on this from copenhagen :)
Comment #152
rteijeiro CreditAttribution: rteijeiro commentedIt seems official tag is FUDK (kinda weird, BTW)
Comment #153
lauriiiComment #154
rteijeiro CreditAttribution: rteijeiro commentedShould we take the proposed solution to review this patch?
It seems that these are not the classes included in the patch:
"field-{{ name }} field-type-{{ fieldtype }} .field-label-{{ label-position }} {{ attributes.class }}"
Comment #155
davidhernandezNo, the issue summary needs changing. You may not want to tackle this one at front end united, as this issue has a rather long history to it.
Comment #156
jwilson3So what is needed is issue summary update per #155, and manual testing per #149.
Comment #157
davidhernandezComment #158
davidhernandezI manually checked the markup for this in Bartik and Stark with a term reference, text field, and comments, pre and post patch. The only thing I noticed is in Bartik's field--taxonomy-term-refernce.html.twig. The clearfix class is applied always, not just when label_display = inline.
Pre:
<div class="{{ attributes.class }} clearfix"{{ attributes|without('class') }}>
Post:
label_display == 'inline' ? 'clearfix'
It is not an inconsequential difference. There is a noticeable spacing difference.
Comment #159
davidhernandezAlso, this can be removed from the comment block in field--taxonomy-term-refernce.html.twig, since the function was removed completely.
* @see bartik_preprocess_field()
Comment #160
davidhernandezComment #161
star-szrI'm wondering whether we should just keep and use these _css variables to "save some overhead" instead of using
|clean_class
, because there can indeed by many fields rendered on a page.Comment #162
davidhernandezRE: #161, if we do that, we hard code them. If someone doesn't want them, and removes them from the template, they still get generated. And when we move these out of the core template, and into the Classy template, they would still be there even though the core/Stark themes don't use them.
Comment #163
RainbowArrayI think what Cottser is saying, and correct me if I'm wrong, is that we do the cleanup of the variable in preprocess, but still send it to the template to get added with addClass. I guess it is more efficient to do the cleanup in preprocess than in the template with
clean_class
?Comment #164
star-szrIt should be more efficient from a performance perspective because
strtr()
is doing a lot less things thandrupal_clean_css_identifier()
- which is doing a more complexstrtr()
and twopreg_replace()
.@davidhernandez is the concern over the variables being irrelevant to the core templates in phase 2? If so we could consider moving the variable setup to a classy preprocess function.
So I'm basically proposing this:
Instead of:
Having said that, it's probably worth doing some actual profiling before making this decision. I can take care of that soon.
Comment #165
star-szrAnd also I'm not proposing we do this for all templates, but field can really be used a lot so it may need some additional optimization.
Comment #166
davidhernandezYes, that is the approach I was first thinking of in the node issue, to avoid the isSticky stuff by adding it as a variable. But, as you noted, after phase 2, these variables would be of no use to core. Unless you think it is worth having them there just in case someone might want to use them, but I don't think we do that with anything else, do we?
I could see doing it in the Classy preprocess to optimize it. They will definitely be used there, though I could argue the same problem. If someone doesn't want them, they are still being generated.
Comment #167
andypostOnce field classes are involved, let's get more eyes on #2229355: Field template suggestions are colliding
Comment #168
yched CreditAttribution: yched commentedSome profiling would be nice here, yes. IIRC we replaced drupal_html_class() with strtr() here in D7 because there was a non-negligible performance impact - see #652246: Optimize theme('field') and use it for comment body, where this was done.
Maybe things are different in D8, but let's make sure before reverting that.
Comment #169
star-szrComment #170
davidhernandezI gave the profiling a shot. These are my results using the patch in #160 and then modifying it to use the variable class names in preprocess, as HEAD is currently doing. This is on my MacBook Pro with MAMP and PHP 5.4.26.
8.0.x
8.0.x versus the patch in 160
8.0.x versus the patch in 160 with _css variables in preprocess
I kept getting APC warning messages. I don't know if there is something wrong with my setup, so I disabled APC and ran it again.
8.0.x
8.0.x versus the patch in 160
8.0.x versus the patch in 160 with _css variables in preprocess
I'll try to profile php 5.5 as well, but I need to compile a binary for it first.
Comment #171
davidhernandezI forgot to explain the page. I added every type of field to my content type and multiple values for ones that allow. So this is rendering about 20 fields with over 70 items.
Comment #172
yched CreditAttribution: yched commented@davidhernandez: Thanks ! 20 fields is not enough though IMO.
The most critical case are listing pages. So we should try a view with a simple query, displaying 20 node teasers, each teaser displaying 5 fields - that's realistic use case ?
(Using a custom page callback that displays 20 node teasers rather than a view would actually allow a more accurate comparison, by not diluting the perf cost into the general Views overhead, actually)
Comment #173
yched CreditAttribution: yched commentedNot sure whether devel_generate currently works on HEAD, but #2320157: Generate placeholder content for Field types would help generating the nodes.
No need to go with various field types, simple number fields would be enough.
Also, we don't want to measure the case of render cache hits, of course :-)
Comment #174
davidhernandezOk, I tried this again. A created a content type with five fields and generated 100 nodes. I then created a custom page displaying teasers for all 100 nodes. Including the node title, that should be 600 field items rendered.
8.0.x
8.0.x versus the patch in #160
8.0.x versus #160 with the _css variables
I then compared the branches against each other just to double-check.
_css vars
_css vars versus the patch in #160 with no changes
Comment #175
yched CreditAttribution: yched commentedThanks @davidhernandez!
So yeah, 3% is not really minor... and it's 3% of [more than in D7] too...
I'm not too familiar with that area and cannot really evaluate the approaches that would let us keep strtr() here.
Worst case, if it's really not doable or has too ugly consequences, we can always consider that it's below the entity render cache and will only be an overhead on cache misses, but of course it's best to keep the performance of cache misses in mind too...
Comment #176
davidhernandezThe 3% seems to mostly come from moving things to the template, and I assume all the added addClass() calls. What we're really looking at is the difference between using strtr() in the preprocess function with variables passed to the template versus using the clean_class filter in the Twig template. (What Cottser mentioned in #161) That is seen in the last group I posted ("_css vars versus the patch in #160 with no changes",) which has been showing a 0.1-0.3% difference. (I probably included more data than I needed to and made it confusing.)
The other possible mitigating factor, if we get all the "Classy" theme changes in, is this will move out of the core template and into the "Classy" theme. The performance hit should only be seen there. Core should actually become slightly faster, shouldn't it? Since all the preprocess and template css code will be gone.
Comment #177
joelpittet@yched and @davidhernandez FYI the twig filter |replace() maps directly to strtr, so that should be much faster(guessing...).
http://twig.sensiolabs.org/doc/filters/replace.html
@davidhernandez any chance you could get a ubench key from from @Fabianx or @Cottser and post your xhprof results to Fabian's server? That would help see bulk and we can inspect it a bit further?
We have some documentation on that here @see https://drupal.org/contributor-tasks/profiling
Comment #178
davidhernandezThinking about this a little more today. If we keep the strtr() (
$variables['entity_type_css'] = strtr($element['#entity_type'], '_', '-');
) we have to do it in preprocess. Option 1 is to move that code to the Classy theme when the template moves. In general, I'm opposed to adding functions to Classy. But, this will also leave us with the scenario where the template in Classy is dependent on code that lives there. If someone were to copy the template from Classy, which we likely encourage, but doesn't use Classy as their base, that template will break. They'll have to copy the preprocess code with it to maintain functionality.Option 2 is to keep the preprocess code in the field module (core.) The template moved to Classy will receive those variables, and anyone that uses that same template will also receive those variables. However, these variables will not be used by the core template, and the (not insignificantly expensive) processing will still happen. That doesn't sound like a good idea either.
If we keep the clean_class method, the processing stays with the class assignment, the work is removed from core, nothing can break, and if any of those classes get removed, the work gets removed with it. If, ultimately, the difference is 0.1-0.4% difference based on my (I won't claim to be perfect) profiling, it seems reasonable to use the Twig filter.
Comment #179
RainbowArrayThat approach seems to make a lot of sense given the effects in those different situations.
Comment #181
karolus CreditAttribution: karolus commentedJust tested the patch at our local sprint. Everything checked out fine. Screen grabs are attached to show the results.
Comment #182
yched CreditAttribution: yched commentedSorry for not being able to follow more closely (afk, following with my phone...). Not clear to me what's the 3% perf impact that wat mentioned earlier. If that's an effect of the patch itself (rather than the clean_css / strtr thing), isn't that a bit worrying ?
Comment #183
star-szraddClass will have at least slightly better performance after #2336355: Refactor Attribute rendering so that class="" is not printed, which is good because in these templates it can be called up to 4 times.
Comment #184
davidhernandezYeah, what Cottser said. The big issue here is all the calls to addClass, not the difference between using strtr and clean_class. We are looking for ways to speed up addClass and I suppose to attribute printing, as well..
I had a conversation with Cottser about this on IRC yesterday, and he brought up using the Twig replace filter. People were using that earlier in this thread, before we ever had clean_class to use. I forgot all about that. If I have time this week I'll try it out and see if I can find any performance improvement over clean_class.
Comment #185
davidhernandez#2229435: Clean up the way attributes are printed in field.html.twig This will likely get in first, so we'll have to reroll if it does.
Comment #186
davidhernandez#2229435: Clean up the way attributes are printed in field.html.twig is in.
Comment #187
lauriiiRerolled
Comment #189
lauriiiSome variables were missing
Comment #191
lauriiiTestbot didnt like my variable inside html for some reason..
Comment #192
LewisNymanIn some template files we aren't added the classes variable to attributes.
Comment #193
lauriiiComment #194
LewisNymanPerfect. I diffed the output of the html and it looks good. Looks like this still needs some performance review
Comment #195
joelpittetFirst set of performance tests on #193
50 nodes on the homepage using teasers of articles with all the fields showing in their viewmode (comments block too).
http://www.lionsad.de/xhprof-kit/xhprof/xhprof_html/?run1=544333b05173f&...
http://www.lionsad.de/xhprof-kit/xhprof/xhprof_html/?run1=544333b05173f&...
~87ms slower which isn't all that great.
Comment #196
davidhernandezI ran some tests using 100 nodes, with 5 fields each plus titles. This setup is similar to what I originally did in #174.
Baseline
Compared to #193
I'm not completely sure why these are faster, other than the performance changes that were made to addClass() in a previous issue. A month has gone by, with many commits to core.
I was more interested in testing the difference between
clean_class
and usingreplace('_', '-')
, since that might be the only alternative within the template.Baseline for #193
Using replace filter
I ran these repeatedly, and replace was always slightly slower, though never hugely different.
I don't know how many performance gains can be found in how we handle these classes in the template, if any significant detriment is from addClass.
On the brightside, these will likely all be removed from the core module and put into Classy. Also, being in the template, if anyone has a performance concern, they can override the template and remove them. That is not something you can do if it were to stay in the preprocess function.
Comment #197
joelpittet@davidhernandez can you post your xhprof results, ask @Fabianx or maybe @Cottser for a key for uploading the bench marks. That way we can dig in and scout the bottle necks.
From the results I posted this is what I got for the bits:
drupal_html_class (|clean_class filter)
Excl. Wall Time (microsec)
before: 1,257
after: 3,805
diff: 2,548
percent diff: 202.7%
addClass()
Excl. Wall Time (microsec)
before: 7,048
after: 9,688
diff: 2,640
percent diff: 37.5%
Both of those are fairly negligible at a difference of 2.5ms.
I'm wondering where the rest of the 50-80ms is coming from?
Comment #198
davidhernandezI tried getting the remote posting of the results to work before, but couldn't get it to work. I'll have to try again.
I lost my last runs after rebooting, but ran it a few more times. This is what I'm seeing when sorted by the function call diff. (sorry for the crappy formatting.)
function|calls diff|call diff %|incl. wall diff|incl. wall diff %|excl. wall diff|excl. wall diff %
drupal_html_class|3,200|33.0%|11,686|25.4%|7,513|16.4%
getClass|3,200|33.0%|4,192|9.1%|3,303|7.2%
strtr|-2,388|-24.7%|-2,319|-5.0%|-2,319|-5.0%
function_exists|-800|-8.3%|-834|-1.8%|-834|-1.8%
call_user_func_array@1|800|8.3%|22,497|49.0%|3,309|7.2%
getAttribute|800|8.3%|38,755|84.4%|12,800|27.9%
func_get_args|800|8.3%|1,210|2.6%|1,210|2.6%
bartik_preprocess_field|-800|-8.3%|-801|-1.7%|-801|-1.7%
addClass|800|8.3%|19,799|43.1%|8,308|18.1%
is_object|800|8.3%|-630|-1.4%|-630|-1.4%
get_class|800|8.3%|481|1.0%|481|1.0%
strtolower|800|8.3%|889|1.9%|889|1.9%
array_merge|800|8.3%|1,723|3.8%|1,723|3.8%
hasExtension|800|8.3%|796|1.7%|796|1.7%
These seem to be the biggest differences in call count and time.
The only other thing I see with majorly different numbers each time is load::service_container. Changing by 10ms an each run. Is that even something to be controlled? Is it introducing too much randomness into the tests?
I sorted the results by Excl. Wall Time and made a screenshot (required some editing to remove the crud.)
Comment #199
lauriiiComment #200
lauriiiRerolled
Comment #201
lauriiiAdded missing docblock
Comment #202
RainbowArrayTried to look back at the discussion to see the forest for the trees. Given the xhprof testing, would it be reasonable to say that we'd be okay with going with the clean_class filter in the template rather than cleaning things up in preprocess? clean_class seems like the most stable option since it doesn't rely upon the existence of a preprocess function, which would be useless if kept in core, and which might be somehow missed if Classy doesn't get properly set as a base theme. Do I have that right?
Comment #203
davidhernandez@mdrummond, can you clarify what you mean by:
Do you mean if the classes in preprocess were moved to a preprocess function in Classy? If so, yes, I would be concerned about someone copying the field template from Classy, but not using Classy as a base. This would break the template. We would also repeat the same problem of things happening in preprocess, just localizing the problem to Classy.
Comment #204
rteijeiro CreditAttribution: rteijeiro commentedComment #205
rteijeiro CreditAttribution: rteijeiro commentedIt looks good for me. Let me know if you need screenshots.
Comment #206
alexpottMissing label_display
Comment #207
davidhernandezI updated the label_display comment in all the templates.
Comment #208
lauriiiOnly reviewed the change and it looks good. Gonna RTBC because of #205
Comment #209
alexpottThe performance concerns feel a bit glossed over. Reading all the profiling in the comments it looks like this patch introduces a 3% regression - is that the case?
Comment #210
davidhernandezThe last test Joel did looks to be about 2.1% and the last one I did was about 1.2%; obviously different tests. I'd have to do a much larger test (a lot more loops) to get a more accurate test. The regression would carry over to Classy, but removed from the core field module once we, hopefully, get the classes removed.
Comment #211
alexpottCalling this twice on the same string feels wasteful. How about an additional set so we don't have too.
Also this issue is a normal task so we need to outline how it fits within the allowable Drupal 8 beta criteria. Can someone add Drupal 8 beta phase evaluation template to the issue summary. Obviously as part of the banana consensus it can go in but it's nice to have the justification in a standard way on every issue.
Comment #212
seantwalshUpdated patch with additional set, so clean_class doesn't run twice on field_name. Also, took a stab at the issue summary per #211. @davidhernandez feel free to revise. Once we have it for this we should add it to any others that are outstanding.
Comment #213
seantwalshForgot to send the patch for testing...
Comment #214
seantwalshPer a conversation on IRC with @davidhernandez I've changed field_name = field_name|clean_class to field_name_class = field_name|clean_class as to not cause issues with using field_name elsewhere in templates.
Comment #217
davidhernandezI think it is this commit that changed things. #2358529: Right-aligned images in CKEditor appear to the right of other fields Some extra field templates were introduced and the test that is failing is checking for exact markup. The difference being an added clearfix on body text.
Comment #218
lauriiiTest failed because of the class sort has changed.
Comment #219
lauriiiComment #220
davidhernandezProfiling the patch in #218
My setup was 100 nodes with a title, body field and four integer fields. That should be six fields per node, giving 600 total on the page.
http://www.lionsad.de/xhprof-kit/xhprof/xhprof_html/?run1=54811b6aec43d&...
http://www.lionsad.de/xhprof-kit/xhprof/xhprof_html/?run1=54811b6aec43d&...
Comment #221
davidhernandez#218 has the changes requested in #211
Comment #223
davidhernandezComment #224
seantwalshRolling, rolling, rolling, field patch is rerolling...
Comment #225
LewisNymanA quick manual test shows all is well
Comment #226
alexpottCommitted a081397 and pushed to 8.0.x. Thanks!
Thanks for adding the beta evaluation for to the issue summary.
Comment #228
davidhernandez*falls to knees and weeps*
It's a Christmas miracle!
Comment #229
mortendk CreditAttribution: mortendk commentedit only took 9 months
Comment #230
Jeff Burnz CreditAttribution: Jeff Burnz commentedIndeed, its a christmas miracle, I am celebrating, well done guys, hats off and merry christmas.