Check your version

This video covers a topic in Drupal 7 which may or may not be the version you're using. We're keeping this tutorial online as a courtesy to users of Drupal 7, but we consider it archived.

Alternate resources: 

Creating Field Widgets for Collecting User Input

Video loading...

  • 0:00
    DRUPAL 7 FIELD API Drupal 7 Field API Fundamentals with Joe Shindelar
  • 0:06
    [WATER DROP NOISE]
  • 0:07
    In the last two lessons,
  • 0:08
    we defined our field type and our field schema.
  • 0:11
    So we know what type of data to store and where to store it.
  • 0:15
    Now we need to add a field widget to collect input from our users
  • 0:19
    so that we know what data to store.
  • 0:21
    In this Lesson
  • 0:21
    In this lesson, we're going to take a look at implementing
  • 0:24
    hook_field_widget_info and hook_field_widget_form.
  • 0:29
    The combination of the two will allow us to provide a user
  • 0:32
    interface in the form of two HTML text field elements that will allow
  • 0:36
    an end user to input both a hex color and a label value
  • 0:40
    to go along within any entity that has
  • 0:42
    an instance of the RGB field attached to it.
  • 0:46
    By the end of this lesson, you should
  • 0:47
    be able to provide administrators with the user interface element
  • 0:50
    for entering data for your custom field type
  • 0:53
    or for any existing field type.
  • 0:56
    [WATER DROP NOISE]
  • 0:56
    JOE SHINDELAR: When we're looking at our site,
  • 0:58
    if we navigate to Structure, Content Types,
  • 1:01
    and we go to the Manage Fields page for the article content type,
  • 1:05
    you can see that we've already got a color field
  • 1:08
    added to our article content type.
  • 1:11
    However, if I click on the Add Content link
  • 1:13
    and then click Article, and I scroll down the form here,
  • 1:17
    we don't see anywhere that we can enter
  • 1:19
    in color information on this form yet.
  • 1:23
    That's because we haven't defined a widget to collect user data.
  • 1:27
    Widgets are a combination of an implementation
  • 1:30
    of hook_field_widget_info and hook_field_widget_form.
  • 1:34
    In an earlier lesson, we already added a really basic
  • 1:38
    definition of hook_field_widget_info.
  • 1:41
    Let's take a look at that quick.
  • 1:42
    If I switch to my code, you can see in the RGB module,
  • 1:46
    I've already got this RGB field widget info function that returns
  • 1:50
    a simple array describing, in this case,
  • 1:53
    just the human readable label of our widget
  • 1:56
    and the field types that this widget will apply to.
  • 1:59
    The key of this array is the unique name of this widget.
  • 2:03
    So we've prefixed it with our module name just to be on the safe side.
  • 2:08
    We had to set this up in order for our field to even show up
  • 2:11
    in the field UI as something that we could
  • 2:13
    add to our article content type.
  • 2:15
    Now we're going to talk about how we can expand on this
  • 2:18
    and actually create the widget for collecting user data.
  • 2:21
    Let's look at the documentation for hook_field_widget_info again.
  • 2:25
    On api.drupal.org, I can pull up the documentation.
  • 2:29
    And it says that the return value for this function
  • 2:31
    is an array describing the widget types implemented
  • 2:34
    by the module, which is what we've got already.
  • 2:36
    We've got, in our case, one widget type.
  • 2:38
    Of course, you could define any number of different widget types
  • 2:42
    by returning more than one element in this array.
  • 2:45
    So we've got our RGB text field as a human readable label
  • 2:49
    and we've added a field types key to tell Drupal which particular field
  • 2:54
    types this widget can be used for.
  • 2:56
    There's some additional keys that we could add here as well.
  • 2:59
    We could add a short description to go with our widget.
  • 3:02
    And then we have this settings key, which is an array whose keys are
  • 3:05
    the names of the settings available for the widget type.
  • 3:08
    This hints that widgets can have per instance settings.
  • 3:12
    A good example of this would be the file field.
  • 3:15
    When you add a new file field to any content type,
  • 3:18
    one of the things you can set is what type of file
  • 3:21
    should this field be allowed to have uploaded.
  • 3:24
    So you have a text field which allows you to enter in things
  • 3:27
    like the extension of files that you can upload.
  • 3:29
    These are per field instance settings.
  • 3:33
    The widget can also define optionally
  • 3:35
    how you would like to handle the scenario
  • 3:38
    where you have a multiple value field.
  • 3:40
    So when you've set your field to say,
  • 3:41
    I would like to be able to collect unlimited values instead of just
  • 3:44
    one, do you want Drupal to handle that use case for you?
  • 3:48
    Or do you want to write some custom code
  • 3:50
    to handle the implementation of that multivalue widget?
  • 3:54
    We've already got this basic hook_field_widget_info though,
  • 3:57
    so we'll stick with what we've got for now.
  • 4:00
    The other key to this puzzle is the hook_field_widget_form.
  • 4:04
    Let's look at the documentation for that.
  • 4:06
    So again on api.drupal.org, I've pulled up the documentation
  • 4:09
    for hook_field_widget_form, which takes a handful of arguments
  • 4:13
    and then returns the form for a single field widget.
  • 4:16
    Really, we just return the form element or a form API array that
  • 4:20
    defines the element that we would like
  • 4:22
    to display to users to collect data.
  • 4:24
    It might be a text field, might be a check box.
  • 4:26
    Whatever the use case, we need to set up that form API array
  • 4:30
    in our implementation of hook_field_widget_form.
  • 4:33
    When our hook is called, we get some additional information passed in.
  • 4:36
    Form and form state are pretty standard for anything
  • 4:38
    that handles form API forms.
  • 4:41
    $field and $instance here refer to the global definition of the field
  • 4:47
    and the per instance definition of this field
  • 4:50
    as it relates to the widget.
  • 4:51
    So we can make adjustments to our widget
  • 4:53
    based on settings in that field instance.
  • 4:56
    Language code items is an array that contains all of the values that
  • 5:00
    were previously set for this field for a particular entity.
  • 5:04
    So if we had saved our node, this would contain any data that
  • 5:07
    had been set before so we can display it to users to edit.
  • 5:11
    Delta refers to this value that is being displayed.
  • 5:15
    So if we have a multivalue field that can hold say, three
  • 5:19
    possible field values, this function hook_field_widget_form gets called
  • 5:23
    once for each value that we want to--
  • 5:26
    or each field that we want to provide,
  • 5:27
    each value we need to display.
  • 5:29
    And this delta is incremented to indicate this is the first time,
  • 5:33
    this is the second time, this is the third time,
  • 5:35
    that the function has been called.
  • 5:36
    I'll also point out that hook_field_widget_form
  • 5:39
    is an anomaly in hooks in that it's not one that you can just implement
  • 5:43
    hook_field_widget_form in any module and have it called
  • 5:47
    for a widget for some other module.
  • 5:49
    This hook_field_widget_form-- or in our case,
  • 5:52
    rgb_field_widget_form-- will only be called
  • 5:56
    for field types that are defined by the RGB module.
  • 6:00
    Let's go ahead and look at implementing
  • 6:02
    hook_field_widget_form in our own code.
  • 6:06
    If I switch back over to my editor, the first step here
  • 6:08
    is just going to be adding a simple implementation of the hook.
  • 6:11
    It might look something like this.
  • 6:14
    So I've declared the function rgb_field_widget_form.
  • 6:17
    I could have put this anywhere in the module
  • 6:19
    but I like to keep my hooks related to field types,
  • 6:23
    field widgets, and field formatters grouped together.
  • 6:25
    So I put this right under our implementation
  • 6:27
    of hook_field_widget_info.
  • 6:29
    I find that it just makes it a little bit easier to read.
  • 6:32
    In here, I need to make changes to this $element array, which contains
  • 6:38
    the already stubbed out widget, and add some form
  • 6:42
    API elements that will allow collection of data.
  • 6:45
    So I'm going to have to return that element.
  • 6:48
    So, if you think about the data that we're storing for our RGB color
  • 6:53
    field, we need to collect the hex value of the color and a label
  • 6:57
    to go with that color or the color name.
  • 6:59
    So our widget is actually going to consist of two text fields.
  • 7:03
    Let's go ahead and add those text fields to this $ element.
  • 7:08
    So I start by adding a new element with the name RGB.
  • 7:11
    The name here is important.
  • 7:12
    This actually matches the name of the column
  • 7:15
    that I defined in my hook field schema in the previous lesson.
  • 7:19
    This allows the field API to know which column to save this value
  • 7:23
    into and to handle that for me automatically.
  • 7:26
    Now I can just make this a simple text field.
  • 7:29
    So I have an array, a form API array, type text field.
  • 7:33
    I've added a field prefix here rgb colon and then the pound sign.
  • 7:38
    And make it easier for people to understand,
  • 7:40
    I should enter in a hex value here.
  • 7:42
    I've set the size to six because these colors
  • 7:45
    are only ever six characters long.
  • 7:48
    The other thing that I'll need to do here
  • 7:50
    is deal with what happens when there's
  • 7:52
    already a value for this field.
  • 7:55
    So I need to set the default value.
  • 7:58
    And this is where the $items variable comes into play.
  • 8:01
    $items, I said, contains the values that
  • 8:04
    were previously set for this field, if any.
  • 8:07
    So I'll do an is set, items, delta, rgb.
  • 8:17
    So if there is a value, let's assign the value of this field to that.
  • 8:22
    Otherwise, we'll just leave it blank.
  • 8:24
    So just a reminder, this function rgb_field_widget_form
  • 8:29
    will be called once for every possible field value.
  • 8:33
    So if our field is set to have a cardinality of three--
  • 8:36
    so you could have three values in this field--
  • 8:38
    this function will be called three times
  • 8:40
    and the delta will be incremented each time items contains the values
  • 8:44
    that were previously set for this field.
  • 8:47
    The other thing I'm going to need is a simple label field.
  • 8:49
    So I'll actually just copy and paste the RGB field
  • 8:52
    that we already created.
  • 8:54
    So I'll change the name here to label.
  • 8:59
    I'll update the default value code like so.
  • 9:03
    And we'll change this to say, Color name, like so.
  • 9:12
    We can remove the size because this is an unlimited size there.
  • 9:16
    All right.
  • 9:17
    So now we've got a simple label field as well
  • 9:19
    and we're returning it.
  • 9:20
    I'm going to save my code and I'm going
  • 9:22
    to switch back over to our site.
  • 9:24
    Back on my site, if I click on the Add Content link
  • 9:28
    and now go to Article, and I scroll down,
  • 9:32
    you could now see the RGB and Color name field that were added
  • 9:36
    by our implementation of hook_field_widget_form
  • 9:39
    are displayed here on the article content type form.
  • 9:42
    So great, we've now provided a way for someone
  • 9:44
    to enter in a value for our field.
  • 9:48
    You'll note though that there's some missing information here.
  • 9:51
    Look at the Image field.
  • 9:52
    You could see the label that was added for this Image field is
  • 9:55
    displayed as well as the help text.
  • 9:57
    Ours isn't showing.
  • 9:58
    Same for the Body field.
  • 9:59
    You can see the label and some additional information.
  • 10:03
    So in order to see why this isn't showing right now,
  • 10:05
    let's switch back over to our code.
  • 10:07
    And I'm going to add a DSM element here, like so.
  • 10:12
    DSM provided by the devel module will allow us to just print out
  • 10:15
    the contents of this $element array and we can see what's going on.
  • 10:20
    If I switch back to the site and refresh,
  • 10:23
    you see it printed out at the top there.
  • 10:25
    And if I expand that, you can see that that contained a stubbed
  • 10:29
    out widget with some information about the entity
  • 10:32
    that this particular field instance has been applied to.
  • 10:35
    And then we've gone and added the RGB
  • 10:37
    and label elements as children of this.
  • 10:40
    However, this element itself, the parent, doesn't have a type.
  • 10:45
    So it's not going to be displayed unless we
  • 10:47
    tell it what type of element this is.
  • 10:50
    I'm going to go ahead and set this to a field set.
  • 10:53
    So if I switch back to my code, I'm going to say,
  • 10:57
    element type equals field set.
  • 11:03
    This is actually element pound type, like so.
  • 11:07
    Back to my site, refresh the page, and when I scroll down,
  • 11:12
    you can see this has been converted to a field set.
  • 11:14
    We can see the label.
  • 11:15
    If we had defined help text for this field instance,
  • 11:18
    that would show up here as well.
  • 11:20
    Great.
  • 11:20
    So that's working.
  • 11:23
    And the way that the field system works,
  • 11:25
    if this was a multivalue field, our function would get called x number
  • 11:29
    of times and it would display this field set three times
  • 11:33
    or four times or however many values this field had.
  • 11:36
    That's not necessarily what we want though.
  • 11:38
    So back in our code, we can make a couple of adjustments
  • 11:41
    to account for this.
  • 11:42
    In our code, we've got this $field variable, which
  • 11:47
    defines the global field definition.
  • 11:49
    I'm going to print that out right now.
  • 11:51
    So I'm going to say DSM field.
  • 11:54
    Switch back to our site and click refresh.
  • 11:58
    So now this DSM print out contains information about the field
  • 12:02
    as it's been defined within the field UI.
  • 12:05
    And you'll see that one of the properties of this array
  • 12:08
    is cardinality.
  • 12:09
    This refers to the number of values that
  • 12:12
    can be collected for this field.
  • 12:13
    Right now, it's set to one.
  • 12:15
    Negative one would indicate that this had an unlimited value.
  • 12:18
    Or if it had a different number, there
  • 12:20
    are going to be three or five or 10 widgets displayed
  • 12:24
    for collecting values for this field.
  • 12:26
    In my code, I want to make use of this information to just wrap
  • 12:31
    our existing element type equals field set so that we're only
  • 12:35
    setting it as a field set when the cardinality is one.
  • 12:37
    Switch back to code.
  • 12:40
    Go ahead and delete this DSM.
  • 12:41
    I'm going to say if field cardinality is equal to one,
  • 12:46
    change this to a field set.
  • 12:48
    Otherwise, don't.
  • 12:49
    Because the field API will take care of rgb_field_widget_form
  • 12:54
    function once for each field value, displaying those inside
  • 12:59
    of the default container for collecting multiple field values.
  • 13:04
    So we'll go ahead and save that.
  • 13:05
    And now we've got a really basic form
  • 13:07
    for allowing people to enter data.
  • 13:10
    Back in our site, click refresh.
  • 13:13
    We implemented rgb_field_widget_form in order to add two text fields.
  • 13:20
    One for collecting an RGB hex value, something like 663399,
  • 13:25
    and another for collecting a color name.
  • 13:28
    We could say, green.
  • 13:30
    We haven't yet implemented the functionality
  • 13:33
    that will allow this value to be saved.
  • 13:35
    We'll take a look at validating and saving the data in the next lesson.
  • 13:39
    [WATER DROP NOISE]

Creating Field Widgets For Collecting User Input

Loading...

The term widget refers to the form element, or elements, that are presented to the user when they are entering data for a field. For example, the file upload field on the Article content type is the widget for the image field attached to that content type. When a field instance is attached to a bundle and an admin is creating or editing an entity of that bundle type the Field Attach API calls out to each individual field and asks it for the widget it would like to use to collect data. Adding a widget for a custom field type is a combination of implementing hook_field_widget_info() and hook_field_widget_form().

Examples:


/**
 * Implements hook_field_widget_info().
 */
function rgb_field_widget_info() {
  return array(
    'rgb_textfield' => array(
      'label' => t('RGB Textfields'),
      'field types' => array('rgb_color'),
    ),
  );
}

/**
 * Implements hook_field_widget_form().
 */
function rgb_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {

  if ($field['cardinality'] == 1) {
    $element['#type'] = 'fieldset';
  }

  $element['rgb'] = array(
    '#type' => 'textfield',
    '#field_prefix' => t('RGB: #'),
    '#size' => 6,
    '#default_value' => isset($items[$delta]['rgb']) ? $items[$delta]['rgb'] : '',
  );

  $element['label'] = array(
    '#type' => 'textfield',
    '#field_prefix' => t('Color name: '),
    '#default_value' => isset($items[$delta]['label']) ? $items[$delta]['label'] : '',
  );

  return $element;
}
Downloads: 
Log in or sign up to download companion files.