Assuming I understand CONTENT_HANDLE_MODULE correctly, when 'multiple values' is set to CONTENT_HANDLE_MODULE then a given widget can apply its own handling of a given field.
Now, lets say there is a widget that needs tp modify the data that is presented inside of a multiple value field using this method.
When CONTENT_HANDLE_MODULE is set, 'multiple values' no longer works.
Instead only a single field is provided instead of multiple fields.
When set back to CONTENT_HANDLE_CORE, the multiple fields are again shown instead of a single field.
The problem happens around line 100 of content.node_form.inc.
Specifically this segment of code:
<?php
// If content module handles multiple values for this form element,
// and not selecting an individual $delta, process the multiple value form.
if (!isset($get_delta) && content_handle('widget', 'multiple values', $field) == CONTENT_HANDLE_CORE) {
$form_element = content_multiple_value_form($form, $form_state, $field, $items);
}
// If the widget is handling multiple values (e.g optionwidgets),
// or selecting an individual element, just get a single form
// element and make it the $delta value.
else {
$delta = isset($get_delta) ? $get_delta : 0;
if ($element = $function($form, $form_state, $field, $items, $delta)) {
$title = check_plain(t($field['widget']['label']));
$description = content_filter_xss(t($field['widget']['description']));
$defaults = array(
'#required' => $get_delta > 0 ? FALSE : $field['required'],
'#columns' => array_keys($field['columns']),
'#title' => $title,
'#description' => $description,
'#delta' => $delta,
'#field_name' => $field['field_name'],
'#type_name' => $field['type_name'],
);
// If we're processing a specific delta value for a field where the
// content module handles multiples, set the delta in the result.
// For fields that handle their own processing, we can't make assumptions
// about how the field is structured, just merge in the returned value.
if (content_handle('widget', 'multiple values', $field) == CONTENT_HANDLE_CORE) {
$form_element[$delta] = array_merge($element, $defaults);
}
else {
$form_element = array_merge($element, $defaults);
}
}
}
?>
What happens here is that when CONTENT_HANDLE_MODULE. is specified, the hook_widget() will never knowingly receive the top-most field where $get_delta is set to NULL.
Instead, the topmost field gets assigned to 0 and is mistaken for the field nested inside of the topmost field at 0.
To make this easier to understand, here is a structure of what happens with a field whose multiple value is set to 3:
TopMost Field = [
- Field 0 = [ field 0 elements ]
- Field 1 = [ field 1 elements ]
- Field 2 = [ field 2 elements ]
- ... other TopMost Field elements ...
]
what my_hook_widget currently receives:
- TopMost Field as [ Field 0 ], gets assigend [ Field 0 elements ]
- Field 0 as [ Field 0 ], gets assigend [ Field 0 elements ]
- Field 1 as [ Field 1 ], gets assigend [ Field 1 elements ]
- Field 2 as [ Field 2 ], gets assigend [ Field 2 elements ]
what my_hook_widget should receive:
- TopMost Field as [ NULL ], gets assigend [ TopMost Field elements ]
- Field 0 as [ Field 0 ], gets assigend [ Field 0 elements ]
- Field 1 as [ Field 1 ], gets assigend [ Field 1 elements ]
- Field 2 as [ Field 2 ], gets assigend [ Field 2 elements ]
Pay specific attention to this line: <?php if (!isset($get_delta) && content_handle('widget', 'multiple values', $field) == CONTENT_HANDLE_CORE) { ?>
See how the content_handle only calls the content_multiple_value_form() function only when $get_delta is NULL?
The solution is not to define a $delta whose NULL value is changed to be 0.
This way the hook_widget() function can tell the difference between the nested field at 0 and the topmost field.
The corrected code looks like the following:
<?php
// If content module handles multiple values for this form element,
// and not selecting an individual $delta, process the multiple value form.
if (!isset($get_delta) && content_handle('widget', 'multiple values', $field) == CONTENT_HANDLE_CORE) {
$form_element = content_multiple_value_form($form, $form_state, $field, $items);
}
// If the widget is handling multiple values (e.g optionwidgets),
// or selecting an individual element, just get a single form
// element and make it the $delta value.
else {
if ($element = $function($form, $form_state, $field, $items, $get_delta)) {
$title = check_plain(t($field['widget']['label']));
$description = content_filter_xss(t($field['widget']['description']));
$defaults = array(
'#required' => $get_delta > 0 ? FALSE : $field['required'],
'#columns' => array_keys($field['columns']),
'#title' => $title,
'#description' => $description,
'#field_name' => $field['field_name'],
'#type_name' => $field['type_name'],
);
if (isset($get_delta)){
$defaults['#delta'] = $get_delta;
}
// If we're processing a specific delta value for a field where the
// content module handles multiples, set the delta in the result.
// For fields that handle their own processing, we can't make assumptions
// about how the field is structured, just merge in the returned value.
if (content_handle('widget', 'multiple values', $field) == CONTENT_HANDLE_CORE) {
$form_element[$get_delta] = array_merge($element, $defaults);
}
else {
$form_element = array_merge($element, $defaults);
}
}
}
?>
I removed $delta and replaced it with $get_delta which contains the correct values.
Once this is done, modules can then act on the NULL case without causing weird behavior for the 0th case.
Attached is a patch that makes these changes.
For compatibility with the 2.x version, you might want to instead define a new hook (say hook_widget_parent for example), then that hook will be called for the NULL case while all other cases go to the existing hook_widget(). (Thus preventing existing hook_widget() functions from breaking when their delta that is always assumed to be numeric is suddenly NULL!)
| Comment | File | Size | Author |
|---|---|---|---|
| #3 | cck-6.x-3.x-fix_CONTENT_HANDLE_MODULE_bug-3.patch | 1.93 KB | thekevinday |
| #2 | cck-6.x-3.x-fix_CONTENT_HANDLE_MODULE_bug-2.patch | 2.04 KB | thekevinday |
| #1 | cck-6.x-3.x-fix_CONTENT_HANDLE_MODULE_bug-1.patch | 1.93 KB | thekevinday |
Comments
Comment #1
thekevinday commentedIt seems I have been having trouble uploading files lately.
Here is the second attempt to upload the patch.
Also, I am now wondering if
should instead be
Comment #2
thekevinday commentedI now believe that the additional case mentioned in #1 should be performed.
This patch applies includes the change.
Comment #3
thekevinday commentedI am reverting #2 because of:
Which is mentioned immediately above the code I modified.
It is a good idea to play it safe here and expect the modules to handle the defaults themselves.