Problem/Motivation
Currently, if you have a view with an exposed filter, and you expose the operator for it, the label is hard-coded to "Operator". The only way to change it is to implement a hook form alter, which is not accessible to site builders, and will likely break if the configuration for the view changes.
An example use case for this would be when you have multiple operators exposed, and would like to have the labels be more explicit as to which one is is for which filter, so that the users can clearly identify them.
Proposed resolution
When a filter has Expose this filter to visitors, to allow them to change it and Expose operator enabled, display a new "Operator label" text field to configure the label for the Operator select element on the exposed filters form.
This will make it configurable via the UI so that site builders can configure it, and export it with the rest of the view.
This would work exactly how the Label for filters currently works. What ever text is configured will be used as the label for the operator select element.
Remaining tasks
Write patchWrite update pathWrite update path testWrite test for the new settingReview- Accessibility review
- Commit
User interface changes
A new textfield element is added to the configure filter form, which displays only when both Expose this filter to visitors, to allow them to change it and Expose operator are enabled.
Configure filter form before

Configure filter form after

Exposed filter form before

Exposed filter form after

API changes
None.
Data model changes
New views data type schema operator_label.
Release notes snippet
Views exposed filters that also expose the operator are now able to configure the label for the operator.
| Comment | File | Size | Author |
|---|---|---|---|
| #61 | 3120627-nr-bot.txt | 144 bytes | needs-review-queue-bot |
| #60 | Screenshot from 2022-12-15 15-25-59.png | 120.29 KB | gaurav-mathur |
| #60 | Screenshot from 2022-12-15 15-15-26.png | 136.39 KB | gaurav-mathur |
| #60 | Screenshot from 2022-12-15 15-13-47.png | 127.99 KB | gaurav-mathur |
| #52 | 3120627-52.with-2625136-btwn-op.png | 87.47 KB | dww |
Issue fork drupal-3120627
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 #2
manuel garcia commentedHere is a working patch as well as the (untested) upgrade path, which should serve as a good starting point.
Comment #3
abhisekmazumdarHi @Manuel Garcia this will be a good option for customization.
I applied the patch and It works flawlessly. Thanks for the patch.
Comment #4
abhisekmazumdarComment #5
dwwGenerally +1 to this feature. It's always hard to justify adding yet more settings to the Views UI. ;) But this does seem like the sort of thing that folks want/need to customize (I certainly have), and forcing them to use
hook_form_alter()for it is a burden.However, the RTBC is premature. At the bare minimum, we need a test of the new feature. We should probably also have a test for the post_update function (thanks for adding that!).
I'll closely review the rest of the patch later (time permitting).
Thanks,
-Derek
Comment #6
manuel garcia commentedThank you @abhisekmazumdar and @dww for having a look at this, I'm very pleased to see there is interest in doing this.
I agree its still early for RTBC, but thanks for that @abhisekmazumdar - I'm glad it's already working :)
I had a go at the upgrade path test, which for now I have not been able to get to pass locally:
So to me the test is actually catching a valid bug in the upgrade path. The post update function does look correct to me though, so perhaps its something else we're missing?
Comment #8
andyf commentedNit: you can use a type declaration on the closure parameter to have the language enforce it.
I don't think you can set nested values in this way on the config entity itself; that's provided by
\Drupal\Core\Config\ConfigBase::set(), ie you can use it with config returned from the config factory.Thanks!
Comment #9
manuel garcia commentedThanks @AndyF for the review
re #8.1 - Cleaner that way, thanks!
re #8.2 - I'm not entirely sure I understand, but I based this on views_post_update_limit_operator_defaults which does something very similar, so I assume it is the correct way to do it?
Cleaning up a bit the update path test etc in this patch, as well as #8.1
Update should test still fail.
Comment #11
andyf commentedThanks @Manuel Garcia!
Ooh, er yeah, good point! I've done a little digging, and I actually wonder if that update really works. I commented out the following line locally from
views_post_update_limit_operator_defaults()and yet\Drupal\Tests\views\Functional\Update\LimitOperatorsDefaultsTest::testViewsPostUpdateLimitOperatorsDefaultValues()still passes, so I wonder if that's just a bad model to be copying?FWIW I made the attached little script and it seems that
test2()andtest3()successfully update the view.Thanks
Comment #12
manuel garcia commentedThanks @AndyF again for the info. Finally figured it out, I looked at other post update functions updating views in core (for example content_moderation_post_update_views_field_plugin_id) and noticed that they were doing it differently, so I followed their pattern and now is working as expected.
So yay for tests. Also
views_post_update_limit_operator_defaultsis indeed incorrect, and we should fix it.This should come back green, next step is add test coverage for the feature itself.
Comment #13
manuel garcia commentedSetting to needs work for adding test coverage to the new option.
Comment #14
manuel garcia commentedHere is the test. I spent a bit of time trying to figure out where it would make the most sense to have it, and in the end I decided for
\Drupal\Tests\views\Functional\Plugin\ExposedFormTest. Happy to move it around if it should go somewhere else though :)Comment #15
manuel garcia commentedComment #16
neslee canil pinto@Manuel, #14 applied cleanly and works has required. Moving to RTBC.
Comment #17
dwwMostly looks good, thanks! A few nits, and a few concerns of real substance:
One could complain this doesn't really tell us much. ;)
Raw
assertText()always makes me nervous, since there's a chance we'll get false positives if that text appears anywhere else on the page for any other reason. I always prefer more targeted assertions if possible. E.g. an xpath that finds exactly the label we're expecting...I guess all this is okay. It's mostly testing that the Views UI works, not that this feature works. ;) Many (most?) views tests directly twiddle the view config. E.g. something like this:
I don't feel super strongly about it, and what's here is more test coverage (which is almost always welcome), but it's also sort of out-of-scope testing, and perhaps duplicate (sort of) with existing tests (#CitationNeeded). /shrug
s/upgrade/update/
Copy/paste error, that's not what this test is testing.
This test is now depending on the fact that
core/modules/views/tests/fixtures/update/views.view.test_exposed_filters.ymldoes *not* define the new 'operator_label' key. Someone might regenerate that view for other tests (e.g. tests that the view was originally added for, etc). Seems a bit fragile and dangerous to go this route. We should either:A) Add some comments to views.view.test_exposed_filters.yml explaining that this test now depends on this fact so that it's less likely someone will accidentally "fix" the view in the future, breaking this test's assumptions.
B) (Probably safer): Add another default view specifically for this test, something like "views.view.test_exposed_operator_label_update.yml" or something that explains it's a legacy view to test the update path. Then there's no chance someone will "fix" it, since it'll be a dedicated view only used by this test.
Doesn't look like we ever directly modify
$display, so I don't think we want to iterate with references here. Unless PHP is weird and the fact that we're getting references to$filterbelow requires references here, too. Would be curious if this works with just$display...Thanks,
-Derek
p.s. Re: #14: Yeah, that seems like a reasonable spot for where to put this test. The layout of Views tests is a bit weird (some make sense, some do not), so it's not easy to make good decisions based on prior art. But +1 to your choice of
\Drupal\Tests\views\Functional\Plugin\ExposedFormTest. Since this feature is entirely UI-centric, I think we're going to need Functional tests for it (lots of Views can be tested via Kernel tests, which are preferred if possible, but not for this), and since it's about the exposed form, we should keep it close to the other tests for that functionality.Comment #18
manuel garcia commentedThanks @dww for the excellent review!
Re #17:
testExposedOperatorLabel()'s execution time by ~25% on my machine which is always a good thing :)Failed asserting that an array has the key 'operator_label'.if we don't do&$display... I think it makes sense, since we are altering the filter inside the display array, then$view->set('display', $displays);. I checked how we're doing it elsewhere out of curiosity, and we're doing something similar onviews_post_update_entity_link_url(),views_post_update_filter_placeholder_text()andviews_post_update_cleanup_duplicate_views_data(), so I suppose it should be safe.p.s. Glad the test is in the right place in
\Drupal\Tests\views\Functional\Plugin\ExposedFormTes:)Comment #19
dwwThanks! Looking really close. Sorry I didn't notice these before, but a few more minor nits/concerns:
Do we want the test to ensure that the operator label is set on this (non-exposed) filter, too? If not, maybe we don't want it in this view at all? Or maybe we want to change the post_update to ignore non-exposed filters? TBD.
This is irrelevant to the test, and should probably be removed.
Comment #20
manuel garcia commentedThanks @dww for the review, valid points.
First, patch needed a reroll due to #2989745: views_update_8500() inlines configuration changes instead of this being done on config save for bc - I had a look at the changes introduced there, and they seem very related to what we're doing here, does that mean we should change our
views_post_update_set_operator_label_defaults()function as well? @seeViewsConfigUpdater::processOperatorDefaultsHandler()Comment #21
manuel garcia commentedComment #22
manuel garcia commentedRe #19.1:
I played around a bit and noticed that the expose configuration is included in the view no matter if the filter is exposed or not. So in my opinion we should be adding the default value for the new configuration to every filter. I have updated the update test to reflect that.
Re #19.2:
I agree, removed it.
Also in this patch:
views_post_update_set_operator_label_defaults()to make use of what was introduced on #2989745: views_update_8500() inlines configuration changes instead of this being done on config save for bc which made sense to me. Let me know if I should roll back this change though :)test_exposed_operator_label_updateview so it has all the current configurations.Comment #25
manuel garcia commentedUpdating all the views...
Comment #26
dwwRe: #22
19.1: Sounds good, thanks!
19.2: 👍
Also.2: Seems like the right thing, yeah. I need to read #2989745: views_update_8500() inlines configuration changes instead of this being done on config save for bc
Also.2: /shrug. Generally test views don't need complete config, only the config for the stuff they care about. The point of this fixture is a known pre-update starting point. But whatever, I don't care much either way. This is fine as-is.
Re: #25: Oh right, good point about updating all the default views that core ships. ;)
A few final concerns before I can sign off on this. I'd fix these myself, but then I couldn't RTBC, so I have to set NW:
Something about the git diff settings here are confusing git into thinking your new view is a copy of the demu_umami view, which is making this patch hard to review. What if you do
git diff -C95%or something? Then it shouldn't consider this a similar file to be copied and will list the new thing as a whole new file (which should be a lot easier to review/read).Now unused. https://www.drupal.org/pift-ci-job/1641713 shows:
Not just 'all exposed filters' anymore...
Thanks/sorry!
-Derek
Comment #27
manuel garcia commentedThanks @dww again for the review!
Re #26.1 Wow first time I'm seeing this very strange, I checked and I couldn't find a way to configure the default value for --find-copies though...
In any case, I used
git diff -C95%for this patch which has done the trick, so thanks for that.Re #26.2 Oops, good catch, fixed.
Re #26.3 Yup, fixed.
Comment #28
dwwSweet, thanks! I can't find anything else to complain about. 😉 Let's see what the core committers think. 🤞
Comment #29
lendudeNice. Big patch but the actual change is quite small.
Interesting. Weaving this into the config update for a different issue will make this helper class VERY hard to clean up let alone ever remove. The hope would be that we can clean/remove this once all the associated update hooks have been removed, but weaving updates into each other would make this very hard to track.
I think we would need to give this its own method that is tightly coupled to the update hook, but this is new ground, so not sure how others feel.
Comment #30
dww@Lendude re: #29: 👍Now that I've read commit 663762f38d from #2989745: views_update_8500() inlines configuration changes instead of this being done on config save for bc, a separate protected method for this is probably more true to the design intentions of ViewsConfigUpdater, and will indeed make it easier to untangle later. Thanks for raising that.
Comment #31
manuel garcia commentedThanks @Lendude for having a look and rising that issue, makes sense. Let's see if I am understanding this class correctly... is this what you meant?
Comment #32
lendude@Manuel Garcia yeah that looks great.
This will make it easier to remove the right things in D10. Since all these updates are probably going away in D10, I don't think it is a big deal right now, but when we start adding more updates to this in D9 (some of which might be removed in D11) we want do have the right pattern for this set so we can just remove methods and not have to refactor the whole class to find code that is still relevant.
We might want to think about adding some @see comments to that class to make it clearer which method is coupled to which update hook, but that is way out of scope here :)
Comment #33
dwwYup, #31 definitely addresses #29/#30. Back to RTBC.
Thanks!
-Derek
Comment #34
dwwEek, whoops, was looking at the interdiff, not the patch. You forgot the
git diff -C95%so the weird diff returned. Would you be willing to re-roll for that?Sorry/thanks!
-Derek
Comment #35
neslee canil pintoRerolled the patch and added interdiff
Comment #36
dwwThanks for the re-roll, @Neslee Canil Pinto. I haven't fully verified the re-roll, but a few concerns with the interdiff you posted:
Not sure what this has to do with this issue. Seems like an out-of-scope (but legit) documentation fix for an existing comment that's wrong?
This shouldn't be here, either, I don't think...
Comment #37
manuel garcia commentedOK here is a reroll of the patch on #31 using
git diff -C95%. The interdiff on #31 is still valid.Re #36.1 I introduced this change on #31 - the change was to remove what seems to be a copy paste error. That description is on
needsEntityLinkUrlUpdatewhich was probably copy/pasted to createneedsOperatorDefaultsUpdateand then forgotten to update it. I thought I'd fix it here as I'd feel silly opening a new issue just for this. Happy to remove it though :)Comment #38
dwwRe-reviewed #37. LGTM. I dunno about #36.1. I tend to prefer Just Fix It Already(tm), but core committers tend to get really set on scope management. I guess we'll see what happens. 😉🤞Hopefully we can leave it as-is, but maybe we'll have to split that out to a trivial follow-up. /shrug
Thanks!
-Derek
Comment #40
xjmNice work on this feature! I think it could use a usability review.
The latest patch also doesn't apply to 9.1.x, so it needs a reroll.
Comment #41
manuel garcia commentedRerolled, three-way merge did the trick.
Comment #43
dwwhttps://www.drupal.org/pift-ci-job/1672597 is indeed a legit failure. Looks like perhaps the test is relying on an update fixture that's now gone in D9?
Comment #44
dwwRe: UX review, added this to the agenda for #3131774: Drupal Usability Meeting 2020-05-05
Comment #45
manuel garcia commentedIndeed valid fail, updating the fixture that the test uses here.
Thanks @dww for adding this to the usability meeting agenda!
Comment #46
dwwInterdiff looks great. Bot is now happy. RTBC once the UX review is satisfied.
Thanks!
-Derek
Comment #47
benjifisherWe discussed this issue at the #3131774: Drupal Usability Meeting 2020-05-05.
Making the operator name configurable seems like a good idea. I guess the usability issue is whether it is clear what the new "Operator label" text field affects.
Before giving a usability review, we would like to see some further updates to the issue summary, so I am setting the status to NW for that.
Besides adding the highlighted text field, the patch seems to move the "Expose operator" checkbox from the first column to the second. That puts it closer to the additional controls that are unhidden when it is selected, which is a good thing. But it should be called out in the issue summary, either as I have just described it or with a "before" screenshot.
The screenshot shows "Operator for content type" in the new textfield, and the list of options has the label "Your momma". Are these two supposed to match? If so, please describe and/or illustrate that in the issue summary. Please also come up with a more useful example. If the two are supposed to match, have you considered keeping the default label: that is, "Operator (Your momma)" instead of just "Your momma"?
Looking at this screenshot reminds us how crowded the Views UI can get. Personally, I wonder if it would improve things if the "Expose operator" checkbox and the additional controls that it enables were put inside a fieldset. Both of these are out of scope for the current issue, but worth keeping in mind.
If you can update the summary, then I will do my best to review it promptly.
Comment #48
manuel garcia commentedThank you so much for having a look at this @benjifisher !
Re: #47:
The patch does nothing of this sort, the "Expose operator" checkbox is already in the first column without the patch, at least if using Firefox.
I'm not sure which screenshot you're referring to, but whatever the user inputs into the text field when configuring the view will be what the select element label will have. It works exactly like the field label. I have added an example use case to the IS Problem/Motivation section.
Updated the IS to clarify as much as I could. I also added before / after screenshots to both the configuration form and the exposed filter form to make it easier to review. Let me know if you need anything else :)
Comment #49
manuel garcia commentedArgh messed up one of the screenshots, here is the good one.
Comment #50
dwwSweet, thanks @Manuel Garcia. Summary looks great. Removing that tag.
Also adding #2625136: Fix label visibility and add wrapper container for exposed numeric/date filters with multiple form elements as related, since both of these issues are dealing with the UI of the views exposed filter form. Even the 'After' screenshots here are still kinda whack, which is why we desperately need to fix #2625136, too. ;)
Comment #51
dww@benjifisher Asked for screenshots where both this and #2625136: Fix label visibility and add wrapper container for exposed numeric/date filters with multiple form elements are applied. Glad they asked! ;) I forgot that #2625136 is doing this anytime there's an exposed operator:
;) It visually hides the label for the operator (although leaves it for assistive tech), because the whole filter (label, operator, value(s)) is now wrapped in a fieldset (see below). Therefore, that bug fix potentially renders this feature request obsolete. :/ Whoops!
I added 2 exposed time filters to the /admin/content view on a local test site, both with exposed operators. Here's just #3120627:
Better than just "Operator" for both (raw core), but still confusing and weird.
Here's what you see once you apply #2625136-129:
Now that there's a labeled fieldset for the whole filter, we probably don't need a custom label for the operator at all.
Some possible paths forward:
A) Close this as "won't fix" in favor of #2625136. :(
B) Postpone this on #2625136, and once that's landed, modify this feature so that it can peacefully co-exist:
B.1) Add a 'Display operator label' checkbox (defaults to false to keep the 'invisible' behavior above) but that you can enable if you still want a custom operator label in there for something.
B.2) Change this feature so the default value is an empty string (for 'invisible') but if folks fill in a value, the code that's setting 'invisible' from #2625136 doesn't fire. Would probably want to change the label for the setting, and add a description.
C) Other?
Thanks/sorry,
-Derek
Comment #52
dwwThis is really a screenshot for #2625136, but here's the same view once you select an operator that requires 2 values (e.g. 'Is between'):
Comment #53
dwwPer @benjifisher in Slack, formally postponing this on #2625136: Fix label visibility and add wrapper container for exposed numeric/date filters with multiple form elements. Once that lands, we can decide what to do with this feature.
Thanks/sorry,
-Derek
Comment #59
damienmckenna#2625136 was committed, so reopening this.
Comment #60
gaurav-mathur commentedi refer some screenshot after use of exposed filter and changment in operator lable on drupal 10.1.x.
Comment #61
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. It either no longer applies to Drupal core, or fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".
Apart from a re-roll or rebase, this issue may need more work to address feedback in the issue or MR comments. To progress an issue, incorporate this feedback as part of the process of updating the issue. This helps other contributors to know what is outstanding.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #63
sokru commentedI don't think its postponed by anything, but needs a reroll.
Comment #65
xjmAmending attribution.