Drupal7 tip: Alter a field widget
We wanted to add a functionality to our file widget so it could register when to exclude a file from search results. Files are indexed and searched with apachesolr and tika. So our idea was to add a checkbox to the file widget and save its value. A hook apachesolr update index will then know if a file can be put in the index or not. We ll save the exclude as field in the file_managed table.
Create the table:
<?php
/**
* Add exclude from search field
*/
function glue_update_7006() {
db_add_field('file_managed', 'exclude', array('type' => 'int', 'not null' => TRUE, 'description' => 'Exclude.'));
}
?>
How to alter the widget
Normal form altering of a field widget wont work, since the render array is not fully constructed. What we need to do is use the #afterbuild functions provided by the render api. At that stage all the info needed to alter the widgets form is present. Here is how to do it:
<?php
/**
* Implements hook_form_alter
*/
function glue_form_measure_node_form_alter(&$form, &$form_state, $form_id) {
//Get lang
if (is_numeric(arg(1))) {
//Put in form state so the add another will able to use it since then the path is not node/[id]/edit but /system/ajax
$form_state['glue_measure_nid'] = arg(1);
}
//Node is already in static cache so we can load it
$node = node_load($form_state['glue_measure_nid']);
//Add exclude search checkbox
$field_attachments_lang = field_language('node', $node, 'field_attachments');
$form_state['field_attachments_lang'] = $field_attachments_lang;
$form['field_attachments'][$field_attachments_lang]['#after_build'][] = 'glue_afterbuild_search_exclude';
$form['#submit'][] = 'glue_afterbuild_search_exclude_submit';
}
?>
With a hook form alter we add a custom afterbuild function and a submit function. Note that we store the field language in the form state since we ll need it in the afterbuild function.
<?php
/**
* Afterbuild function for exclude files from search
*/
function glue_afterbuild_search_exclude($element, &$form_state) {
foreach ($element as $key => $item) {
if (is_numeric($key) && $item['#value']['fid']) {
$element[$key]['display_search']['#type'] = 'checkbox';
$element[$key]['display_search']['#checked'] = false;
$element[$key]['display_search']['#title'] = t('Exclude in search results');
$result = db_select('file_managed', 'f')
->fields('f')
->condition('fid', $element[$key]['#value']['fid'], '=')
->execute();
$file = $result->fetch();
if ($file->exclude == 1) {
$element[$key]['display_search']['#value'] = 0;
$element[$key]['display_search']['#checked'] = true;
}
$element[$key]['display_search']['#attributes']['class'][0] = 'field-attach-exclude-search';
$element[$key]['display_search']['#id'] = $element[$key]['display']['#id'] . '-exlude-search';
$element[$key]['display_search']['#name'] = 'field_attachments[' . $element[$key]['#language'] . '][' . $key . '][display-exclude-search]';
}
}
return $element;
}
?>
In the afterbuild function we can effectivly alter the render array to add our checkbox.
Finally in the submit function we store our values.
<?php
/**
* Form submit for exclude files from search
*/
function glue_afterbuild_search_exclude_submit($form, $form_state) {
foreach ($form_state['values']['field_attachments'][$form_state['field_attachments_lang']] as $key => $item) {
$file = file_load($item['fid']);
if ($file) {
if (isset($item['display-exclude-search']) && $item['display-exclude-search'] == 1) {
$value = 1;
}
else {
$value = 0;
}
db_update('file_managed')
->fields(array('exclude' => $value,))
->condition('fid', $file->fid, '=')
->execute();
}
}
}
?>
The result:
Add new comment