This issue is now a meta-issue. It has been separated out into the following child issues:
- #3089521: Sort options for entity reference field are unsorted
- #3089523: Use progressive disclosure to hide Sort options on entity reference fields until bundles are selected
- #3089525: Sort options should correspond to bundles selected for entity reference field settings
- #3089528: Sort options for entity reference fields can be ambiguous if a field has different labels across bundles
- #3089529: Sort options for entity reference fields may be confusing if several fields share labels
Problem/Motivation
Steps to reproduce these issues:
a) Install with the Standard install profile.
b) Go to Admin > Structure > Content Types.
c) Edit the Article content type -- change its name to Recipe and title field label to Recipe name.
d) Edit the Page content type -- change its name to Vendor and title field label to Vendor name.
[Note: This is similar to the content types used as examples in the User Guide.]
e) Now go to the Recipe content type > Manage fields. Add a Vendor reference field. Or alternatively, go to the Vendor content type and add a Recipe reference field. When you get to the field settings page, you'll see that the title sort option in the "Sort by" select list says "Recipe name" in either case (or it might randomly say "Vendor name" in either case -- I've seen it both ways). Anyway, it is very confusing to say "Recipe name" if you are trying to add a Vendor reference field on the Recipe content type. Here is what the sort options look like:

Proposed resolution
Some points to consider for resolving this issue:
- One field may have multiple different labels across different bundles. The current code is arbitrarily choosing to display one of the labels and ignoring other labels. But in a simple select list, we cannot really show all of the labels -- there could be a LOT, especially for things like Title that are often labeled differently in different content types.
- The same label may be used on multiple fields. The current code is only displaying the label (ambiguous), not the field machine name (unambiguous). We need to display the machine name too, or perhaps instead of the label.
- This is a page that is used by site builders, not content editors, so perhaps displaying only the machine name would make sense -- but on some sites that have been around for a while, certain fields get repurposed and relabeled without changing their machine name, so machine names may not be so intuitive either. Also, removing the label would be disruptive for people who are familiar with the current approach. However, when you're adding a field to a content type, if you want to use an existing field, the Field UI module is already only showing the machine name in that dialog.
- Similar existing UIs in Core:
(a) Views -- Add Field/Filter/Sort dialog -- gives you the labels and not the machine names. But it has an entire table with wrapping to put lots of information in, not just a select list.
(b) Field UI -- add existing field for -- what you have in the select list is "Field Type Name: field_machine_name". For example, it says "Entity reference: field_test" for one test field I set up. It does not show the label of the field at all, just the label for the field type.
So... here are some conclusions:
1. We want the machine name to be displayed.
2. We want the label to be displayed. But there could be a lot of labels. So, we need to convey that somehow.
3. We probably want the label(s) first, then machine names, to be least disruptive.
4. The list should be sorted alphabetically.
There's a section below in the issue summary showing some possible formatting options that were considered.
The latest patch (currently #128 but it needs more tests) looks like this:

Remaining tasks
- Fix #3065903: Add label sort ability to Select element
- Decide on which formatting option is best
- Make a patch to implement it
- Update the patch to use the results of #3065903: Add label sort ability to Select element
- Add tests
- Add a change record.
User interface changes
Less confusing and less ambiguous labels on the choices for sorting reference fields if there are multiple bundles with different field labels for the same field or multiple fields with the same label. In my experience building web sites for clients, the former is pretty common for the Title field, and somewhat common for other fields, and the second is also fairly common.
Furthermore, the labels/fields displayed are limited to the bundles that are currently selected to be referenced.
Also the choices are sorted for better scanning.
API changes
None.
Data model changes
None. Behind the labels, the machine names of the choices do not change, only the UI.
Other formatting options that were considered
There are several ways we could format the options. Let's consider each option for the following cases:
C1: Title field, where one content type has it as "Recipe name" and another has it as "Vendor name".
C2: Image field field_image, label "Image", which has subfields of alt, target ID, etc. [see comments #21/22]
C3: Field added in Field UI, with machine name field_foo, with label "Foo" on all content types.
Here are 4 possible options for the option labels:
F1: Patch in #23
- C1:
Recipe name|... [title]
- C2:
Image (alt) [field_image.alt]
Image (target_id) [field_image.target_id]
- C3:
Foo [field_foo]
For this one, we have a patch (#23) and a screenshot. Notice that the highlighted item is an example of (C1):

F2: Use () for the fields
This is not great -- see also comments #21/22.
- C1:
Recipe name|... (title)
- C2:
Image (alt) (field_image.alt)
Image (target_id) (field_image.target_id)
- C3:
Foo (field_foo)
F3: Separate by :
- C1:
Recipe name|...: title
- C2:
Image (alt): field_image.alt
Image (target_id): field_image.target_id
- C3:
Foo: field_foo
F4: Machine name first with :
- C1:
title: Recipe name|...
- C2:
field_image.alt: Image (alt)
field_image.target_id: Image (target_id)
- C3:
field:foo: Foo
Release notes snippet
The user interface for the field setting for choosing how to sort the options for Entity Reference fields has changed. (Behind the scenes, the machine names of the options are still the same, although they may be shown in a different order than they were previously.)
Previously, if you had several bundles (such as content types) which each used the same field with different labels, the user interface for choosing how to sort the references would show you one of the labels. For instance, it is quite common on Node content types to change the label of the title field. So, if you wanted to sort a Node reference field by title, you might see something like "Recipe" or "Vendor" as the label. This could be confusing.
The UI has been changed so that it now shows the most common label in use for each field that can be used for sorting, plus an indication like "Title, ..." if there is more than one label in use, plus the machine name for each field. This should avoid confusion by site builders about which field is actually being chosen to sort by.
In addition, the choices are sorted for easier scanning, and the choices/labels are limited to the selected bundles that can be referenced.
[Put in screenshots from the issue summary showing before/after pictures.]
| Comment | File | Size | Author |
|---|---|---|---|
| #130 | Screenshot_128.png | 22.25 KB | jhodgdon |
| #128 | 2900409-128.patch | 14.9 KB | benjifisher |
| #128 | interdiff-2900409-126-128.txt | 1.12 KB | benjifisher |
| #126 | 2900409-126.patch | 14.9 KB | benjifisher |
| #126 | interdiff-2900409-124-126.txt | 4.18 KB | benjifisher |
Comments
Comment #2
vivekguptakota commentedI found this this fix. If it is suitable then we can use this patch.
This is patch is like Jugada. May be I am wrong but it works.
Comment #3
jhodgdonThanks for trying! However, that patch is not correct. For one thing, the word "Title" would need to be translated... for another, it seems kind of like a "hack" -- not really addressing why the title field label is incorrect, just sort of putting a band-aid on it after it is first done incorrectly.
Comment #4
vivekguptakota commentedI already told that, it is Jugada(hack).
Because field_name is same i.e. title. So in array title field are always override with latest called values as title is common in all content type.
Comment #5
jhodgdonSorry, I didn't understand "Jugada". :) Anyway, we should not have patches like hacks...
Comment #8
jhodgdonHere is what I think the problem is. In DefaultSelection::buildConfigurationForm()
https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Entity%21...
it does essentially this:
So. If you have two bundles foo and bar for Node, and their title fields are labeled "Foo name" and "Bar name", and you go through this code, your reference field settings form in the "Sort by" setting will either show "Foo name" or "Bar name" as the sort by option. And this will be confusing, hence this Usability bug.
This will probably also be a problem for other fields that may have different labels in different bundles.
The question is what to do about it... Probably what we need to do is show all of the options instead of just the last one we encountered in the loop. Maybe something like this patch?
Comment #9
jhodgdonThis patch isn't quite right -- it needs to remove duplicates in the labels before concatenating. How about this?
Comment #11
jhodgdonUpdating the issue summary with more straightforward steps to reproduce. I am making screen shots and will update shortly.
Meanwhile here's a new patch with (hopefully) the coding standards problems fixed. Not making interdiffs right now since I think no one is looking at this patch and it's pretty small anyway.
Comment #13
jhodgdonAdding before/after screenshots to issue summary.
Comment #14
jhodgdonBetter issue title.
Comment #15
jhodgdon1 more coding standards fix hopefully -- interdiff is only whitespace.
Comment #16
jhodgdonDiscussed this on the weekly Usability call today. Points:
a) There's an additional related problem: two fields on two different bundles may have the same label. In this case, the same label would appear in the select list twice, and it would not be obvious which field you want to sort by. You might even choose one that doesn't appear on the bundles you've chosen.
b) With the current patch, if one field had a bunch of different labels across bundles (could often happen with the Title field, for instance), the label shown in the Select list would get really long. That's not good.
c) Additional problem: there's no sorting on the list of options.
d) Additional desirable feature: if you check boxes for which bundles to allow, it should filter the list of sort-by fields down to those that occur on the chosen bundles [this should be a separate issue].
So, we probably need a new patch that would:
1) Display the machine name as well as the label. Probably in format "field_foo_bar (Foo Bar)".
2) Limit the display of labels if there are multiple labels. If we're displaying machine name, probably only 1 option will fit, plus a "..." if there is more than 1. So it might look like: "title (Recipe name|...)"
3) Sort the list of options.
I'll work on it in the next day or few days, unless someone else has the inclination.
Comment #17
jhodgdonYou know, what we really need here is the pop-up field picker you get in Views UI when you are adding a field, filter, or sort, rather than trying to stuff all the relevant information into a select list.
Comment #18
jhodgdonLooking at what Views UI does:
The code to build the Add dialogs is in \Drupal\views_ui\Form\Ajax\AddHandler
https://api.drupal.org/api/drupal/core%21modules%21views_ui%21src%21Form...
That method is building all types of "Add xyz" forms for Views UI. What that method does:
a) Gets a list of "options" to display in the form from Views::viewsDataHelper()->fetchFields(), passing in the "xyz" as the "type" of thing being added.
b) Builds them into a tableselect with filtering in that form method.
and (c) that form is popped up using Ajax (or a direct link if there is no JS) when you click on one of the Add links when editing a view.
This would be complex to do. Views UI has all this infrastructure to maintain the state when popping out to the links etc.; Field UI doesn't. So ... probably not going to happen, although I think it would be way better than trying to cram information into a select list here.
Comment #19
jhodgdonAnother thing to think about: on the Field UI's "Manage Fields" page, there is a field select list for when you are adding an existing field to a content type. What does that do? Let's see... That is in FieldStorageAddForm::getExistingFieldStorageOptions.
https://api.drupal.org/api/drupal/core%21modules%21field_ui%21src%21Form...
That has a limited number of options -- only includes configurable fields that are used on bundles of this entity type, but not already on this bundle. And the options are formatted like this:
So, that has set a precedent of using "Type: field_machine_name" in a field select list, when you add an existing field to a content type.
However, all of the field machine names here were presumably created in Field UI. It doesn't include built-in fields created by Core or Contrib developers with who knows what kind of coder-intuitive machine names... so not exactly the same situation.
Comment #20
jhodgdonOK, here's a new patch. Uploading so I can try it out on simplytest.me (and so tests will run). Will upload screenshots soon. I really should get a local test site going... :(
Comment #21
jhodgdonAh, this isn't quite right -- the asort() doesn't work because the array elements are $this->t() objects and not strings that can be sorted.
But anyway, any comments on the output format, which looks like this screenshot:

Comment #22
jhodgdonBesides the sorting problem, the other thing I don't like about that latest patch is that () is used both for column names (for things like Image fields that have the alt text for example), and for machine name. It's confusing.
Not sure what to do. Any ideas?
Comment #23
jhodgdonHere's a new patch. I put the field machine names in [] instead of having two () in each label. And I cast the t() calls to string so the list can be sorted. And a screenshot of what it looks like:

Comment #24
benjifisher@jhodgdon:
Usability review
You did not add the "Needs usability review" issue tag, but you did mention this issue in the #ux channel and list it as a "remaining task", so here goes. This review is based on the comments above and on the screenshots; it is not a code review.
Here is a link to the Drupal Usability meeting from 2019-02-05. I hope that is the right one.
As far as usability is concerned, the most important thing is to have an unambiguous identifier, so +1 for adding the "machine name" to the Select list. (Full disclosure: to some extent, I am agreeing with myself. I think I am the one who brought up the possibility of different fields with the same label during the Usability meeting.)
It is also important for usability to sort the list, so +1 for that improvement, too. How have we put up with this until now?
I seems to me that the only real question is whether to put the label or the machine name first, and I think you have that right, too. Given that we want the least disruptive change, and the current list has just the label, I think it is right to show that first, followed by the (unambiguous) machine name.
Usability is improved if we present a consistent UI. So I do not love the current format with square brackets, "Label [machine_name]". Why not follow the example of reusing a field on the "Add field" (to a fieldable entity) form and separate them with a colon as in "Label: machine_name"? Another option is to use parentheses (consistent with the Views UI) and add italics to distinguish the machine name from part of the label: "Label (machine_name)".
By the way, I cannot talk about reusing a field without mentioning #2717319: Provide better default configuration when re-using an existing field.
Comment #25
jhodgdonThanks for the usability review! Adding tag for the next time around.
So, I agree it would be good to mimic other UI patterns.
Here's what we have available.
a) In Field UI, when you go to add an existing field to a content type, what you have in the select list is "Field Type Name: field_machine_name". For example, it says "Entity reference: field_test" for one test field I set up. It does not show the label at all.
EDITED b) In Views, it just seems to pick one label. So for that field, it says "Test Test", although in another content type it is called "Vendor Test". So this would suffer from the same problem. However, the Title field says "Title" -- it hasn't picked up the customized title names. I am not sure why. Also in Views it is a multiselect, multi-column table and it doesn't show the machine name at all. So, that is actually I think not a great pattern.Edited version: In views you have a multiple-column multiselect table. It is alphabetized by one of the labels. It does show you "Also known as Other Label". But it has a lot of space (multiple lines etc. in that area for descriptions). It doesn't show the machine name.
Comment #26
jhodgdonHere is a screenshot of what Views does. We just cannot do it in a select list.
Note that title is always called "Title" and the alternate forms are not shown. And machine names are not shown at all.
(In this screenshot, I made a field_test with labels "Test test" in the Test content type, and "Vendor test" in the Vendor content type.)

Comment #27
jhodgdonOK. @benjifisher and I were discussing this in Slack.
It looks like we agree on the following:
1. We want the machine name to be displayed.
2. We want the label to be displayed. But there could be a lot of labels. So, we need to convey that somehow.
3. We want the label(s) first, and alphabetical by label.
So, here are some options for formatting. Let's consider each option for the following cases:
C1: Title field, where one content type has it as "Recipe name" and another has it as "Vendor name".
C2: Image field field_image, label "Image", which has subfields of alt, target ID, etc. [see comments #21/22]
C3: Field added in Field UI, with machine name field_foo, with label "Foo" on all content types.
Formatting options
F1: Current patch
- C1:
Recipe name|... [title]
- C2:
Image (alt) [field_image.alt]
Image (target_id) [field_image.target_id]
- C3:
Foo [field_foo]
F2: Use () for the fields
This is not great -- see also comments #21/22.
- C1:
Recipe name|... (title)
- C2:
Image (alt) (field_image.alt)
Image (target_id) (field_image.target_id)
- C3:
Foo (field_foo)
F3: Separate by :
- C1:
Recipe name|...: title
- C2:
Image (alt): field_image.alt
Image (target_id): field_image.target_id
- C3:
Foo: field_foo
Comment #28
jhodgdonAnother option would be to change it up and have the machine name first, alphabetical by machine name, so it would look like this.
F4: Machine name first with :
- C1:
title: Recipe name|...
- C2:
field_image.alt: Image (alt)
field_image.target_id: Image (target_id)
- C3:
field:foo: Foo
Comment #29
jhodgdonGiven that the UI for adding existing fields to a content type has only the machine name and not the label, and that the machine name is shown on the other Field UI pages, I think I actually would vote for option F4 of the options listed in comments #27-28. Any other thoughts?
Comment #30
jhodgdonAdding the 4 formatting options to the issue summary, as well as information about the existing similar UI for Views and Field UI in Core.
Comment #31
jhodgdonForgot some information.
Comment #32
benjifisherI edited the IS a bit.
The main reason for preferring "Label [machine_name]" over "machine_name [Label]" is that the existing UI has the Label (only) and we prefer to minimize disruption.
Comment #33
jhodgdonGood point... Sounds like maybe the current patch, with formatting option 1, is probably the best we can do, unless someone thinks of a better option?
Comment #34
jrockowitz commentedAs discussed at the UX team meeting on April 2, 2019, we feel the best approach is F1: Patch in #23 which append each field's machine name in square brackets.
I am removing the 'Needs usability review' tag.
Comment #35
jrockowitz commentedComment #36
alexpottIf the ... is an ellipsis then is needs to be an
…character. I think the|…is a new pattern in core - are we sure this is the best way to illustrate what we mean? I'm also concerned about how this will look if the label is the @label (@column) format.Could we use formatPlural instead of the if here?
The arguments could be prepared outside the list.
Comment #37
jhodgdonRegarding the question of "is this the best way"... To resolve this issue, we came up with a lot of possible solutions, looked at existing UI patterns in Core for other field-related things, discussed all the possibilities at several Usability group meetings, went over all the cases (including fields like Image that have columns), and decided this was the clearest presentation of all the solutions we could think of. I think it's been usability-reviewed enough, and the approach was signed off on by the Usability team.
But I'll address the code and ... character issues in a new patch soon.
Comment #38
jhodgdonAlso regarding formatPlural, I don't think it would work well here. Some languages have many different "plurals" forms of nouns/verbs; for instance, I think Russian has different forms for @count being 0, 1, (2-4), or 5+, while English just uses singular for 1 and plural for 0 and 2+. So a translator is presented with the two English strings, which are normally things like ["1 thing", "@count things"], and asked to make them into their array of N "plural" forms. It makes pretty good sense if "@count" appears in the string, but there's no @count here at all. We really want to have one result for 1 and a different result for 2+, no matter what language is involved, and we're not talking about inflected forms for nouns/verbs. So to me, it doesn't feel like formatPlural is the right fit, where a Russian translator would see strings that don't involve @count at all and maybe not know how to translate it into a plural set?
Comment #39
jhodgdonAnother note on formatPlural() is that there are some languages, like Chinese, that have only 1 plural form. For those languages, formatPlural would definitely fail us here, as they would not have 2 strings to submit. Anyway, here's a patch, and I added a note about not using formatPlural(), since it seems like a good question that could come up again in future code maintenance.
Anyway, here's a new patch that hopefully addresses #36:
- Use the elipses character instead of ...
- Move the calculation of t() arguments outside the if() statement (which I think/hope is what was meant in the third item).
- Add a comment about why we don't want to use formatPlural(), for future maintainers.
Comment #40
benjifisherI reviewd the patch in #39. It addresses the points raised in #36.1 and #36.3, and I agree with the argument not to use
formatPlural()as suggested in 36.2.I just have a couple of minor suggestions for simplifying the code.
These lines are rather long. I think the code is easier to read if you define
$arguments = ['@label' => $field_definition->getLabel()];outside theifblock. Then you can replace the longest line with something likeThe not-so-long line becomes
If you prefer to change those lines as little as possible in order to avoid scope creep on this issue, then I will not argue. Since you are touching these lines, I hope you will agree to clean them up a bit.
I think it is a little simpler to make the
|…part of the replacement text:If you think that counting the list after popping one element is too tricky, then there are alternatives. For example,
'@label' => array_pop($list) . (count($list) > 1 ? '|…' : '');. We might even decide that the comment is redundant if we do it that way.Also, have you considered using
array_shift()instead ofarray_pop()?Comment #41
benjifisherI forget: maybe we have already considered and rejected this idea ...
Since the machine name is the only reliable thing to search for and the status quo is that the list is not alphabetized, maybe we should sort the list by machine name instead of label.
Either way, we will be getting something much, much better than what we have now.
Comment #42
jhodgdonThanks for the review!
I have adopted some of what you suggested. What I didn't adopt:
a) I think we do want two translatable strings for the label: '@label|… [@machine_name]' and '@label [@machine_name]'. I am just not sure that all languages use ... to mean "and then some". We should leave that open to translation.
b) I see what you're saying about the machine name, but I think it's hard to scan things that are sorted by something other than the left-most part of a string. And sometime in one of the comments here or UX meetings, I am pretty sure we were told to emphasize the labels (put them first) and not the machine names. Plus the other UI comparisons (like Views) sort by label. So... I think we're stuck with that?
Anyway, here is a new patch, and interdiff.
Comment #43
benjifisher@jhodgdon:
Thanks for considering my suggestions. I think the updated patch makes the code a little easier to read.
I reviewed the interdiff and the full patch, and I retested. It all looks good. As I said in #40,
I am marking this issue RTBC. I am also adding the tag for a change record. I will draft one (not today) unless you do it first.
Comment #44
alexpottThe string cast is tricky. That means you are losing safeness. Which in turn means if the translation adds an HTML then things are broken. If you want to sort you need to sort in a way that does not lose safeness. To do this you need to do some thing that doesn't result in a change to the object.
So something like
We could open a follow issue to add a help public static to TranslatableMarkup so this is simpler for everyone.
Comment #45
jhodgdonOK... that looks messy but I see your point. Adopting your code... I added the function as a static in the class here -- I thought it made it a bit easier to understand the code.
Comment #47
jhodgdonwhoops. Should have probably tested it before uploading patch. I don't have a working environment now though (PHP version, ugh)... need to fix that sometime SOON. Meanwhile...
Comment #49
jhodgdonNeeds namespace to pass in a callable...
Comment #50
jhodgdonComment #51
benjifisherI think I prefer an anonymous function, as suggested in #44, to creating an extra method. We do not really want to encourage reuse of this function, since we plan to replace it with something better. Also, I think there are simpler ways to refer to the callable: something like
$this->compareTranslatablesorstatic::compareTranslatablesor[$this, 'compareTranslatables']or[get_class($this), 'compareTranslatables']should work.I am setting to NW because we should at least create a follow-up issue and add a code comment referring to it.
I was about to create that follow-up issue, but I am bothered by the inefficiency of cloning and converting to
stringand then throwing away the result. When sorting, we will have to do that many times for some items in the list. Is there a way to do this without rendering the strings more than once? I briefly considered (for the follow-up issue, not here) comparing based on the protected$stringproperty at the heart of the object. Then I realized how that would affect lists of translated strings. :-(Looking at the API documentation for FormElement, I see that there are properties
#after_buildand#process. Both of these are arrays of callbacks, similar to the#pre_renderand#post_renderproperties we had in D7. I am not sure whether either of these is used after the TranslatableMarkup objects have been converted to actual strings. If they are, then I think this would be more efficient than the solution suggested in #44.Comment #52
jhodgdonLooking into after_build and process does seem like a better alternative. I was also bothered by how inefficient this seemed to be.
Looking at API documentation for RenderElement, maybe we could also use the "lazy builder" functionality? Also, as a note, post_render and pre_render still exist (they are documented on RenderElement).
Anyway... It looks like maybe a post_render callback that would create the sorted options would be good, but I'm not really sure how that would work.
Comment #53
jhodgdonHah, actually how about if we added something to the Select form element, like a #sorted property, that would force the options form element to sort its options in its own post_render callback? That seems like an even better solution. Then we could just leave these things as TranslatableMarkup and everyone would have a solution. :)
Would that work?
Comment #54
jhodgdonDiscussed the idea in #53 on Slack with alexpott and benjifisher. We all seem to think it's a good idea. benjifisher suggested for some use cases, it might be useful to specify "Sort starting at element N and leave the first N-1 elements unsorted". So, to do that, probably we would want to add 2 properties to the Select form element:
- #sort (boolean, default to FALSE for BC) -- if TRUE, sort the options by their labels after rendering/translating
- #sort_start (int, default to 0) -- if sorting, start the sort at this element, leaving the previous ones as they were.
This seems feasible and better than the last patch...
Comment #55
jhodgdonHm... Well, I tried this idea out, and I don't think it is working out very well. I tried using the following callbacks on the Select form element class, with the following results:
- #pre_render, #after_build, #process -- the options at this point still have TranslatableMarkup objects in them
- #post_render -- the whole thing at that point is an HTML string
So, I looked into the theming. The theme hook is 'select' (not surprising). There is a preprocess function in includes/form.inc called template_preprocess_select(), which calls form_select_options() to do the work (also in form.inc).
But even here... The machine names for the options are cast to strings in this function (that I didn't modify), even if they are TranslatableMarkup. But the labels are still TranslatableMarkup objects when we get here. So, apparently they aren't actually turned into strings until you get to the Twig template, or rather I guess whatever gets passed into the Twig template is magically cast to a string somewhere else.
So... I am not sure what to do. I made this patch, which works (it does sort the options, and documents these new properties on the Select), but since it is still effectively casting the TranslatableMarkup to string too early (I guess?), maybe it is still wrong. I guess I don't really understand when it is and when it isn't OK to cast TranslatableMarkup to string. Maybe @alexpott can answer that question? If we can't cast to string in this theme preprocess function, then I guess we have to stick with cloning the objects still?
Meanwhile, here's a patch and an interdiff to the patch in #44... It does work, at least!
Comment #56
jhodgdonAs a note, there doesn't seem to be any testing for the Select element to verify how it renders...at least, if there is, I couldn't find it. Do we need to write one? If so, is that out of scope for this issue? It seems like it would be good to unit test the sorting behavior (with translation), but given that there isn't even, as far as I can tell, any test for Select (or for many other elements)... I guess implicitly most Functional tests will be testing that select elements are working... but still!
Comment #58
benjifisherFor the proposed
#sort_startoption (see #54) I was thinking that it would normally be 0 or 1, to handle cases like the- None -option, which we want to keep at the top. I cannot think of a case where you would want it to be more than 1, but my lack of imagination does not mean it will never be needed. As long as we are adding an extra option, I figure we may as well let it be an integer rather than a boolean.Comment #59
jhodgdonUm.... I think #sort_start is an int in the patch? But I should have set it to 1 to skip the -none- option in the Reference field sort select in this patch. The default on the Select element itself is zero.
Anyway, the patch failed tests with a bunch of undefined index #sort_options errors, I think due to the recursion in form_select_options() that happens if there are option groups (which is why there were 82 fails and not thousands). This should fix it.
Comment #60
jhodgdonChatted with @alexpott about this in Slack:
a) What we need to do is split off the modifications to Select into a separate, blocking child issue. So, doing that.
#3065903: Add label sort ability to Select element
b) In addition, there is one modification needed to the patch: when sorting the labels, we are implicitly casting the TranslatableMarkup objects to string. What we want to do is leave the 'label' array element as TranslatableMarkup, while sorting by another variable that is that cast to string. Subtle.
c) Also there is a test for the Select element in \Drupal\Tests\system\Functional\Form\FormTest::testSelect() that can be added to in this child issue.
So, setting this issue to Postponed until we do the child issue, in which case this patch will be smaller.
Comment #61
jhodgdonHere is the most recent patch, without the bits that are now on #3065903: Add label sort ability to Select element.
Comment #62
benjifisherAs I just wrote on #3065903: Add label sort ability to Select element, I think we should use the
#empty_optionand/or#empty_valueoptions instead of adding the "- None -" option and#sort_start => 1.Comment #63
jhodgdonI agree that this patch should be using the empty options. I will just point out that this particular select wasn't using them before (no idea why not, but we should be).
Comment #64
berdirviews has a related helper function: views_entity_field_label()
Wondering if we'd want move that out of views and reuse, if that helps?
Comment #65
jhodgdonOh yeah, definitely! I was not aware of that function. Would totally be better to use it. It even counts to find the most commonly used label, which is better than what the code in this patch is doing.
Would we put it onto a class somewhere, or should it just be put into some other include file?
Comment #66
berdirGood question, not sure. Putting it on EntityFieldManager might be an option, it uses methods from that and the entity type bundle info service, which is already available there.
Comment #67
jhodgdonI guess we should spin that off into a separate issue:
#3069442: Deprecate views_entity_field_label() in favor of EntityFieldManager->getFieldLabels
Also updating the issue summary.
Comment #68
jhodgdonI explored the views_entity_field_label() function on that other issue, and concluded that we can't really call it here (whether or not it is inside Views or on the EntityFieldManager class... Reproducing what I wrote on #3069442-4: Deprecate views_entity_field_label() in favor of EntityFieldManager->getFieldLabels here (slightly edited to make sense here):
So, this issue I think only needs to be postponed on #3065903: Add label sort ability to Select element. Thoughts?
Comment #69
jhodgdonHere's a new patch, which again requires #3065903: Add label sort ability to Select element.
I did three things here:
a. Used the #empty_value option in the select to add the "None" entry, instead of doing it manually like it was before.
b. As in views_entity_field_label(), use the most popular label as the one users will see if there are multiple choices.
c. Moved the calculation of the options list to a separate method, because it was getting complicated and broke the flow of the form builder method.
I think that the main patch will be actually quite a bit easier to read than the interdiff, but here are both. Leaving this as Postponed as this depends on that other issue's patch. Anyway, it works in my local test site...
Comment #70
jhodgdonWhoops. I don't need sort_start. Same patch with this one line taken out. Still works, because the sort_start default is now sensible on the other issue. :)
Comment #71
larowlanBlocker is in
Comment #72
larowlanBlocker is in
Comment #73
jhodgdonApparently the patch in #70 fails tests, so setting to Needs Work rather than Active.
Comment #74
benjifisherAt least some of the errors came from this line:
getUntranslatedString()is a function (method), not a variable (property).I started to review the patch in #70. The code in the new helper function seemed complicated, and I wanted to suggest ways to simplify it. In the end, I decided to implement those suggestions myself.
The first loop in that function did too many things. In my version, it just counts the number of times each label is used. (Not quite: it also stores some data for later.) The version in #70 was complicated because it handled multiple columns and, to a lesser extent, because it started to generate labels.
I made some other minor simplifications:
continue;to the first loop instead of starting witharray_filter().array_pop()instead ofarray_shift().I still like the idea of counting the number of labels after the
array_pop(), but since you already decided that was too tricky, I will leave it as is. (See my comment #40.)Comment #75
benjifisherI updated the issue summary, mostly the Remaining Tasks section. When we added and then removed a second blocking issue, we left a few changes un-reverted.
Comment #76
benjifisherI am adding the Novice tag since drafting a change record is a suitable task. Start with the release-notes snippet in the issue description, and copy over some of the screenshots. See also Contributor task: Write up a change record for a Drupal core issue.
I am also adding the tag for BADCamp, since I am attending that while I work on this issue today.
Comment #77
jhodgdonI like the new patch! Definitely cleaner and easier to understand than my last one.
However, there is a problem: It looks like the logic of whether to use "|..." or not is reversed. Screenshot:

As you can see, the Title field has no ... for "Vendor name", and the generic fields like ID and Comments all have the ... even though they have the same label across content types. Oops. Seems to be the correct logic for fields with columns, such as Image (alt).
Also as a note: when I tested it on simplytest.me with 8.8.x and the patch applied, the options were not sorted... Maybe their 8.8.x did not have the latest patch applied from the other issue? I guess I'd need to test it on my own machine to see. I may do that later.
Comment #78
jhodgdonI think this also needs a test.
Comment #79
benjifisherI also forgot to upload an interdiff. I will fix that one now, the backwards logic when I. have a chance. (I was tired last night.)
Comment #80
benjifisherThe backwards logic is because I switched from the variable
$multipleto$single_labeland forgot to make the corresponding changes.The attached patch fixes that and is also a little more frugal in the data that is stored in the first loop and used in the second.
Comment #81
jhodgdonNot quite! As noted in #77, the with-columns case was correct before. Now it is reversed!
Comment #82
jhodgdonWe definitely need a test!
Comment #83
benjifisherSorry, I am rushing. Yes, we need a test. Here is another patch.
Comment #85
jhodgdonStill rushing. :) This is what is in the latest patch, for the column case:
That last line should have .@column in it, I think? The only difference should be whether the |... is there or not.
Comment #86
jhodgdonComment #87
benjifisherThe attached patch fixes the problem pointed out in #85. It also fixes a coding standard that the testbot caught.
When there are multiple labels and multiple columns, this patch uses
'@label (@column)|… [@field.@column]'. Do we want to change that to'@label|… (@column) [@field.@column]'?I have also added a test.
I tried using a unit test for the new (protected) method. I was willing to mock all the objects needed for the constructor and use ReflectionClass to test the protected method, but I stopped trying when
$this->t()complained that the container was not initialized. I decided to use a kernel test instead, modeled on EntityReferenceSelectionSortTest.I am not sure it makes sense to define the node types in the
setUp()method. I am happy to rearrange the code if someone will advise me.Comment #88
jhodgdonRegarding the format of the labels, I don't feel strongly about it, but I think it's good as it is.
The new patch looks good.
It seems to me that defining node types should be done along with defining the fields (both in setUp() perhaps?)? But I think it is OK as it is. The test seems fairly thorough...
Maybe we could add a bit to it though, to verify it works with built-in fields? For instance, change the label of the Title field on one of the bundles to "Alternate title", and verify that the title entry works (has Title... in it), and also verify the entry for something like the node ID built-in field.
And also should we verify that the sort order is correct in the test? Because one of my earlier screenshots (#77) didn't have the sort order right (although the patch was fine, that was just a simplytest.me glitch). But maybe we don't need that test, I don't know.
Comment #89
benjifisherI guess EntityReferenceSelectionSortTest tests a different sort order. I should be able to test the sort order, but then I will probably want to rename the test class.
I thought of changing the title label, but (after a small amount of digging) could not figure out how to do it. Maybe just pass the right option to
NodeType::create()? Any hints?Comment #90
jhodgdonHm, let's see. In the UI, you go to Edit on the content type, and update a field in the form. Let's see what happens when you save the form... Some snippets from NodeTypeForm:
That should help?
EDIT: I guess we don't need $type though, because we know what the bundle IDs are ($type->id() here, but known strings in the test).
Comment #91
webchickSorry, I'm coming into this issue 90 comments in. :P (I have NOT read the previous comments yet; this is a "evaluating this as a new user" first impression comment.)
But comparing "before":
and "after":
The after seems WAY more confusing, at least to me:
1) No idea what |... means (@benjifisher did explain it on the UX call but that would not have been remotely clear to me, and also doesn't seem to resolve the initial bug report of "I expect to see 'vendor' here but instead I see 'recipe'." At minimum I think we need some help text and/or swap it out with another piece of punctuation.)
2) Now we're also exposing the raw field machine names, thus doubling the cognitive load of the decision here. (Especially because some of those, like "nid" weren't named by the site builder in the first place.) The rationale given for this was that sometimes there might be more than one field called "Description," so the machine name helps disambiguate.
Something that seems to solve both of these problems though is instead of exposing machine names or adopting punctuation groups, where the field is ambiguous instead prefixing it with its entity/bundle name. (And limiting those to only the entity/bundle types that are referenced by the field itself.)
In other words, on Drupal.org's issues' "Related issues" sort setting, none of the fields would need disambiguation, because you can only ever reference Issue content types with that field. So it'd just be a simple list of field labels, same as it is today.
Versus in a hypothetical "Project type" entity reference field on a "Release" node, you would see single field labels for everything except for "Title," and for that, and in the drop-down you'd see X separate selections:
Theme: Theme name
Module: Module name
Theme engine: Theme engine name
...
That seems to satisfy the request in the OP, without also introducing a lot more things to consider here, and requiring extra documentation for what should be a "simple" select list decision.
The one thing @benjifisher raised in the meeting is that if a site builder has made some questionable choices and for example set up separate fields for "field_theme_engine_description" and "field_module_description" and so on, you'd see quite a lot of duplication in the list... but even still, "Bundle/Entity first: Disambiguated thing" is a pattern we use lots of other places (Views UI, Permissions, etc.) so that seems preferable to introducing a one-off pattern here.
Happy to be told I'm wrong/missing details/over-simplifying/etc. This was just my first time eyeballing this either ever or at least in awhile, and so wanted to get my thoughts down.
Comment #92
jhodgdonOK... Would have been nice to have that suggestion back in February (comment #16) when we first brought this to a Usability meeting. But that's OK.
So... if we're bringing back to the table how to format this...
Personally, since this form is only for site builders, when I'm building a site I would rather just see the machine names -- and yes, I do realize that I am not the average site builder, although I spent a number of years employed doing mostly that. The advantage of the machine names is that they are unambiguous -- which is why behind the scenes, that is what the values are for this dialog. And as another note, in the dialog from Field UI for adding an existing field to a new bundle, all you see is the bundle label and field machine name (NOT the field label). The issue summary has a list of other UIs where you are choosing fields... some use only the labels, and some use only the machine names, and I agree, there aren't any others that use both.
Another note: using "Bundle: Label" or something like that -- will not work unless we change what the values are for the dialog -- we can only have 1 entry for a given field machine name. So we cannot have both "Vendor: Vendor name" [one alias for the title field] and "Recipe: Recipe name" [another alias for the title field] in the select list, because both of them have the same field machine name [title]. I mean, we *can*, but we would have to change more than just the labels for this select list.
So... Not sure what to do.
Comment #93
webchickYeah, I'm sorry, I must've been away for that one. :(
But I think regardless if you keep the machine names there or not... we still need one separate entry for each of the possible permutations. The OP (which I guess was you :D) says:
Anyway, it is very confusing to say "Recipe name" if you are trying to add a Vendor reference field on the Recipe content type.
"Recipe name |... [title]" still says "Recipe name" and not "Vendor," which is the keyword that people will naturally be scanning for when they mean "Vendor."
Comment #94
jhodgdonIf you have the machine name "title" instead of any of the labels, you will avoid all problems with ambiguity, and then you don't need permutations per bundle because there is only one machine name for each field.
Anyway... What you are asking for (permutations) will not work unless we do a lot more changes.
Right now, all we are storing in the field settings is the machine name of the field. You're asking for permutations, so they would select something like "Vendor: Vendor name" for the title field, and also have the choice of "Recipe: Recipe name" and "Page: Title", all for the title field.
So even if we have some kind of widget that allows us to have multiple labels for the same machine name (which this simple select would *not* allow, since they array key is the same, namely "title", for all 3 of these permutations), the next time someone came into this dialog to change the sort, we would have no way of remembering which permutation they chose.
Unless you're advocating saving the bundle they chose along with the field settings? Which seems silly, because it's only relevant to this particular, horrible, UI and not to the field setting at all.
So... I think we have a few options:
- Go with something similar to this patch, but fix it somehow so that it's clearer.
- Only show the machine name
- Keep the UI as it is in Core now
- Use something other than a select, like a tableselect, which has more room for columns and there we can list a column for the machine name, and a column that shows all the labels in use for that field and which bundles it's in and whatever else we want
Thoughts?
Comment #95
webchickOk, if we have to list machine names here, then why not make the label "
<em>Various</em>[title]" or something. Then it's clear without an "answer key" what is being implied there.Ironically, on the UX call https://youtu.be/lyZwmMCTcuU (2nd half) the idea of using a tablesort pattern like Views UI did come up. :) Feels like overkill for one little setting, though. Another idea that had some support was incorporating optgroups somehow. Maybe:
...or something.
Basically this all spun out of "what the heck does
|...mean?" so if we could solve that issue, we might be able to let the rest of it slide. (Still unfortunate about exposing machine names here... but it is at least a site builder UI, not a content author one. But we don't expose e.g. "nid" on any other Field UI, Views UI, etc. screens [Do you even know what that is unless you've been spelunking in the database tables?], so it's pretty weird to do so here.)Comment #96
jhodgdonAn optgroup for the multiple-label fields sounds like a reasonable idea, to group them together and highlight that they're different. I think it should just be called "Fields with multiple labels".
I'd be fine with saying "Various labels" instead of "One Example|..." too. That is an excellent idea [I like putting "labels" on there as it makes it clearer what "various" means -- we're trying to go for clarity!). That would also group them together (all the "Various" would alphabetize the same). Does an EM tag work inside of select lists?
So... Let's try out a few of these and make some screenshots (easier to critique and compare than hypotheticals, IMO). I will probably have some time tomorrow or Friday to do that. Not today.
Comment #97
webchickThose labels sound like vast improvements over mine, +1. :)
GREAT question! And apparently... nope. :P Oh well.
Comment #98
jhodgdonOK, how about if we do both? We can put in the opt group called "Fields with multiple labels", which will indent the "various" ones, and also use the label "Various labels [machine_name]" within that opt group, so that the format matches the other items in the list.
Comment #99
webchickSure, we could try that. I don't suppose I can also convince you to only show the machine name where a field has various labels? ;)
Comment #100
jhodgdonI personally think that having both the label and the machine name is helpful, at least for some site builders. You see both on the Manage Fields page... If it is in [] it at least indicates to people that it is additional information, rather than the primary thing they should look at. Also, then all the fields shown have the same format. Anyway... I can make a few patches trying these options out, and we can see what we think.
Comment #101
jhodgdonOK, I've made a new patch.
With the option group, there was a choice:
a) I could let the opt group be alphabetized along with the fields, so it appeared in the middle of the list (under F for "Fields with multiple labels"). I didn't like that.
b) I could put it at the top. I opted for that.
c) We don't have the option of putting it at the end yet -- see #3069844: Provide additional options for sorting the options in Select form elements... but could postpone (again!) on that.
Anyway, here is the patch, interdiff, and a screenshot. Test in the patch passes locally...

Comment #102
Mixologicdrupalci snafu. requeuing last test.
Comment #104
aaronmchale(I missed the UX call on Tuesday, so sharing some thoughts now)
For fields with multiple labels, here's an idea: display those labels in a comma separated list, and chop off the list after a certain number of characters to avoid it becoming too wide, for example "Recipe name, Title, Vend... [title]". I'm not sure if that's any better or worse than the "Fields with multiple labels" idea discussed above, but it's at least an improvement on the "|...".
Maybe combine the two, so stick with the "Fields with multiple labels" opt-group, but instead of each field showing simply "Multiple labels" (which I worry could be slightly confusing and make it harder to locate the exact field since people might not know or recognise the exact machine name they need), implement the idea I just suggested of a limited comma separated list with the machine name. Doing that could result in something like:
Fields with multiple labels:
Recipe name, Title, Vend... [title]
Description, Body [body]
Authored by [uid]
Authored on [created]
...
Comment #105
jhodgdonI like that idea! I wonder how many characters we should allow?
Comment #106
jhodgdonActually, on thinking about #104 more, I realized it wouldn't work, because of translations (the field labels can be translated).
What we could do though is make it look like:
Fields with multiple labels:
- Most common label, ... [title]
This avoids the confusing "|..." replacing it with ",...", and then because it's underneath the "Fields with multiple labels" header, I think it is more understandable what is going on?
That's kind of a merge of parts of the patch in #87 and parts of the latest patch... From the patch in #87, we would add in the option group stuff (with sort start of 2), and change the | to a comma (the latest patch gets rid of the counting, so it's less of a change to start from #87 I think).
Also, we need to make sure that the items in the option group are sorted. I am not sure if sorting is inherited from the outer option list or not.
I'll work on a patch later today.
Comment #107
jhodgdonOK, here's another patch. Interdiff is from patch in #87.
This patch:
- Groups fields with multiple labels together in an optgroup at the top
- For those, uses "Most common label, ... [machine_name]" format
See what you think... here's a screenshot:

Comment #108
aaronmchaleThat's a fair point, and the approach of only displaying the most common one sounds like a good idea in that case.
That being said, a workaround could be to get each field label, translate them individually, so you end up with the translated plain-text strings and not translation objects, then concatenate them and chop off any overflow. Although that does seem almost like unnecessary computing power when displaying the most commonly used label would be also be a good approach.
Comment #109
jhodgdonWe are trying to avoid translating too early... see several comments early in this issue about that. That is why we did #3065903: Add label sort ability to Select element so the option labels could be sorted as late as possible in the process, and then came back here to use its result.
Comment #110
aaronmchaleOk yeah that sounds fair
Comment #111
benjifisherFor the record: between Comments #90 and #91, we discussed this issue again at the weekly Usability meeting. The recording is at Drupal Usability Meeting - 2019-10-08.
Another idea that came up was to limit the list to the selected target bundles. In fact, some participants in the call assumed that it already worked that way.
In many cases, an ER field is restricted to a single bundle. In that case, the contentious part of this issue would be irrelevant if we implement that idea. Having the list sorted, on the other hand, is always a good thing (even though it is not mentioned in the title of this issue).
I think that limiting the options to selected bundles will be complicated. It is not as simple as using the
#stateskey in the form array. Unless there is an easy way that I have not thought of, we should work on this in a separate issue. I think the Examples module has code that is close to what we need. I am trying to think of other places in core where we use an AJAX callback on a form. Maybe on the node-edit form, where we "Add another"? But that is a submit element, not just a changing selection in a set of radio buttons.Comment #112
jhodgdonI don't think it's too complicated to limit the options to the selected bundles -- just requires a little Ajax, so that when those checkboxes are checked or unchecked, we recalculate the options?
Comment #113
benjifisherMy previous comment accidentally changed the target version. I am reverting that change.
Yes, a little bit of AJAX should do it. I have not done that sort of thing before, which is why I am trying to think of existing examples in core.
Comment #114
aaronmchaleYes that should be possible with the existing AJAX API.
Comment #115
benjifisherI was worried about making sure the form still works without JS. As I said, I have not done much with AJAX.
Then I realized that it is very easy, after all. Not only does this form already use AJAX: it already uses AJAX when the user changes the selected bundles. To see this, enable the "Create referenced entities if they don't already exist" option and choose two or more bundles.
I will supply a patch later today.
Comment #116
benjifisherThe attached patch does two things:
#sort_optionskey).It probably needs updates to the tests, but I am setting it to NR to see what the testbot says. (I have not forgotten my question and @jhodgdon's answer in #89 and #90.)
As I said in #115, the form already triggers an AJAX call when there is a change to the selected bundles. The definition of
$selected_bundlesis not really new: I have just moved a line and changed the name of the variable in order to avoid a conflict.After (1), the problem that (2) solves is more obvious: when adding a content-reference field, the list of available sort options is empty except for the optgroup. Even with the patch from #107, the problem is pretty noticeable if you add a user-reference field.
Since this patch targets 8.9.x, I could not generate the interdiff using the
interdiffutility. Instead, I applied the patch from #107 to 8.8.x, rebased on 8.9.x, and usedgit diff.Comment #117
jhodgdonOh thanks! My original "patch with the optgroup" #101 did remove it when it was empty, but then that was lost when I did #107. Glad you restored that functionality!
Anyway, the interdiff looks good. I did have one question: If someone checks no content types (bundles) on the form, does that mean nothing can be referenced, or does that mean everything can be referenced? Because we definitely have some UIs where checking nothing means everything.
I'll give this a manual test sometime soon and make screenshots.
Comment #118
aaronmchaleI don't think it's possible to not check anything, I tried that recently and the bundle selection configuration is required. It is a bit unfortunate though that there isn't at least a way of telling ER you want all bundles.
Comment #119
jhodgdonThe patch above doesn't apply... Something wrong there. It seems to be more of an interdiff? Way smaller than previous patches.
Comment #120
benjifisherHere is another attempt at the patch I meant to upload in #116. See that comment for the interdiff.
Comment #122
jhodgdonI guess I'll wait to review/test until the automated tests pass.
Comment #123
benjifisherIt is not surprising that the patch in #120 fails some tests. It changes the behavior of the form, so that only fields from the selected bundles are available as sort options. Initially, no bundles are selected, so no fields are available.
We might want to spin off this change into its own issue. But I will not do that yet.
The attached patch changes the tests, selecting all the available bundles before looking for sort options. The kernel test passes locally. I have not set up my local environment for functional tests, so I am not sure that the other one will pass.
There is more work to be done on the tests, but first let's see if I can get them to pass.
Comment #124
benjifisherI am still moving cautiously, since I have not set up to run the JS tests locally. This patch just removes a step from the test that is now redundant. The patch in #123 selects all available bundles, so we no longer need the lines that select the first available bundle.
Comment #125
jhodgdonLooks like the tests are passing now! Also no coding standards violations. So that's good.
I've reviewed the patch itself (not interdiffs) in detail. It's looking very good; haven't done a manual test this time. I found a few things to address (some are definitely nitpicks):
a) core/lib/Drupal/Core/Entity/Plugin/EntityReferenceSelection/DefaultSelection.php
In this comment line, there should only be 1 space after the .
b) Up a bit from there in the main form method, I think we could use a comment to explain why #sort_start is 2 (which is to make the optgroup with the fields with multiple labels stay at the top):
Hm.... Actually, that is not always a good idea, because there might not be an optgroup at the top. So, I think we need to make #sort_start 1 if the optgroup is not there, and #sort_start 2 if the optgroup is there. I'm not sure how to detect it, but maybe the return value of calculateSortOptions needs to be ['#options' => (the options), '#sort_options'] => (1 or 2)], and the return value would be added using += to
$form['sort']['field']instead of being put directly into its#optionselement? Hope that makes sense...c) in calculateSortOptions:
Would this be clearer as:
Not sure which is better?
d) I think there maybe should be a space between the comma and the ... in the labels: "Most Common Label, ... [machine_name]" ?
e) The changes to FunctionalJavascript/EntityReference/EntityReferenceAdminTest.php make sense to me (and the test passes, so good!).
f) The new test core/tests/Drupal/KernelTests/Core/Entity/EntityReferenceSelection/EntityReferenceSelectionLabelTest.php also looks good. But I think we need to also test the case of selecting a subset of the bundles, and verifying that the options are correct there too?
Comment #126
benjifisher(a) Fixed.
(b) and (c): I briefly considered defining
$group_keyin the calling function, passing it tocalculateSortOptions(), and then checking$options[$group_key]in the calling function. I decided it made more sense to use your suggestion of returning an array with keys'#options'and'#sort_start'(a piece of a render array). Come to think of it, we might just return a complete render array. Given that, I did something similar to your suggestion for (c).(d) I agree. Fixed.
(e) Check.
(f) Still to-do, along with other updates to the tests. The attached patch only changes the form.
I decided that it does not make sense to present a "Sort by" select list where the only option is "- None -", so I added a
'#states'key.I also broke a few long lines to keep them under 80 characters.
Comment #128
benjifisherIf we are going to add a space as suggested in #125(d), then we need to adjust the tests as well.
Comment #129
jhodgdonThe bot likes this latest patch, and there are no coding standards violations.
I've reviewed the interdiffs since my last thorough review (#125). It looks great!
Nitpick:
Comment should end in . not ,
I would have just fixed that, but there is more to do:
I'll give it a manual test now and make a screenshot.
Comment #130
jhodgdonManual testing results: Looks good to me!

- When I uncheck all bundles, the Sort options select list goes away.
- When I check just one bundle, the title label from that bundle is shown for [title], and the list is correctly alphabetical.
- If I uncheck that one and check the other, the label from that bundle is shown for [title].
- When I check two bundles with different title labels, the "Fields with multiple labels" optgroup appears at the top. Here's a screenshot of that:
I'll add that to the issue summary and clean it up a bit. Seems like the only To Dos are in #129.... but I think the Usability group will review this issue later today at the weekly UX meeting so we'll see what they say.
Comment #133
webchickOk, @benjifisher brought this to UX meeting today w/ @DyanneNova, @crkrina, and myself (recording will be at https://youtu.be/frCRPmHyq-Q once finished processing).
His demo was great; he showed how the current select list is a complete CF with multiple problems, and also shows how the current patch vastly improves upon it, in several ways:
#1: The default "Sort" list is, ironically, unsorted. LOL. So fields are in whatever order, and good luck to you trying to find what you need, even if it's not one of these more ambiguously named fields. This issue instead puts them into alphabetical order, and even accounts for post-translation labels. Wonderful.
#2: The patch makes it so the "Sort" drop-down doesn't show up until you've selected one or more content types to reference. Awesome! This is a core UX concept called progressive disclosure, where you hide complexity until the point at which you actually need it. Great stuff.
#3: EVEN MORE AWESOME, the patch limits the choices in the select list to only fields that are attached to the selected content types. So you cannot sort by "Vendor SKU" in a situation where you've selected "Article" and "Recipe" to reference, but not "Vendor." AMAZING. A+++ would select again.
So all of that stuff is great, awesome stuff the UX team is very +1 on.
Now, though, we get into the more contentious parts. ;)
#4: Ambiguous field names. We've made some great progress since the last showing, in that these are clearly called out into their own section (optgroup), and we use a common "plain English" pattern of ellipsis to indicate "more than one of these."
HOWEVER. This treatment pulls the fields out of the alphabetical "flow" — now you scan your newly nicely alphabetized list around the R section for "Recipe name" and don't see it. Scratching your head, you try "Title." Also don't see that. So then you start flipping around, and eventually find the optgroup thing and, if you're lucky, finally see the label you're looking for. (There's some cool logic Benji's added to increase the odds of this, where "majority wins" and if 2/3 content types call it "Title" you'll see "Title ..." But in case of a tie, it's a toss-up.) This actually happens in the meeting, albeit for other reasons, so you can feel the user pain in "real time." :D
What I think we really want to see here instead (in the case of Basic Page, Article, and Recipe name selected) is:
- (other alphabetical selections)
- Recipe name
- (other alphabetical selections)
- Title
- (other alphabetical selections)
Not two Titles (one for Basic page and one for Article). Not only Title (and Recipe name is not in the list).
It was explained that this doesn't work, because Form API does not allow duplicate keys, and each of these ultimately resolves down to the key of "title". @DyanneNova found a "Closed (works as designed)" issue to this effect at #1048816: Duplicate values not allowed for select options. However, there are also some workarounds posted there that might well be worth looking into, because then:
There were some other ideas brainstormed around this if duplicate keys are an absolute no-go; for example, disabling the duplicate options and saying something like "Recipe name (choose Title instead)" but this once again just adds more complexity/potential misfires. @ckrina also pointed out that ultimately, if we need to communicate more information than can be communicated in a simple select list, something like https://www.drupal.org/project/linkit is a far better UX pattern. But we'd need to introduce this pattern into core first in order to use it, and this will likely prove a tall order if the accessibility research at #2346973: Improve usability, accessibility, and scalability of long select lists is any indication.
#5: This patch also exposes the underlying machine names for every field. This adds ultimate clarity to help with choice selections in case of duplicate fields (Benji's demo had 3 fields called "Date" for example, that are very confusing to deal with under the old UI).
HOWEVER. It also leads to much more "visual clutter" on what should be, once again, a fairly simple "select and go" setting. (Though the "before" patch version has all kinds of issues enumerated here, it looks much nicer/less intimidating to use for this reason) The desired outcome would be to only show machine names where needed for disambiguation. It was explained that this is tricky because ambiguity might be introduced post-translation. (For example, several Inuit words that all get resolved down to "Snow" in English). We did not seem to have any bright ideas for how we might resolve this one, though it does seem like it's trying to solve a different (though related) issue of "What happens if there are multiple fields with the same label?"
---
All that to say, it seems like this one issue, which is now at 130+ comments, is trying to fix at least 5 underlying issues, and at least 3 of those are entirely non-controversial and should definitely be added to core and make things better for everyone, while we continue noodling on the less obviously awesome paths. Is it possible to split 1, 2, and 3 into their own issue(s) that could be RTBC and committed quickly, and perhaps 4 and 5 as well, and turn this instead into a "meta" issue for improving the field in general? Then we could better hone in on the places we need to come to agreement on without holding up great fixes that just make sense for all scenarios.
Comment #134
jhodgdonOK, we can do that. I will take a stab at separating it out tomorrow if no one beats me to it.
Comment #135
jhodgdonI have separated this into several child issues:
Comment #136
aaronmchaleUnfortunately I couldn’t make the recent
UX meeting, but I think the outcome of splitting out the issue makes sense.
Comment #138
solotandem commentedAlso see
#3132676: Use progressive disclosure on sort direction element of entity reference fields
created as a child issue of
#3089523: Use progressive disclosure to hide Sort options on entity reference fields until bundles are selected
instead of this issue.
Comment #140
jhodgdonI had a brief discussion with @benjifisher in Slack today. As a result, we closed 2 of the child issues as Won't Fix. The other 3 have already been Fixed. So... this Meta issue is done, as best we can, and we have a much more usable Reference Field UI for the most common use cases.