Problem/Motivation
This issue started as a Twig conversion issue, but it was determined fairly early on that theme_options_none() is not a good use case for the theme system in general.
Proposed resolution
Remove theme_options_none(), it doesn't belong in the theme layer. Replace theme_options_none() with an alter hook.
Remaining tasks
-
User interface changes
n/a
API changes
theme_options_none() has been removed. The functionality provided by theme_options_none() has been replaced by an alter hook, hook_options_list_alter() which allows altering the complete options list, including the label for the empty option.
#1988614: Adjust hook_options_list_alter() example in options.api.php to use $field->id() instead of $field->id
Comments
Comment #1
c4rl commentedTagging
Comment #2
geoffreyr commentedComment #3
swentel commentedHmm, the only theming function is theme_options_none which only returns translatable strings. It seems extremely overhead to me to convert that no ?
Comment #4
star-szr@swentel - Possibly, but at least it's consistent :)
Comment #5
jenlamptonYeah, let's convert it to get moved over to Twig, and then create a follow-up issue to do something better, maybe remove it entirely? :)
Comment #6
swentel commentedI would remove it immediately to be honest :)
Comment #7
joelpittetI agree with swentel here and we should remove it immediately. Create some kind of preprocess that allows for the value manipulation by contrib. But I took a stab at it anyways for practice;)
Comment #9
star-szr#7: drupal-twig-options-1898434-7.patch queued for re-testing.
Comment #11
star-szr#7: drupal-twig-options-1898434-7.patch queued for re-testing.
Comment #13
star-szrOkay, the test failures look much more reasonable now :)
Comment #14
joelpittetCleaned up styles, fixed a bug with spaces causing tests to fail with {% spaceless %}
Maybe these values can be moved out of theme layer and into config?
Also this thing will fail test with twig debug turned on because it html encodes the label and those twig debug comments get jammed in there.
Comment #16
joelpittetOk I think I have plan...
a) Get rid of this theme layer bit
b) Move the code from the preprocessor up to the theme() call above in _options_get_options
c) Augment the allowed_values or equivalent by preprending the option before it hits hook_options_list
d) Possibly rewrite the tests
e) Docs update
f) profit?
Please talk me out of this if you know why this won't do the trick
Comment #17
joelpittetComment #18
joelpittetOk so here's what I came up with:
No more
theme_options_none()A theme function to change a label value was overkill. I moved the logic for this magical option_none label to the
options_allowed_values()so that I didn't lose the ability to manipulate this value.This is an API change. But now if you want to manipulate the none value of a field you can implement
hook_options_list()and that value will be prepended along with all the other values(just as it was before but previously prepended after the hook call and unavailable inhook_options_list()).I had to move field "properties" along with the field to get consistent properties to match up like they did previously and it passed all the tests locally.
Comment #19
joelpittet@todo Write an example to checking empty option and widget type and overriding it's _
nonelabelComment #20
steveoliver commentedThis definitely looks like the way to go. Yeah, just an example in options.api.php would probably make things real clear. I imagine just a few lines of implementation like this:
Comment #22
joelpittetOk so take 2. This one I am confident will pass. *shakes fist at taxonomy module*
The big difference is I brought everything closer to what it was and added an API Change.
The idea would be if you needed to change the Empty Option Label you could do something like this
Comment #23
joelpittetthe API change, as it wasn't super obvious above, would be the $field in the hook being called by reference.
Comment #24
star-szrRe-titling ala #1898060: Remove all (useless) theme functions from dblog module, so we don't have to convert to Twig.
Comment #25
star-szrThis looks great @joelpittet! We should update options.api.php with an example to reflect the API change.
Comment #26
webthingee commentedadded the @code to docblock from #22
Comment #27
star-szrThanks @webthingee!
This should be a complete sentence per http://drupal.org/node/1354#drupal, and I'm not sure about the capitalization, I would suggest something like:
// Override the default empty option label.
I would also change the example to use something other than 'None', the two dashes are not as obvious IMO :)
Comment #28
webthingee commented@Cottser ~
Taking a looks at it also, here's what I am thinking.
Comment #29
star-szrYup, that looks better. Just make sure to end the comment in a period.
Comment #30
webthingee commentedThis is the re-roll taking the place of the patch from comment #26.
Comment #31
star-szrLooking at the change again in the context of the hook_options_list docblock, I think we should explain what the code sample is for, namely changing the empty option label.
Something like this maybe (would need to be wrapped at 80 chars)?
To change the empty option label to '-- None --', update $field['empty_option_label'] as in the following example:
Comment #32
webthingee commentedThis is the re-roll taking the place of the patch from comment #26 and overriding comment #30, based on #31.
Comment #33
star-szrI'm sorry to be saying this now as we're refining docs but after reviewing the patch again, only the module defining the options would be able to change the empty option label. Other modules or themes would not be able to change the empty option label, so that would be a regression.
We could probably just do an alter hook for the empty option label instead. Any objections to that idea?
Comment #33.0
star-szrAdd conversion summary table
Comment #33.1
star-szrUpdate remaining
Comment #34
joelpittet@Cotter, no objections if it gets rid of the theme function:) I just don't know how to make one, could you provide a patch?
Comment #35
star-szrYes.
Comment #36
steveoliver commentedRelated issue: #1751234: Convert option widgets to Plugin system
Comment #37
yched commentedWhoops, sorry that I only find this one now.
As much as I hate the current theme_options_none(), the proposed solution doesn't fly, since HOOK_options_list() is only invoked on the module providing the field type (i.e it's not a hook but a callback - we're slowly getting rid of those as we move to plugins).
theme('options_none') lets any custom code change the label of the 'none' option (that was a frequent feature request way back in the old CCK days). The proposed solution would only let the field type control it.
Comment #38
star-szr@yched - please see #33 which is our current plan (an alter hook) - would that work?
Comment #39
yched commentedAh, right, I only looked at the last patch.
Yes, an alter hook sounds good. But then, maybe an alter hook on the whole $options array ?
In OptionsWidgetBase::getOptions() (where the code lives now after #1751234: Convert option widgets to Plugin system) :
- Get the list of options from the field type (
module_invoke($this->field['module'], 'options_list'))- Add the empty option.
- Call the new alter hook,
- Sanitize the whole list (the
array_walk_recursive(array($this, 'sanitizeLabel'));bit)- Flatten if needed (the
$this->flattenOptions($options);bit)Comment #40
star-szr@yched - that sounds good. To satisfy the use case of theme_options_none(), when you implement the alter hook you would just target the '_none' key in the array. Thanks for explaining how the sanitize and flatten operations would need to be moved as well.
Code from #1751234: Convert option widgets to Plugin system:
Comment #40.0
star-szrUpdate API changes
Comment #41
-enzo- commentedHello Guys
I did a small patch based in thread recommendations and support from Gnuget and Cottser on IRC, please check and let me know if works for you.
Comment #42
gnugetComment #44
star-szrThanks for having a go at this @enzolutions! I think we need to move the logic from theme_options_none() to here and then provide the alter hook to change this; we can't just use '- None -' as the default, that would be a regression. Also, we don't need to duplicate the sanitize and flatten operations. Instead, we should move this 'Add an empty option if the widget needs one' code further up within the getOptions() method.
Comment #45
gnugetComment #46
gnugeti did a new patch how Cotter suggested.
This patch add the things from #39 and take in account the clarifications from Cottser (#44).
Also, this is a example about how can be use the new hook alter:
Comment #47
dawehnerI'm curious whether we could improve this string, as N/A seems to be not easy for new users.
It feels wrong to add an alter hook. Do you think there is a need for that?
Comment #48
star-szr@dawehner - can you expand on 'feels wrong'? I'm not sure how else we would replicate the functionality of the theme function we're removing. Arguably we could make the alter hook specific to the empty option instead of all the options - I'm fine with either approach.
Comment #49
gnuget@dawehner check #33, 39 and #44
I'm not sure if using the drupal_alter is the best way to do the alter hook in this case but works fine.
Comment #50
dawehnerOkay I'm fine :)
Comment #51
star-szrLooks good so far, thanks @gnuget!
Please indent the 'break' lines by two spaces per http://drupal.org/coding-standards#controlstruct.
This should be ModuleHandler::alter() per http://drupal.org/node/1894902, see drupal_alter() API docs that note it is deprecated as well.
Comment #52
star-szrFollowup to my last comment: I asked in #drupal-contribute and @tim.plunkett said that the alter hook would look like
\Drupal::moduleHandler()->alter().Comment #53
star-szrRe-titling.
Comment #54
gnugetUpdated version of the patch, using
\Drupal::moduleHandler()->alter()instead of drupal_alter and a change in the "break" lines for follow the coding standardsComment #55
yched commentedThanks, looking good !
OptionsWidgetBase::OPTIONS_EMPTY_NONE should be static::OPTIONS_EMPTY_NONE
If you're using moduleHandler for this alter hook, then it would probably make sense to use it for the module_invoke('options_list') call just above.
The new hook_options_list_alter() needs to be documented in options.api.php
Comment #56
gnugetAnother version of the patch, taking in account #55
Also, seems to is missing a reference for
ModuleHandler::invoke($module, $hook, $args = array())in http://drupal.org/node/1894902Comment #57
yched commentedThanks @gnuget :-)
Some more polish:
- hook_options_list_alter() hook should receive the same arguments as the hook_options_list() callback:
$this->field, $this->instance, $this->entity
- Use $module_handler = \Drupal::moduleHandler(); rather than fetching it twice in OptionsWidgetBase::getOptions()
+ Several language / formatting issues with the phpdoc for hook_options_list_alter() :
- "Alter the options that is displayed in a option list"
Wrong grammar + missing trailing point + verb needs to be 3rd person.
Since the description for hook_options_list() is "Returns the list of options to be displayed for a field.", I'd suggest "Alters the list of options to be displayed for a field.".
- "Called by getOptions() to allow modules..."
Just mentioning a method name is not enough if you don't specify the class (has to be the fully namespaced class name, including the leading "\".
I'm not really fond, however, of the trend of documenting where hooks are called, this is often impossible to maintain IMO.
I'd suggest simply:
"This hook can notably be used to change the label of the '_none' option."
- @param blocks should not be separated by a newline, and include type hints.
All in all, I'd suggest the following:
Comment #58
gnugetI'm not a native english speaker, so is still hard for me write documentation, thanks for your corrections @yched.
I found a problem, i had to change:
with this:
this because
\Drupal::moduleHandler()->alter()expects maximum 4 params (http://api.drupal.org/api/drupal/core!lib!Drupal!Core!Extension!ModuleHandler.php/function/ModuleHandler%3A%3Aalter/8) so i had to use a$contextvariable how is recommended in the drupal_alter in drupal 7 (http://api.drupal.org/api/drupal/includes!module.inc/function/drupal_alter/7)The problem is i don't know how this will affect the documentation in options.api.php :-/
I attach the patch updated with this changes, and i did a little modifications at the options.api.php file but i'm not sure if is correct what i did there
Thanks for your time and corrections.
Comment #59
gnugetmy last patch has a problem in the options.api.php =/ i attach a updated version
Comment #60
yched commentedYeah, I'm not a native english speaker either, and writing clean docs is always a painfiul process ;)
alter() / $context: Ah, right, that's the usual pattern for alters with many arguments.
You can have a look at hook_entity_field_access_alter() for an example of how this gets documented in api.php
Comment #61
gnugetOks, i updated the documentation using as example the hook_entity_field_access_alter().
Thanks again @yched :-)
Comment #63
yched commented#61: 1898434-61-options_none.patch queued for re-testing.
Comment #64
yched commentedThanks @gnuget !
Looks good to me if testbot approves.
Comment #65
star-szrThis is looking good, nice work @gnuget and @yched :)
In the comments for in options.api.php can we refer to 'the empty option' instead of 'the _none option'? A bit friendlier IMO :)
Wording is a bit off here, how about "Check if this is the field we want to change."
This comment and the inline comment noted above need to end in a period per http://drupal.org/node/1354#drupal.
Trailing whitespace.
On which performed operation? I'm confused by this description. Maybe it's copy + pasted from hook_entity_field_access_alter() but I'm not sure it makes sense here.
What about just:
Re-wrap these lines at 80 characters please per http://drupal.org/coding-standards#drupal. The last line is 81 characters but this could work out:
Comment #66
gnugetOks, a updated version with the changes from #65
Comment #67
star-szrChanges look good, thanks @gnuget!
For the param docs here maybe we can say 'An empty option (_none) might have been added…'? I think we should mention _none somewhere :)
Comment #67.0
star-szrRemove sandbox link
Comment #67.1
star-szrUpdating summary to use template and reflect current status
Comment #68
gnugetOks, done :-)
Comment #69
star-szrI'd say this is ready to go now, I did a manual test last night creating node_options_list_alter() and it worked great.
Just rolling in a tiny coding standards fix (http://drupal.org/coding-standards#array), RTBC! Great work @gnuget and thanks again @yched :)
Comment #69.0
star-szrUpdated issue summary.
Comment #70
joelpittetThis has changed completely from my crazy start but I am so happy to see this theme function get the boot and get replaced by something better! Great work @yched @gnuget and @Cottser for taking the idea and running wild:)
Comment #70.0
joelpittetUpdated issue summary.
Comment #71
catchMuch better! Committed/pushed to 8.x.
Comment #72
swentel commentedChange notice started at http://drupal.org/node/1987618
Comment #73
yched commentedChange notice looks good. Thanks !
Comment #74
star-szrThanks @swentel! I added an example of a comparable theme_options_none() override to the change notice as well.
Comment #75
yched commented@Cottser: right, makes sense :-).
$field->id might turn into a protected property at some point, so I switched it to $field->id() in the code sample.
Comment #76
star-szr@yched - should we create a small follow-up to adjust the sample code in options.api.php then?
Comment #77
yched commentedOh. Yes, I guess so :-/
Comment #77.0
yched commentedUpdate API changes
Comment #78
star-szrCreated #1988614: Adjust hook_options_list_alter() example in options.api.php to use $field->id() instead of $field->id as a follow-up issue.
Comment #79.0
(not verified) commentedAdd follow-up issue
Comment #80
jibranAdded #2426781: Custom OptionWidget have no empty option label as a follow-up issue.