Drupal 7 Field API sample
Recently I had to create a custom field for a project I am working on. The field was not difficult to implement, it only had to store two values in the database, but I didn't found a sample tutorial for that so I want to share my experience with you.
If you take a look at the Examples module, you can find a sample field that stores one value in the database, but this sample will show you how to store more data. In fact this field will store two values retrieved from The Internet Chuck Norris Database. One numeric value that represents the joke identificatior and a text value that holds the joke itself, for example:
Chuck Norris once ordered a Big Mac at Burger King, and got one.
First step to create our custom field is to create the database structure to store the data. This can be done using the hook_field_schema in the .install file of your module.
/**
* Implements hook_field_schema().
*/
function field_chuck_field_schema($field) {
$columns = array(
'id' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => FALSE
),
'joke' => array(
'type' => 'varchar',
'length' => 2048,
'not null' => FALSE
),
);
return array(
'columns' => $columns,
);
}
You can create as many columns as you want to store your data. Just take into account the supported types.
Next step is to create a .module file to hold the field specifications starting with the hook_field_info:
/**
* Implements hook_field_info().
* Provides the description of the field.
*/
function field_chuck_field_info() {
return array(
'field_chuck' => array(
'label' => t('Chuck Norris Joke'),
'description' => t('Creates a field for Chuck Norris jokes.'),
'default_widget' => 'field_chuck',
'default_formatter' => 'chuck_norris_joke',
),
);
}
In this hook we create our field name "field_chuck" and the default widget and formatter names. Then we describe the field widget with hook_field_widget_info telling Drupal the name of the widget, a label for it and for what field types it's designed:
/**
* Implements hook_field_widget_info().
* Expose Field API widget types.
*/
function field_chuck_field_widget_info() {
return array(
'field_chuck' => array(
'label' => t('Chuck Norris Joke'),
'field types' => array('field_chuck'),
),
);
}
Also we must tell Drupal the field widget structure with hook_field_widget_form:
/**
* Implements hook_field_widget_form().
* Return the form for a single field widget.
*/
function field_chuck_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
$element += array(
'#type' => $instance['widget']['type'],
'#default_value' => isset($items[$delta]) ? $items[$delta] : '',
);
return $element;
}
This hook implementation is different than the one in the Examples module but I guess this is more customizable because we can use hook_element_info to implement our own Form API element types with their values:
/**
* Implements hook_element_info().
* Declare the field Form API element types and specify their default values.
* @see field_chuck_field_process().
*/
function field_chuck_element_info() {
$elements = array();
$elements['field_chuck'] = array(
'#input' => TRUE,
'#process' => array('field_chuck_field_process'),
);
return $elements;
}
Now we can create the field Form API elements in the #process callback function:
function field_chuck_field_process($element, $form_state, $complete_form) {
$element['submit'] = array(
'#type' => 'markup',
'#markup' => t('Go!'),
'#prefix' => '<div id="field-chuck-submit"><h2>',
'#suffix' => '</h2></div>',
'#attached' => array(
'js' => array(drupal_get_path('module', 'field_chuck') . '/field_chuck.js'),
),
);
$element['joke'] = array(
'#type' => 'textfield',
'#title' => t('Chuck Norris Joke'),
'#default_value' => isset($element['#value']['joke']) ? $element['#value']['joke'] : '',
'#prefix' => '<div id="field-chuck-joke">',
'#suffix' => '</div>',
'#maxlength' => 2048,
'#size' => 100,
);
$element['id'] = array(
'#type' => 'textfield',
'#title' => t('Joke ID'),
'#default_value' => isset($element['#value']['id']) ? $element['#value']['id'] : '',
'#prefix' => '<div id="field-chuck-id">',
'#suffix' => '</div>',
'#size' => 4,
);
// To prevent an extra required indicator, disable the required flag on the
// base element since all the sub-fields are already required if desired.
$element['#required'] = FALSE;
return $element;
}
The final steps are:
- Create the implementation of hook_field_load if we want to process the data before loading it in the field widget.
- Don't forget that the implementation of hook_field_validate and hook_field_is_empty are required for a correct field validation.
- Also we can implement hook_field_presave if we want to alter the data before storing it in the database.
- Create the custom field formatter using hook_field_formater_info and hook_field_formatter_view as I explained in a previous post.
The full example code can be downloaded from my Drupal sandbox and includes the javascript to fetch the Chuck Norris jokes, so I hope you will enjoy it :)