Drupal Custom Elements API Errors

Posted on July 29, 2013, 4 p.m.

The Drupal Form API is powerful, but very extensive and complicated. In another post we discussed how to add a custom element from scratch. Watch out for the errors and mistakes highlighted in this advanced-level post.

Element and Field Defaults

To fully understand the API, you need to understand how elements are built. When you define a form field, custom or not, you have to give it a #type.

When the form is being built, Drupal will look at the #type and decide what to do with it. If it's a custom element you've defined, Drupal will look at the hook_element_info() that defined that custom element, and grab all the information from that array. That is, keys and values in that array will be merged into your field. This allows you to set defaults for that element #type. Let's look at an example. For simplification, let's define a basic custom element type:

1
2
3
4
5
6
7
8
<?php

function example_element_info() {
  $elements['custom_element'] = array(
    // Element declaration here ...
  );
  return $elements;
}

Note that this element won't do much. But now, let's use it in a form:

1
2
3
4
5
6
7
8
<?php

function example_some_form() {
  $form['my_field'] = array(
    '#type' => 'custom_element',
  );
  return $form;
}

If we want each usage of the element to, by default, have certain properties, we can just add it to the hook_element_info() function. So doing this:

1
2
3
4
5
6
7
8
9
<?php

function example_element_info() {
  $elements['custom_element'] = array(
    // Rest of element declaration here ...
    '#some_property' => 'some_property',
  );
  return $elements;
}

Will mean that all uses of your element in forms would be as if you had declared the form like so:

1
2
3
4
5
6
7
8
9
<?php

function example_some_form() {
  $form['my_field'] = array(
    '#type' => 'custom_element',
    '#some_property' => 'some_property',
  );
  return $form;
}

In other words, #some_property will "bubble" up from the element declaration to the actual element useful.

Learning Drupal? Subscribe to my Drupal articles, tips and tutorials.

This means you can do powerful things, like declaring default #theme functions, default #prefix and #suffix content, etc.

To summarize: the form declaration for that element will get merged to the properties defined in hook_element_info(). So keep this in mind when defining your custom elements.

Hook Theme and Render Element

So you've defined your custom element, but now want to control its appearance. Easy right? Just give it a #theme function in hook_element_info(). Well, it's not that simple.

You might notice it's not rendering now or ignoring your theme function. So you go and add that function to the theme registry, using hook_theme().

But now we have another problem: our theme function isn't being called with the right arguments. That's because when defining this function in hook_theme(), you need to use the render element property, rather than your typical variables property. As follows:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
<?php

// DO THIS
function example_theme() {
  return array(
    'gitbucket_field' => array(
      'render element' => 'element',
    ),
  );
}

// NOT THIS
function example_theme() {
  return array(
    'gitbucket_field' => array(
      'variables' => array('element' => NULL),
    ),
  );
}

And there you go: two big secrets about custom Drupal elements. With this knowledge on hand, you should be able to create all the custom elements you'll need. Without surprises.