Create a new webform element in Drupal 7
Sometimes the default field types within Webform don't work as we want them to or we want to do something beyond which will work beyond a few hacks in the theme. The following will show you what is required to define a new field type and the necessary functions to make it work.
Defining the new webform component
The first thing you need is a custom module, if you haven't got one set one up (guide on Drupal.org).
To define a new field type/component you need to use hook_webform_component_info(). This guide will go through adding a new slider component using the jQuery UI.
<?php
function MODULE_NAME_webform_component_info() {
$components = array();
$components['slider'] = array(
'label' => t('Slider'),
'description' => t('Create a slider for users to select a value.'),
'features' => array(
'csv' => TRUE,
'email' => TRUE,
'email_address' => FALSE,
'email_name' => FALSE,
'required' => FALSE,
'title_display' => FALSE,
'title_inline' => FALSE,
'conditional' => FALSE,
'group' => FALSE,
'spam_analysis' => FALSE,
'attachment' => FALSE,
),
'file' => 'components/slider.inc',
);
return $components;
}
?>
There are various elements in the featured array which should be pretty self-explanatory but I will go through them anyway.
- CSV
- If set to TRUE, the value of the component will be passed through to the CSV output.
- If set to TRUE, the value of the component will be included in the %email_values token.
- Email address
- If set to TRUE, the value of the component can be used as the to/from email address.
- Email name
- If set to TRUE, the value of the component can be used as the from email name.
- Required
- If set to TRUE, defines whether the component can be set as required.
- Title display
- If set to TRUE, the title of the field will be displayed.
- Title inline
- If set to TRUE and Title display is also set to TRUE, the title will be shown inline with the component.
- Conditional
- If set to TRUE, the component can be used as a conditional value which will change the output of other fields/components.
- Group
- If set to TRUE, the component can be used to group together multiple components.
- Spam analysis
- If set to TRUE, the component holds data that can be used for spam analysis by any modules that hook in to Webform.
- Attachment
- If set to TRUE, the component takes file uploads.
The file needs to be set if you plan on storing all your component related functions together in one file (which I would recommend).
Create your the file for your component.
_webform_defaults_component()
<?php
function _webform_defaults_slider() {
return array(
'name' => '',
'form_key' => NULL,
'pid' => 0,
'weight' => 0,
'value' => '',
'mandatory' => 0,
'extra' => array(
'field_prefix' => '',
'field_suffix' => '',
),
);
}
?>
Certain values can be left as they are, but within the extra array you have free rein to define any additional information you want saved with your component.
_webform_theme_component()
<?php
function _webform_theme_slider() {
return array(
'webform_display_slider' => array(
'render element' => 'element',
),
);
}
?>
This function allows you to add additional information in to hook_theme().
_webform_edit_component()
<?php
function _webform_edit_slider($component) {
$form = array();
$form['extra']['field_prefix'] = array(
'#type' => 'textfield',
'#title' => t('Left'),
'#default_value' => $component['extra']['field_prefix'],
'#size' => 60,
'#required' => TRUE,
'#maxlength' => 255,
'#weight' => 1.1,
'#parents' => array('extra', 'field_prefix'),
'#description' => t('Text placed to the left of the slider'),
);
$form['extra']['field_suffix'] = array(
'#type' => 'textfield',
'#title' => t('Right'),
'#default_value' => $component['extra']['field_suffix'],
'#size' => 60,
'#required' => TRUE,
'#maxlength' => 255,
'#weight' => 1.2,
'#parents' => array('extra', 'field_suffix'),
'#description' => t('Text placed to the right of the slider'),
);
return $form;
}
?>
Here you define your additional form elements using the form API to add to the edit screen of the component.
_webform_render_component()
<?php
function _webform_render_slider($component, $value = NULL, $filter = TRUE) {
$node = isset($component['nid']) ? node_load($component['nid']) : NULL;
drupal_add_library('system', 'ui.slider');
drupal_add_js('jQuery(document).ready(function(){jQuery("#webform-slider-'. $component['form_key'] .'").slider({
min: 1,
max: 5,
step: 1,
value: jQuery("#"+ jQuery("#webform-slider-'. $component['form_key'] .'").attr("data-rel") +" input").val(),
slide: function(event, ui) {
jQuery("#"+ jQuery("#webform-slider-'. $component['form_key'] .'").attr("data-rel") +" input").val(ui.value);
}
});});', 'inline');
$slider = '<div class="slider-item slider-item-first">'. ($filter ? _webform_filter_xss($component['extra']['field_prefix']) : $component['extra']['field_prefix']) .'</div>';
$slider .= '<div class="slider-item slider" id="webform-slider-'. $component['form_key'] .'" data-rel="webform-component-'. $component['form_key'] .'"></div>';
$slider .= '<div class="slider-item slider-item-last">'. ($filter ? _webform_filter_xss($component['extra']['field_suffix']) : $component['extra']['field_suffix']) .'</div>';
$element = array(
'#type' => 'hidden',
'#default_value' => $filter ? _webform_filter_values($component['value'], $node, NULL, NULL, FALSE) : $component['value'],
'#required' => $component['mandatory'],
'#weight' => $component['weight'],
'#prefix' => '<div class="slider-wrapper clearfix">'. $slider .'</div>',
'#theme_wrappers' => array('webform_element'),
);
if (isset($value)) {
$element['#default_value'] = $value[0];
}
else {
$element['#default_value'] = 3;
}
return $element;
}
?>
The _webform_render_component() function defines how the form element is sent to the webform itself.
For the slider element, I am using a hidden field which will store the value and add some jQuery to add the slider to the form. My code is a bit of a mess and I am sure the jQuery could be written a lot better, but it gets the job done.
_webform_display_component()
<?php
function _webform_display_slider($component, $value, $format = 'html') {
return array(
'#title' => $component['extra']['field_prefix'] .' / '. $component['extra']['field_suffix'],
'#weight' => $component['weight'],
'#theme' => 'webform_display_slider',
'#theme_wrappers' => $format == 'html' ? array('webform_element') : array('webform_element_text'),
'#format' => $format,
'#value' => $value[0],
'#translatable' => array('title', 'field_prefix', 'field_suffix'),
);
}
?>
The _webform_display_component() function defines how the value is displayed from the component in the various reporting from webform. If you are using a custom #theme function that will obviously need to be defined.
<?php
function theme_webform_display_slider($variables) {
$element = $variables['element'];
$value = $element['#value'];
return trim($value) !== '' ? $value : ' ';
}
?>
_webform_table_component()
<?php
function _webform_table_slider($component, $value) {
return check_plain(empty($value[0]) ? '' : $value[0]);
}
?>
This defines how the value is displayed within the reports table.
_webform_csv_headers_component() & _webform_csv_data_component()
These functions define how the component value is displayed within CSV outputs from Webform.
<?php
function _webform_csv_headers_slider($component, $export_options) {
$header = array();
$header[0] = '';
$header[1] = $component['extra']['field_prefix'];
$header[2] = $component['extra']['field_suffix'];
return $header;
}
?>
There are 3 rows of headers that you have the ability to enter data in to for the CSV output.
<?php
function _webform_csv_data_slider($component, $export_options, $value) {
return !isset($value[0]) ? '' : $value[0];
}
?>
For a full list of available functions look in the Webform module folder for the file called webform.api.php. This file has all the available component hooks.
Comments
cmaaga
Thu, 2013-01-10 16:47
Permalink
Step1 Step2, etc
Hi!
how to display the steps number above the form?
I see that you do it :)
james
Thu, 2013-01-10 20:22
Permalink
hook_node_view(). See here
hook_node_view(). See here for full code - http://pastebin.com/2bZbzgJu
J.Precheur
Thu, 2013-07-25 06:51
Permalink
Insert only the default value
Hie,
first thank you for all this elements.
I have a problem. The value which is inserted is all the time the default value (3 in your code) and not the selected value in the slider.
I don't understand why ? Do you have any suggestion ?
Thanks
J.Precheur
james
Thu, 2013-07-25 08:14
Permalink
For whatever reason $value
For whatever reason $value probably isn't being passed through.
This code still works with the latest version of Webform for me so you should make sure everything has been copied as is.