Community Documentation

Adding a custom element type & expanding elements

Last updated July 8, 2007. Created by Wim Leers on November 16, 2005.
Edited by hunmonk, Amazon. Log in to edit this page.

The start and end date selection boxes proved to be a particular challenge in my upgrade of eventrepeat module. I handled it by creating my own form element type.

Hook_elements

First, use hook_elements() to declare the new type: 'eventrepeat_date' is the name of the new type. Also, if you want any default values, be sure to declare them either here or in the process function:

<?php
function eventrepeat_elements() {
  
$type['eventrepeat_date'] = array('#input' => TRUE);
   return
$type;
}
?>

Dynamic expand function

Normally, #process would be declared as a "the" expand function in the element type declaration (hook_elements()), but since I needed to pass $edit and $node as function arguments in this case, I declare it for each instance of the element type. Hence a dynamic #process handler.
A normal expand function is more limited, because you can provide less context. Sending $user as a parameter would be possible though.

Here's how the element type is invoked when in a $form array. Notice in particular how the #process attribute is declared here as an array. The key is the name of the callback used to expand the type into multiple elements (you may not need a function such as this if your new type is simple). The value is an array of arguments to be passed to the callback function.

<?php
$form
['end_controls']['end_date'] = array(
 
'#type' => 'eventrepeat_date',
 
'#title' => t('Repeat end date'),
 
'#process' => array('_eventrepeat_form_date' => array($edit, $node, 'eventrepeat_end')),
);
?>

The expand function

Next, write the expand function. The first argument is always the element that is being passed for processing and the other arguments are the optional arguments I added in the #process attribute. Notice that I'm adding to $element and returning it:

<?php
function _eventrepeat_form_date($element, $edit = NULL, $node = NULL, $prefix = NULL) {
   
 
// Get current year, and drop next 10 years into an array.
 
$date = getdate(time());
 
$curyear = $date['year']; 
 
$years = array(0 => '--'. t('Select') .'--');
  while (
$i < 10) {
   
$years[$curyear + $i] = $curyear + $i;
   
$i++;
  }

 
// Months array.
 
$months = array(
   
'--'. t('Select') .'--',
   
t('January'),
   
t('February'),
   
t('March'),
   
t('April'),
   
t('May'),
   
t('June'),
   
t('July'),
   
t('August'),
   
t('September'),
   
t('October'),
   
t('November'),
   
t('December')
  );
 
 
// Days array.
 
$days = array(0 => '--'. t('Select') .'--');
  for (
$i = 1; $i <= 31; $i++) {
     
$days[$i] = $i;
  }

 
// Compose the select boxes, and add the exception editor button if necessary.
 
$element[$prefix .'month'] = array(
   
'#type' => 'select',
   
'#default_value' => $edit ? $edit[$prefix.'month'] : ($node->{$prefix.'month'} ? $node->{$prefix.'month'} : 0),
   
'#options' => $months,
  );
 
$element[$prefix .'day'] = array(
   
'#type' => 'select',
   
'#default_value' => $edit ? $edit[$prefix.'day'] : ($node->{$prefix.'day'} ? $node->{$prefix.'day'} : 0),
   
'#options' => $days,
  );
 
$element['comma'] = array(
   
'#type' => 'markup',
   
'#value' => ', ',
  );
 
$element[$prefix .'year'] = array(
   
'#type' => 'select',
   
'#default_value' => $edit ? $edit[$prefix.'year'] : ($node->{$prefix.'year'} ? $node->{$prefix.'year'} : 0),
   
'#options' => $years,
  );

  if (
$prefix == 'eventrepeat_EXDATE_edit') {
   
$element['exception_button'] = array(
     
'#type' => 'submit',
     
'#value' => t('Add/Delete Exception'),
    );
  }

  return
$element;
}
?>

The theming function

Then, a theming function to pretty it up. This is basically a theming function for a form item, but I put an inline container and $element['#children'] (which is the constructed select boxes, etc. from my expand function) into it. Naming convention for the theme function is theme_elementname.
Without a theming function, you won't get any output.

<?php
function theme_eventrepeat_date($element) {
  return
theme(
   
'form_element',
    array(
     
'#title' => $element['#title'],
     
'#description' => $element['#description'],
     
'#id' => $element['#id'],
     
'#required' => $element['#required'],
     
'#error' => $element['#error'],
    ),
   
'<div class="container-inline">'. $element['#children'] .'</div>'
 
);
}
?>

About this page

Drupal version
Drupal 5.x, Drupal 6.x

Archive

Drupal’s online documentation is © 2000-2012 by the individual contributors and can be used in accordance with the Creative Commons License, Attribution-ShareAlike 2.0. PHP code is distributed under the GNU General Public License.