Create a list of options as a list in Allowed values or as an array in PHP code. These values will be the same for %field in all content types.

', array('%field' => $form['widget']['label']['#default_value'])); if ($form['widget']['widget_type']['#default_value'] == 'optionwidgets_onoff') { $output .= t('

For a \'Single on/off checkbox\' widget, define the \'off\' value first, then the \'on\' value in the Allowed values section. Note that the checkbox will be labeled with the label of the \'on\' value.

'); } elseif ($form['widget']['widget_type']['#default_value'] == 'optionwidgets_buttons') { $output .= t('

The \'Checkboxes / radio buttons\' widget will display checkboxes if the multiple values option is selected for this field, otherwise radios will be displayed.

'); } if (in_array($form['type']['#value'], array('text', 'number_integer', 'number_float', 'number_decimal')) && in_array($form['widget']['widget_type']['#default_value'], array('optionwidgets_onoff', 'optionwidgets_buttons', 'optionwidgets_select'))) { $form['field']['allowed_values_fieldset']['#collapsed'] = FALSE; $form['field']['allowed_values_fieldset']['#description'] = $output; } } } /** * Implementation of hook_theme(). */ function optionwidgets_theme() { return array( 'optionwidgets_select' => array( 'arguments' => array('element' => NULL), ), 'optionwidgets_buttons' => array( 'arguments' => array('element' => NULL), ), 'optionwidgets_onoff' => array( 'arguments' => array('element' => NULL), ), 'optionwidgets_none' => array( 'arguments' => array('widget_type' => NULL, 'field_name' => NULL, 'node_type' => NULL), ), ); } /** * Implementation of hook_widget_info(). * * We need custom handling of multiple values because we need * to combine them into a options list rather than display * multiple elements. We will use the content module's default * handling for default values. * * Callbacks can be omitted if default handing is used. * They're included here just so this module can be used * as an example for custom modules that might do things * differently. */ function optionwidgets_widget_info() { return array( 'optionwidgets_select' => array( 'label' => t('Select list'), 'field types' => array('text', 'number_integer', 'number_decimal', 'number_float'), 'multiple values' => CONTENT_HANDLE_MODULE, 'callbacks' => array( 'default value' => CONTENT_CALLBACK_DEFAULT, ), ), 'optionwidgets_buttons' => array( 'label' => t('Check boxes/radio buttons'), 'field types' => array('text', 'number_integer', 'number_decimal', 'number_float'), 'multiple values' => CONTENT_HANDLE_MODULE, 'callbacks' => array( 'default value' => CONTENT_CALLBACK_DEFAULT, ), ), 'optionwidgets_onoff' => array( 'label' => t('Single on/off checkbox'), 'field types' => array('text', 'number_integer', 'number_decimal', 'number_float'), 'multiple values' => CONTENT_HANDLE_MODULE, 'callbacks' => array( 'default value' => CONTENT_CALLBACK_DEFAULT, ), ), ); } /** * Implementation of FAPI hook_elements(). * * Any FAPI callbacks needed for individual widgets can be declared here, * and the element will be passed to those callbacks for processing. * * Drupal will automatically theme the element using a theme with * the same name as the hook_elements key. */ function optionwidgets_elements() { return array( 'optionwidgets_select' => array( '#input' => TRUE, '#columns' => array('value'), '#delta' => 0, '#element_validate' => array('optionwidgets_validate'), '#process' => array('optionwidgets_select_process'), ), 'optionwidgets_buttons' => array( '#input' => TRUE, '#columns' => array('value'), '#delta' => 0, '#element_validate' => array('optionwidgets_validate'), '#process' => array('optionwidgets_buttons_process'), ), 'optionwidgets_onoff' => array( '#input' => TRUE, '#columns' => array('value'), '#delta' => 0, '#element_validate' => array('optionwidgets_validate'), '#process' => array('optionwidgets_onoff_process'), ), ); } /** * Implementation of hook_widget(). * * Attach a single form element to the form. It will be built out and * validated in the callback(s) listed in hook_elements. We build it * out in the callbacks rather than here in hook_widget so it can be * plugged into any module that can provide it with valid * $field information. * * Content module will set the weight, field name and delta values * for each form element. This is a change from earlier CCK versions * where the widget managed its own multiple values. * * If there are multiple values for this field, the content module will * call this function as many times as needed. * * @param $form * the entire form array, $form['#node'] holds node information * @param $form_state * the form_state, $form_state['values'] holds the form values. * @param $field * the field array * @param $items * an array of default values for this element * @param $delta * the order of this item in the array of subelements (0, 1, 2, etc) * * @return * the form item for a single element for this field */ function optionwidgets_widget(&$form, &$form_state, $field, $items, $delta = NULL) { $element = array( '#type' => $field['widget']['type'], '#default_value' => !empty($items) ? $items : array(), ); return $element; } /** * Process an individual element. * * Build the form element. When creating a form using FAPI #process, * note that $element['#value'] is already set. * * The $fields array is in $form['#field_info'][$element['#field_name']]. */ function optionwidgets_buttons_process($element, $edit, &$form_state, $form) { $field_name = $element['#field_name']; $field = $form['#field_info'][$field_name]; $field_key = $element['#columns'][0]; if (!$form_state['submitted']) { $element['#value'] = optionwidgets_data2form($element, $element['#default_value'], $field); } $options = optionwidgets_options($field); $element[$field_key] = array( '#type' => $field['multiple'] ? 'checkboxes' : 'radios', '#title' => $element['#title'], '#description' => $element['#description'], '#required' => $field['required'], '#multiple' => $field['multiple'], '#options' => $options, '#default_value' => isset($element['#value'][$field_key]) ? $element['#value'][$field_key] : NULL, ); // Make sure field info will be available to the validator which // does not get the values in $form. $form_state['#field_info'][$field['field_name']] = $field; return $element; } /** * Process an individual element. * * Build the form element. When creating a form using FAPI #process, * note that $element['#value'] is already set. * * The $fields array is in $form['#field_info'][$element['#field_name']]. */ function optionwidgets_select_process($element, $edit, &$form_state, $form) { $field_name = $element['#field_name']; $field = $form['#field_info'][$field_name]; $field_key = $element['#columns'][0]; if (!$form_state['submitted']) { $element['#value'] = optionwidgets_data2form($element, $element['#default_value'], $field); } $options = optionwidgets_options($field); $element[$field_key] = array( '#type' => 'select', '#title' => $element['#title'], '#description' => $element['#description'], '#required' => $field['required'], '#multiple' => $field['multiple'], '#options' => $options, '#default_value' => isset($element['#value'][$field_key]) ? $element['#value'][$field_key] : NULL, ); // Make sure field info will be available to the validator which // does not get the values in $form. // TODO for some reason putting the $field array into $form_state['storage'] // causes the node's hook_form_alter to be invoked twice, garbling the // results. Need to investigate why that is happening (a core bug?), but // in the meantime avoid using $form_state['storage'] to store anything. $form_state['#field_info'][$field['field_name']] = $field; return $element; } /** * Process an individual element. * * Build the form element. When creating a form using FAPI #process, * note that $element['#value'] is already set. * * The $fields array is in $form['#field_info'][$element['#field_name']]. */ function optionwidgets_onoff_process($element, $edit, &$form_state, $form) { $field_name = $element['#field_name']; $field = $form['#field_info'][$field_name]; $field_key = $element['#columns'][0]; if (!$form_state['submitted']) { $element['#value'] = optionwidgets_data2form($element, $element['#value'], $field); } $options = optionwidgets_options($field); $keys = array_keys($options); $on_value = !empty($keys) ? $keys[1] : NULL; $element[$field_key] = array( '#type' => 'checkbox', '#title' => $options[$on_value], '#description' => t($field['widget']['description']), '#default_value' => isset($element['#value'][$field_key][0]) ? $element['#value'][$field_key][0] == $on_value : FALSE, '#return_value' => $on_value, ); // Make sure field info will be available to the validator which // does not get the values in $form. $form_state['#field_info'][$field['field_name']] = $field; return $element; } /** * FAPI function to validate optionwidgets element. * * Transpose selections from field => delta to delta => field, * turning multiple selected options into multiple parent elements. * Immediate parent is the delta, need to get back to parent's parent * to create multiple elements. */ function optionwidgets_validate($element, &$form_state) { $field = $form_state['#field_info'][$element['#field_name']]; $updated = optionwidgets_form2data($element, $element['#value'], $field); form_set_value($element, $updated, $form_state); } /** * Helper function to transpose the values as stored in the database * to the format the widget needs. Can be called anywhere this * transformation is needed. */ function optionwidgets_data2form($element, $items, $field) { $field_key = $element['#columns'][0]; $options = optionwidgets_options($field); $items_transposed = content_transpose_array_rows_cols($items); $values = (isset($items_transposed[$field_key]) && is_array($items_transposed[$field_key])) ? $items_transposed[$field_key] : array(); $keys = array(); foreach ($values as $value) { $key = array_search($value, array_keys($options)); if (isset($key)) { $keys[] = $value; } } if ($field['multiple'] || $element['#type'] == 'optionwidgets_onoff') { return array($field_key => $keys); } else { return array($field_key => reset($keys)); } } /** * Helper function to transpose the values returned by submitting the widget * to the format to be stored in the field. Can be called anywhere this * transformation is needed. */ function optionwidgets_form2data($element, $items, $field) { $field_key = $element['#columns'][0]; $options = optionwidgets_options($field); $keys = isset($items[$field_key]) ? $items[$field_key] : array(); if (!is_array($keys)) { $keys = array($keys); } $values = array(); foreach ($keys as $key => $value) { if (array_key_exists($value, $options)) { $values[] = $value; } } if (empty($values)) { if ($element['#type'] == 'optionwidgets_onoff') { $keys = array_keys($options); $values[] = array_key_exists(0, $keys) ? $keys[0] : ''; } else { $values[] = NULL; } } return content_transpose_array_rows_cols(array($field_key => $values)); } /** * Helper function for finding the allowed values list for a field. * * See if there is a module hook for the option values. * Otherwise, try content_allowed_values() for an options list. */ function optionwidgets_options($field) { $function = $field['module'] .'_allowed_values'; $options = function_exists($function) ? $function($field) : (array) content_allowed_values($field); // Add an empty choice for non required radios and single-selects. if ($field['widget']['type'] != 'optionwidgets_onoff' && !$field['required'] && !$field['multiple']) { $options = array('' => theme('optionwidgets_none', $field)) + $options; } return $options; } /** * Theme the label for the empty value for options that are not required. * The default theme will display N/A for a radio list and blank for a select. */ function theme_optionwidgets_none($field) { switch ($field['widget']['type']) { case 'optionwidgets_buttons': return t('N/A'); default : return ''; } } /** * FAPI themes for optionwidgets. * * The select, checkboxes or radios are already rendered by the * select, checkboxes, or radios themes and the HTML output * lives in $element['#children']. Override this theme to * make custom changes to the output. * * $element['#field_name'] contains the field name * $element['#delta] is the position of this element in the group */ function theme_optionwidgets_select($element) { return $element['#children']; } function theme_optionwidgets_onoff($element) { return $element['#children']; } function theme_optionwidgets_buttons($element) { return $element['#children']; }