Problem/Motivation
The __value tokens in views don't work for adding classes to fields or rows.
Steps to reproduce
- Install Drupal
- Add a text/select field to the basic page content type with some values
- Add some basic page nodes with values selected
- Create a view of basic pages
- In the formatting settings, try to add the field value as a class using replacement tokens:
- See that the default token works, but the __value token for the raw value does not output anything:

Proposed resolution
Either fix the issue so the raw value can be used, or update the text to indicate the are not supported.
Remaining tasks
- Confirm approach
- MR with fix or text change
- Review
- Commit
Original report
If I want to create a class for a field or row or etc. using replacement patterns raw values it won't work. It will just replace if I don't use the raw value.

Example:
- if I enter state-[field_state] it works fine (returning state-In work which anyway isn't css compliant)
- if I enter state-[field_state-value] it just returns state--field_state-value when it should return state-1(or whatever the raw value is)
Shouldn't it work with raw values also? If I use them in "Rewrite results" the raw values are displayed correctly.
A little backtracking on this bug brought me to function tokenize_value($value, $row_index = NULL) in views_handler_field.inc.php. I think this is the function that should replace the token with it's proper value but it doesn't do that. But from there on I'm lost :).
| Comment | File | Size | Author |
|---|---|---|---|
| #103 | Screenshot 2024-09-09 at 10.35.47 am.png | 6.15 KB | pameeela |
| #103 | Screenshot 2024-09-09 at 10.39.20 am.png | 54.21 KB | pameeela |
| #69 | 1262630-69.patch | 6.97 KB | lendude |
| #69 | interdiff-1262630-68-69.txt | 1.9 KB | lendude |
| #68 | 1262630-68.patch | 7.06 KB | lendude |
Issue fork drupal-1262630
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #1
dawehnerMh there are more major bugs around.
There was another issue around some days ago where as far as i remember earl said that this is by design, sadly i can't find it at the moment.
Comment #2
Alex Savin commentedIf it's by design than I think it's a good idea to highlight it in the description of that field. Now that field's description is:
Comment #3
irwin nerwin commentedIn the Issue Summary, asavin noted:
"if I enter
state-[field_state]it works fine (returningstate-In workwhich anyway isn't css compliant)"It sure isn't! If I enter
myprefix-[field_vocabularymachinename]and two multi-word terms in that vocabulary are, for example, The State of Things and The End of the World then for both of them I get the row classmyprefix-The(as well as the unwanted and not-prefixed classesState,of, andThings, or,End,of,the, andWorld).The row class token may need to be run through drupal_clean_css_identifier (at least that's a function I saw used elsewhere. Whether or not to use strtolower may be a matter of preference, but I'd prefer it. (If I seem to have any clue what I'm talking about, it's sheerly by chance. I am a rube noob in Drupal programming.)
I also have noted the problem asavin was mainly noting: If I used myprefix-[field_vocabularymachinename-tid], I get the class myprefix--field-vocabularymachinename-tid. Would have been the work-around if it had worked right.
Although I also recall seeing it said somewhere, as dereine mentioned, I really don't think either of these can be "by design." Or shouldn't be, anywhoo. I note that, with vocabulary fields, with more than one term on a node, Views would have to loop through all the terms in the node to generate prefix-termfirst, prefix-termsecond, and so on.
Using D7.7, Views 7.x-3.0-rc1, Zen 7.x-3.1 sub-theme.
(My prolix attempt to elaborate on this in another now-closed issue thread last April here, where I also wish for taxonomy sub-fields to be available in Views, such as the built-in description or an added field.)
Comment #4
merlinofchaos commentedWhen doing CSS replacements, the tokens are supposed to be run through filtering to replace spaces with dashes and stuff. Did something happen to that? I noticed it earlier that the token wasn't turning into a class properly.
Comment #5
dawehnerHopefully i understand it now better. There are two layers of css classes
Currently both this levels uses only the actual rendered fields as tokens, not the sub-tokens, called self-tokens.
Self-tokens are used to rewrite the output of a field. One important thing you have to have in mind is that they are designed to work with multi-value-fields, so if you rewrite the text of a field, the self-tokens are applied to the current value of the field.
One example are image descriptions.
You can use this self-tokens in the css classes with some kind of hacky way: rewrite the output of a field, and use this field as a token for another field. But we agreed that there should be somehow a way to use them at field-level css classes.
it seems to be, that you just vent, if yes please ignore the following parts. You have self-tokens already, why do you need sub-fields? Additional you could write a custom formatter which does everything what you want. Sub-fields seems not really to make sense as there are already two ways to achieve this goal.
Comment #6
irwin nerwin commentedmerlinofchaos: "tokens are supposed to be run through filtering to replace spaces with dashes and stuff. Did something happen to that?"
Yes, apparently, something did happen to that, because it was working and I was actively styling on it, then one day my styles disappeared because it wasn't working. I'm not sure what (Views? Tokens? Core?), and I'm not sure when. Sometime before April. We started with D7 in January, and doing lots of upgrades & changes (of course) when I first noticed that row classes weren't being filtered anymore, e.g. "myprefix-this-is-my-class" had become "myprefix-This Is My Class".
I don't know if the tid non-replacement arose simultaneously, because I didn't try that option until looking for a styling alternative after the row class filtering stopped working.
Comment #7
irwin nerwin commentedI wrote: I also wish for taxonomy sub-fields to be available in Views, such as the built-in description or an added field.
dereine: it seems to be, that you just vent, if yes please ignore the following parts. You have self-tokens already, why do you need sub-fields?
I was perhaps confusing, inappropriately mentioning in this thread what is really a separate suggestion. I do not seek to use those sub-fields as css, but as fields displayed in a Views row. I'm just looking to be able to display available data in Views, which of course is what Views is all about. Currently, one can add a single vocabulary's terms with
add field | Content: MyVocabNamebut a term's sub-fields are not available (or I'm missing something, always a possibility). Don't know what that would look like —Content: MyVocabName DescriptionorContent: MyVocabName SubFieldName? — nor how hard such a thing would be to implement. I have a one-term-per-page vocabulary with which I'd like to use the sub-fields, but I can see with mutiple terms per page it could be very tricky. But, as I say, a separate issue from this thread.Comment #8
dawehnerBeside the fact that it's another issue, i provided you already a solution: custom formatters.
Comment #9
anruetherJust wondering if you are going to resolve this in Views or if we will have to think about other solutions like custom formatters ? Anyway it would be nice if tokens would be filtered if they are supposed to work as css class.
Comment #10
mathieuhelie commentedSubscribe
Comment #11
kansaj commentedthe work around will be to use actually another filed value with the value self as replacement pattern and then to use it as replacement for the row class.
Comment #12
omahmI'm also stuck on this. I have a field of Content: Type set to exclude from display. Would be nice if I could add the [type] replacement pattern to the row class option so I can style the rows for each node type, just spits out '-type' at the moment, is there another way of doing this with hooks?
Comment #13
rokrPlease also have a look at
Comment #14
Norberto Ostallo commentedAny updates/patches about this issue?
Comment #15
TelFiRE commentedUpdate? This is a long-standing, well known bug that has no workarounds as far as I can see.
Many thanks to the views developers, but I can't see why some priority isn't placed on this. It's really limiting.
Comment #16
longtom commentedYou might experiment with the views php module (http://drupal.org/project/views_php). I was able to use this and have my tokens replaced inside css.
Comment #17
clemens.tolboomFor example the token for Row class
Comment #18
clemens.tolboomFWIW I added
which make you wonder why not adding 'default' classes. The ugliness of this is we need also a template file wrapping a div around my views-view-fields.tpl.php content like
The result is like
Comment #18.0
clemens.tolboomAdded image to illustrate this.
Comment #19
yanchen commentedFor me the replacement pattern in 'create css class' option under style setting just returns the token:
In the 'create new class' under style setting for the field I entered:
silk-[field_silk_color-value]
So if the value is 'red', it supposed to be 'silk-red' ...
Comment #20
clemens.tolboom@yanchen are you trying to tell 'cannot reproduce' ? Then it's ok to change the issue status ;)
Comment #21
Dicebar commentedThis issue still seems to exist. Here is another potential workaround for people who run into this issue.
As raw value tokens do work in the regular field output, you can first build up your CSS class in a field that you hide from display, and then use the output from that field as a token for the class in your second field. To build on yanchen's example in #19:
- Add field_silk_color as field.
- Check "exclude from display".
- Under "Rewrite results" rewrite the results to "silk[field_silk_color-value]".
- Add field_silk_color as a field again.
- Under "Style settings" customize the field HTML and add a class name to akin to [field_silk_color]. Check the replacement patterns as mentioned above to verify your field name.
This should end up with the desired class name being rendered on the field.
Comment #22
artfulrobot commentedI've noticed that adding a DraggableViews field also breaks the token substitution in views row classes.
e.g. if I have rows class set as
issue-[field_issue]then this works without Draggable Views field, but if Draggable Views field is also added then the output is justissue--field-issue(EDIT: ah, there's a workaround for this)
Comment #23
dgtlmoon commentedSo I found that preprocess wrappers like template_preprocess_views_view_unformatted are calling ->get_row_class() to render out the tokenized values where possible
However get_row_class() passes (correctly) the class information via tokenize_value however it does not convert that information to a css class name (with drupal_html_class), additionally I used explode() to make sure each token is parsed (not just only using drupal_clean_css_identifier())
Thoughts? Seem's fairly safe to me, although I think that the confusion here could be now 'get_row_class' should really be 'get_row_classes' - as this function is only called once no matter how many classes you have
Comment #24
dgtlmoon commentedAnd ofcourse the previous patch was rolled wrong :)
Comment #25
polYour patch is working perfectly, we should now determine what is the best solution between your patch and my solution here.
Comment #26
dgtlmoon commented@Pol I think mine is more applicable - adding a another field hook does not fix this initial problem - however having that extra hook is definitely very handy (And your patch is relying on transliteration module to exist, so makes it a little irrelevant to most use-cases)
Comment #27
DrCord commenteddgtlmoon's patch in #24 worked great and was lightweight and easy to apply.
Comment #28
barwonhack commentedNice effort on #24 BUT does not respect individual class names.
EG: "Term one, Term two, Term three" are output as "term-one--term-two--term-three".
Should be: "term-one term-two term-three".
Comment #29
bnorbi commentedpatch #24 worked for me
Comment #30
barwonhack commentedDeleted my comment - sorry wrong issue.
Comment #31
attiks commentedPatch works and is - IMHO - a cleaner fix then the other issue
Comment #32
polThis patch is simple and should be working for this particular use case indeed.
My question is, why we do not provide valid CSS names through the token system already in place ?
See my patch here: https://www.drupal.org/node/1360186#comment-8008187
Thanks!
Comment #33
polAfter a discussion on Hangouts, the patch proposed in this thread is the way to go. Thanks all !
Comment #34
dawehnerI'm a bit confused about the additional drupal_strtolower() call in
drupal_html_clas.Are we okay with this potential BC break?
Comment #35
polYup that's why I proposed to have additionnal tokens...
Comment #36
dawehnerWhy can't we just call out to the values not using
drupal_html_class?Comment #37
attiks commentedIt is best practice for class names to be lower case
Comment #38
damiankloip commentedLooks good, aside from:
The call to drupal_clean_css_identifier and drupal_html_class is not needed. drupal_html_class will call that anyway.
Comment #39
jelle_sNew patch based on #38.
Comment #44
jelle_sNew patch with fixed tests.
Comment #49
jelle_sI missed something. Last try, should be green now.
Comment #50
attiks commentedThanks
Comment #51
dawehnerThere we go!
Thanks a lot for everyone who contributed on this issue.
Comment #52
damiankloip commentedHere is a patch for 8.x. Looking at the 7.x patch, I think it is not completely correct. $classes could not always be set. Will provide a new patch.
Let's see what fails with the 8.x one first.
Comment #53
damiankloip commentedDaniel, here is the additional fix for 7.x. $classes array will only work if
$this->uses_fields() && $this->view->field. Otherwise, $class will just exist. Because the previous patch inited $classes array regardless,and IDE wouldn't care. We still need to explode the classes for the other case. I would just commit this interdiff!Comment #54
dawehnerThis is the problem with you @damiankloip, you are right, always! Meh.
Comment #56
lendudeThis is not going to work with Twig tokens since they contain spaces and after the explode, tokenizeValue will no longer have any working tokens left. So after exploding on white space we need to reconstitute the token again.
So, took a stab at that.
Not sure if we need more tests, because the updated tests now test if a proper formatted class is printed, where the test before the change only tested if a class was returned.
Comment #58
solysergio commentedThank you very much
Comment #59
elpino commentedRegarding the last patch for 7.x-3.x at #49 (and interdiff on #53)
Thanks, works great! ...almost.
As mentioned in #28, I discovered that if a token had multiple elements on substitution they would end up as a single concatenated string, ie taxonomy terms applied to a node.
This is my solution, I don't know if it's the correct way to go about it because I don't know if all lists/arrays after token substitution end up concatenated with underscores...
Line 139 of plugins/views_plugin_style.inc (sorry I don't know how to produce the patch)
Comment #60
abarpetia commentedHello,
Can anyone tell me which patch has been committed to 7.x-3.x-dev branch?
There is no commit message and this issue breaking few sections of my website. As this patch is included into recent views 7.x-3.14 release which is also security release, I would like to fix my website ASAP.
Thanks in advance.
**Edit**
Found issue: drupal_html_class converting all the classes to lower case. If anyone else facing this issue please look 2750021 issue.
Comment #61
amaisano commented@elpino #59 above: I have a similar problem. This new update broke my website because I had multiple tags printed as Views row classes.
Before:
<div class="views-row even tag1 tag2 tag3">After:
<div class="views-row even tag1-tag2-tag3">Furthermore, non-alphanumeric separator for the multiple values settings results in a hyphen, so I can't use the " " space separator any more.
Does your code alteration address this?
Comment #62
volker23 commentedSame problem as @amaisao #61 above. How can I remove the - between multiple terms. For now i have just replaced views_plugin_style.inc with the previous file from 7.x-3.13. I hope this won't break even more things.
Comment #63
dawehnerI'm wondering whether we could be more intelligent using a regex for the exploding in the first place.
Nitpick: let's fix this CS error
Comment #64
finnehow about
Comment #65
dawehnerThis looks much better for me.
Comment #66
lendude@finne, thanks! Turns out all the stripping of spaces and empty elements broke everything. We need to implode using the same delimiters that were used on the split, and in the same spot. With the preg_split in #64 a class with "blabla-{{ token }}" would come out as "blabla- replacement" and not "blabla-replacement".
So just leaving the spaces in the array and then imploding back with no glue gives the right result.
But added a test so we test both scenarios. A solitary token and a concatenated token.
Comment #67
dawehnerAs talked with @lendude we should add a unit test, now that this logic gets too complex for us to handle. Here
Comment #68
lendude@dawehner, good call on the unit tests, that immediately highlighted some issues, so more unit test and reworked the fix.
Comment #69
lendudeQuick cleanup.
Comment #70
dawehnerThat's just beautiful!
Comment #72
adrien.felipe commentedSadly this commit comes as a shot in the foot for me, as I use a contextual filter to pass a serie of classes to my views, depending on user configurations:
%1 would be replaced for example by 'col-xm-12 col-sm-6 col-md-4'
but now it obviously prints 'col-xm-12-col-sm-6-col-md-4' and all my site is visually broken.
I wonder what other option I would have.
Comment #73
alexpottIs #72 a commit blocker?
Comment #74
dawehnerSounds like it to be honest!
Comment #75
lendudeHmm, just thinking out loud here....
I see three options here:
1. One token equals one class (the current fix), all spaces in the replaced token get replaced by dashes.
2. Tokens get replaced before class cleanup and any spaces in the replaced token lead to new classes.
3. Add an option to switch between these two.
Option three, I think, would be bad and confusing for most users, lets not go there.
Looking at the screenshot in the IS, option one would lead to a class 'point-of-interest' and option two would leave you with three classes 'point of interest'.
Since it's easy enough to target three classes in one CSS selector, getting three classes doesn't sound too bad, just target .point.of.interest and you're done. Getting the point-of-interest class means you can't target just the point part of it, which is what #61 and #72 are about.
So yeah, after writing this, I agree, we should try to do option 2.
Comment #76
lendudeAnd looking at it more, this is what already happens now in current HEAD, so all that would change would be the use of Html::getClass vs Html::cleanCssIdentifier, but there are already issues with that, see #2750021: View Styles Plugin - row CSS class name is forced to lowercase
Not sure if we need to do anything here....
Comment #77
adrien.felipe commentedI made a patch not to clean a class if the token is a contextual filter raw value (ie stats by '!').
This solved my issue. I'll post it and put a link back here.
Comment #78
amaisano commentedWould #76 or #77 allow separated multiple classes output from one field? See my comment at #61
Comment #79
adrien.felipe commentedFor D7 and views 7-x.3, I have uploaded this patch #2769971: Raw token values will have spaces removed when used as class that will let you use raw value of contextual filters (!1) to insert multiple classes. This works for my case.
I don't know if in #61 you use contextual filters, or use values from others fields.
In my opinion, I would vote for @Lendude's point 3.
1. I don't believe we should change so radically such a behavior
-> I remember being frustrated by these kind of classes "Point of interest", but without doubt many people styled theirs sites this way.
2. This new functionality - while the right behavior - should be switchable and behave as before in old installations.
3. It might be a problem to class clean in some occasions, like #59, #61, #72 and more.
Making it switchable would be easy with a db_variable, but how would @Lendude's point 3 be implemented?
In my case contextual filters bring 2 values, rendered and raw, which makes it easy.
Maybe CSS token should have and extra character or format, letting them be "raw" and not parsed.
Comment #80
klonosUntil there is consensus and the issue is fixed in Views 7.x, @Dicebar's solution in #21 worked for me. Thanx!
Comment #81
damienmckennaFYI forcing class names to lowercase breaks some existing modules and sites, see #2750021: View Styles Plugin - row CSS class name is forced to lowercase for details.
Comment #82
damienmckenna(sorry, wrong issue, it's #2750021: View Styles Plugin - row CSS class name is forced to lowercase)
Comment #84
barwonhack commentedA possible alternative solution is to add a text field to a taxonomy that serves as a CSS field for each term.
You will need populate this manually (or possibly using rules) but at leat you can create a CSS class devoid of spaces and capitals.
Comment #85
xjmHmmm, this seems like totally buggy and unexpected behavior for me. Plus, we are then polluting the output with lots of single-word, non-namespaced classes, so I think it also violates a lot of our expectations for themers in D8.
I also don't see any discussion about sanitization on this issue. I'd at least like to see some test coverage asserting that we're not opening up XSS injection holes via tokens here.
I think this is a more correct fix though:
Comment #86
drakythe commentedSo I believe this patch when applied to D7 branch of views has a behavior that broke some behavior.
We're using a space character as a simple separator between multi-value fields, then using those multi-value fields as CSS classes. By stripping the white space and replacing it with dashes it completely broke our unique classes we needed for certain behaviors. I get replacing spaces in field values, but it would be far more convenient if the string replace was performed before the simple separator is applied.
Comment #87
xjm@dawehner, @alexpott, @tim.plunkett, @cilefen, and I discussed this issue after I commented in #85 and agreed to downgrade it to normal. While the current behavior can be buggy, it does not meet the criteria for a major bug. Thanks!
#86 makes sense.
Comment #89
tacituseu commentedThere seem to be two issues here:
1. whitespaces in tokens used for css
It can be solved by using twig's filtering both at row and field level:
some-row some-row-type-{{ token_name|clean_class }}, I'd be against any auto-magic here, just better documentation, user should be responsible for assuring the class will make sense, instead of code trying to guess the intention/force specific pattern (beside assuring valid HTML, so explode on space, 'clean_class' and 'trim' the resulting array's elements, finally implode it with space).2. using raw tokens which are only available for rewrite output
They are added (but then not cached) by
Drupal\views\Plugin\views\field\EntityField::addSelfTokens()insideDrupal\views\Plugin\views\field\FieldPluginBase::getRenderTokens()only when$itemargument is passed and has key 'raw' set toFieldItem, which only happens for 'Rewrite results' pass, field level style overwrites under 'Style settings' don't have them as they are called in another pass fromDrupal\views\Plugin\views\style\StylePluginBase::renderFields()with empty array as argument:and even further complicating matter is
Drupal\views\Plugin\views\field\FieldPluginBase::elementClasses()callingDrupal\views\Plugin\views\field\FieldPluginBase::tokenizeValue()which is using cached values from$this->view->style_plugin->render_tokens[$row_index];(set by previousgetRenderTokens()calls) and when they're not found fallbacks to passingIt seems to be by design as explained with workaround given by @dawehner in #5 (more detailed in #21), which is fine for row level rewriting, but I would expect that at the field level if there is a 'Raw value' token listed under 'Rewrite results' then I can use it as well in 'Style settings'.
Comment #102
acbramley commentedThis issue hasn't been updated in over 7 years. We require more information to proceed here. Can steps to reproduce be added to the IS if this is still applicable?
Comment #103
pameeela commentedUpdated IS with some more info.
Comment #104
acbramley commentedThanks so much @pameeela! Back to NW for the fix to be rolled into an MR against 11.x
Comment #107
xjmAdding credits from my triage review in #87.