Altering A File Form Field Element In Drupal 7

Altering text in Drupal 7 is quite simple thanks to things like string overrides that allow you to replace all instances of a string throughout a site. If you want to change a single element on a single form then string overrides don't quite work, but using hook_form_alter() or hook_form_form-id_alter() allows you to manipulate any form in a Drupal site.

At first, changing a file field form element on a node form might seem like a simple thing to do, but the reality is slightly more complex. Let's say that we have a content type called 'page' that contains an element called 'field_page_image', which is just a default file field. In this example I have created an unlimited list, but the code will work for a set number of items, even one. Setting up a hook_form_form-id_alter() function to alter the node edit form is easy enough, but you'll quickly realise that although the field_page_image field exists, the elements relating to the file itself are not present. This is because these elements are built after this function call.

To alter these fields we need to use the #after_build attribute. This attribute contains an array of function names that will be called after the form or form element have been built. As the form elements for the file field haven't been created yet we must use this attribute to alter the element after is has been built.

As the node type edit form I am altering is for the node type 'page' the hook function is called 'mymodule_form_page_node_form_alter()'. With this function created I just cycle through the elements in the 'field_page_image' element and add the #after_build attribute to each file element. The function mymodule_rename_remove_button() is used to alter the individual elements, so I just add the function name here.

We can safely ignore any non-numeric elements as these are just meta elements that detail what text should appear around the 'Choose File' button. Here is the source code of the mymodule_form_page_node_form_alter() function.

function mymodule_form_page_node_form_alter(&$form, &$form_state) {
  if (isset($form['#node']->language)) {
    $node_language = $form['#node']->language;
    if (isset($form['field_page_image'][$node_language])) {
      foreach ($form['field_page_image'][$node_language] as $item => $field_banner) {
        if (!is_numeric($item)) {
          continue;
        }
        if (isset($form['field_page_image'][$node_language][$item])) {
          // Alter the file field element after it has been built.
          $form['field_page_image'][$node_language][$item]['#after_build'][] = 'mymodule_rename_remove_button';
        }
      }
    }
  }
}

Now all that is left is to create the mymodule_rename_remove_button() function. This function takes the element and the form state as parameters and must return the altered form element. To change the text of the button that removes the file we just need to do the following.

function mymodule_rename_remove_button($element, &$form_state) {
  $element['remove_button']['#value'] = t('Remove/Replace');
  return $element;
}

Any files that we upload to this content type will now be shown on the node edit page with a 'Remove/Replace' button.

The #after_build attribute can be used in a number of different circumstances outside of the one mentioned here. A good example is when trying to alter a form that then goes on to be altered by another module that adds more elements to it. By using #after_build on the main form element you can ensure that you can alter a form after all modules have worked on it. This means that you don't have to rely on module loading precedence, which can cause issues if you try and alter a form before certain elements are added.

Comments

Is this not working with /admin/structure/multifield. Is there anything else about multifield compare to file field or field collection?

Permalink

Add new comment

The content of this field is kept private and will not be shown publicly.
CAPTCHA
7 + 0 =
Solve this simple math problem and enter the result. E.g. for 1+3, enter 4.
This question is for testing whether or not you are a human visitor and to prevent automated spam submissions.