Upgrade Your Drupal Skills

We trained 1,000+ Drupal Developers over the last decade.

See Advanced Courses NAH, I know Enough
Mar 11 2013
Mar 11

Drupal's content modeling toolbox makes it easy to add simple values to any content type -- numbers, text fields, dates, and so on -- but odd gaps pop up occasionally. Numeric ranges, for example, can be frustrating: While you could add separate "minimum" and "maximum" fields to a content type, it's a bit frustrating to split conceptually related set of values into distinct fields. Thankfully, the Range module can fill the gap.

Screenshot of administration screen

Range field gives site builders and administrators a single field type with two values: minimum and maximum. Variants for each basic numeric type are available (Float range, integer range, and so on), and the module provides enough formatting options to capture most of the basic use cases for the field. Views integration is also baked in, making it possible to sort and filter by the range values as well.

Screenshot of resulting change to site

A handful of existing feature requests for the module suggest potential improvements: the Views filter would be even more useful if it could pull up nodes nodes whose ranges included the incoming filter value, for example. While it's possible to simulate that using a pair of filters working together, it's definitely not as convenient. That request aside Range is a clean and simple field module that fills an awkward gap. If your content types need ranges, it's just what you need!

*/
Oct 22 2012
Oct 22

Posted Oct 22, 2012 // 0 comments

Some time back, I wrote a blog post entitled Compound fields in Drupal 7 where I discussed how to create custom fields for your content types using Field API. Since then, I've often been asked how to create custom fields for use in forms (using Form API), outside of using those fields in entities such as nodes and taxonomy terms.

Assuming you've read that blog post, I'll now show you how to extend an existing custom field into a form element that you can use in any FAPI form.

Hooks

To extend your field, you'll need to add some additional hooks to your module. It's important to note that you can extend any field into a form element that exists in Drupal, not just something defined by your module.

hook_element_info -- This hook tells Drupal about your form element.

1
2
3
4
5
6
7
8
9
10
11
12
function dnd_fields_element_info() {
  return array(
    'dnd_fields_attribute' => array(
      '#input' => TRUE,
      '#tree' => TRUE,
      '#process' => array('dnd_fields_attribute_process'),
      '#element_validate' => array('dnd_fields_element_validate'),
      '#theme' => array('dnd_fields_element'),
      '#theme_wrappers' => array('form_element'),
    ),
  );
}

Process Functions

In hook_element_info, we named a processor function that will define how our new form element should be processed.

In this example, we are "faking" a field instance so that we can reuse the field widget defined in hook_field_widget_form (dnd_fields_field_widget_form). If you prefer, you can skip to the next code sample to create a standalone element processor function without relying on what requirements this Field API hook has.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
function dnd_fields_attribute_process($element, &$form_state) {
  // Create a dummy field instance just to get the same output from our existing field widget
  $instance = array(
    'field_name' => 'dnd_fields_ability',
    'settings' => array(),
    'widget' => array(
      'type' => 'dnd_fields_ability',
    ),
  );
 
  $form = array();
  $field = array(
    'settings' => array(
      'abilities' => array(),
    ),
  );
  $langcode = LANGUAGE_NONE;
  $items = array();
  $delta = 0;
  $form_state['field'] = array(
    'dnd_fields_ability' => array(
      $langcode => array(
        'field' => array(
          'type' => 'dnd_fields_ability',
          'cardinality' => 6,
          'settings' => array(),
        ),
      ),
    ),
  );
 
  $element = dnd_fields_field_widget_form($form, $form_state, $field, $instance, $langcode, $items, $delta, $element);
  return $element;
}

If you are creating a new form element that does not come from an existing field, you will want this instead:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
function dnd_fields_attribute_process($element, &$form_state) {
  $fields = array(
    'ability' => t('Ability'),
    'score' => t('Score'),
    'mod' => t('Modifier'),
    'tempscore' => t('Temp score'),
    'tempmod' => t('Temp modifier'),
  );
 
  foreach ($fields as $key => $label) {
    $element[$key] = array(
      '#attributes' => array('class' => array('edit-dnd-fields-ability'), 'title' => t('')),
      '#type' => 'textfield',
      '#size' => 3,
      '#maxlength' => 3,
      '#title' => $label,
      '#default_value' => NULL,
      '#attached' => array(
        'css' => array(drupal_get_path('module', 'dnd_fields') . '/dnd_fields.3x.css'),
        'js' => array(drupal_get_path('module', 'dnd_fields') . '/dnd_fields.3x.js'),
        ),
      '#prefix' => '<div class="dnd-fields-ability-field dnd-fields-ability-' . $key . '-field">',
      '#suffix' => '</div>',
    );
  }
 
  return $element;
}

Technically, we're done. You now have a form element that you can define in any Form API code. For example:

1
2
3
4
5
6
7
8
9
10
11
12
13
function dnd_character_test_form($form, &$form_state) {
  $form = array();
  $form['test'] = array(
    '#type' => 'dnd_fields_attribute',
    '#title' => t('Attribute fields'),
    '#description' => t('Provide a description here.'),
  );
  $form['submit'] = array(
    '#type' => 'submit', 
    '#value' => t('Submit'), 
  );
  return $form;
}

Themeing your Element

The cool thing with your new form element is that you can theme it, even though this is not strictly neccessary, since the widget defined in the field will handle most of this for you. So feel free to skip this step if you're already happy with the Field API widget that you have.

The following code sample displays a generic form output, since the field that we defined is really just a special case of the 'textfield' form element type. However, you can feel free to get fancy here, and display literally any HTML output you want.

Also of note is that this is just like any other theme function in Drupal. You can refine this more using preprocess theme functions and .tpl.php files to theme your form element even more. However, for this example, I'm going to keep it simple.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function theme_dnd_fields_element($variables) {
  $element = $variables['element'];
 
  $attributes = array();
  if (isset($element['#id'])) {
    $attributes['id'] = $element['#id'];
  }
  if (!empty($element['#attributes']['class'])) {
    $attributes['class'] = (array) $element['#attributes']['class'];
  }
  $attributes['class'][] = 'dnd-fields-ability';
 
  // This wrapper is required to apply JS behaviors and CSS styling.
  $output = '';
  $output .= '<div' . drupal_attributes($attributes) . '>';
  $output .= drupal_render_children($element);
  $output .= '</div>';
  return $output;

As one of our superb Team Architects, Tobby Hagler expertise spans the gamut of technical capabilities -- from interface development to application layer engineering and system architecture.

Tobby’s specialties tend to focus on ...

Apr 17 2012
Apr 17

Oh, scrolling multi-select form elements. Does anyone really like them? Picking multiple items from one of these widgets often requires option-control-alt-clicking your way through a long list, hoping you don't accidentally deselect the options you've carefully chosen. Drupal's default Select Widget allows you to use convenient dropdown select menus to choose the contents of single-value fields, but if you have a multi-value field, you're out of luck. Wouldn't it be great to give content editors a list of several single-select dropdowns, rather than the unruly multi-select box? It would, and that's precisely what the Multi Selects module does.

Screenshot of Multiple Selects being added

Like many cool Drupal 7 tricks, Multiple Selects is a field editing widget that can be used with multi-value list fields like Text and number lists, as well as taxonomy term references. No configuration is necessary -- just set the field's widget to "Multiple Selects," and you're ready to go. Rather than a single scrolling multi-select box, content editors will see single-select dropdowns, with the traditional FieldAPI 'Add another item' button below.

Screenshot of Multiple Selects in action

In addition to providing a slightly cleaner editing interface, this approach allows editors to choose the order in which their field values appear. Adding five taxonomy terms and then dragging them into the correct order is impossible with a multi-select box, but works fine once Multiple Selects is enabled. The only downside is that it doesn't support node, user, or entity reference fields yet. That addition is a minor change, though, and a patch to add it has already been posted. If you're looking for a simple multi-value select widget that also gives your editors control over the order of the values entered, look no farther than the Multiple Selects module.

*/
Apr 28 2009
Apr 28

The Field API is major new functionality in Drupal 7 to provide custom data types just like CCK did for previous versions of Drupal. Field API became part of Drupal 7 February, 2009, but there is still plenty of work to do. We need your help, and we’ll help you learn what you need to know to contribute.

The Field API is a great way to get yourself involved directly in Drupal core development. We realize, however, that Field API is a big, new, scary chunk of code that is not the easiest thing to jump into. The Field API team wants to help you get up to speed, so we’ve created the Field API mentoring process. Here’s our promise: If you assign a Field API issue to yourself and take responsibility for it, the Field API mentors will help you learn what you need by participating in the issue and answering questions on IRC.

We’ve created a Field API contributor page at drupal.org that describes (most of) the open issues and their degree of difficulty. If you want to grab one but have some questions about that part of Field API, ask about it over at Field API: What do you want to know? and we can add it to the documentation.

Apr 27 2009
Apr 27
Field API: What would you like to know? | Barry Jaspan

The Field API is major new functionality in Drupal 7 to provide custom data types just like CCK did for previous versions of Drupal. The Field API team has written fairly thorough API documentation but that is more useful as reference material than as a tutorial or HOWTO handbook.

So, here’s your chance to tell the Field API team what you want to know how to do. Comment on this post telling us what we should explain.

One option is to give us the title of HOWTO pages you’d like to read, such as:

  • What is the difference between a Field, Bundle, and Field Instance?
  • How do I add a Text field to a node type?
  • How do I add an Image field to users?
  • How do I get a list of all defined Fields and Field Instances?
  • etc.

Special thanks to chx for having the idea and offering to write some of the articles! (No good deed goes unpunished…)

About Drupal Sun

Drupal Sun is an Evolving Web project. It allows you to:

  • Do full-text search on all the articles in Drupal Planet (thanks to Apache Solr)
  • Facet based on tags, author, or feed
  • Flip through articles quickly (with j/k or arrow keys) to find what you're interested in
  • View the entire article text inline, or in the context of the site where it was created

See the blog post at Evolving Web

Evolving Web