Start your free trial now, and begin learning software, business and creative skills—anytime, anywhere—with video instruction from recognized industry experts.

Start Your Free Trial Now

Fleshing out a content type with fields


Drupal 7 Custom Module Development

with Jon Peck

Video: Fleshing out a content type with fields

Before describing how to add custom fields, some background is needed. Drupal 7 introduced an abstracted mechanism for handling data that made it possible to share the same Application Programming Interface for managing data structures and how the data structures relate. This API is known as The Entity API. At the highest level, an entity type is an abstract group of fields. A field is a reusable data container holding primitive data types such as text, numbers, and so forth.
please wait ...
Watch the Online Video Course Drupal 7 Custom Module Development
2h 57m Advanced Oct 16, 2012

Viewers: in countries Watching now:

Extend your Drupal 7 sites with custom modules, which allow you to create everything from admin interfaces to forms. Author Jon Peck describes how modules extend your base Drupal installation, then walks through how to write your own module with a practical example featuring geo-positioned alternative energy centers. The course also describes how to control access to site features, create new content types, build forms, understand data persistence, embrace coding standards, and much more.

Topics include:
  • Creating your first module
  • Interacting with hooks
  • Working with permissions and roles
  • Controlling access
  • Adding a menu item to an admin interface
  • Using the Form API (FAPI) to quickly create a form
  • Creating custom form validation
  • Manually creating a custom content type
  • Validating user input
  • Importing content using feeds
  • Creating a block
  • Understanding best practices and coding standards
Developer Web
Jon Peck

Fleshing out a content type with fields

Before describing how to add custom fields, some background is needed. Drupal 7 introduced an abstracted mechanism for handling data that made it possible to share the same Application Programming Interface for managing data structures and how the data structures relate. This API is known as The Entity API. At the highest level, an entity type is an abstract group of fields. A field is a reusable data container holding primitive data types such as text, numbers, and so forth.

An example of an entity type is a node, and nodes have both the title stored as text, and a unique identifier the node ID stored as a number. An entity is an instance of an entity type, and any given entity has the same fields. For example, node ID number 12 has the title of Finn, and node ID number 28 is called Jake. Both nodes have the same fields, title, and node ID, but the values can be different. Entity types can be sub-classed as a bundle.

A bundle is an entity type with a predefined collection of attached fields. Each bundle has the fields that are in the entity type along with a group of additional fields. So to continue the example, a Wind Farm is a bundle of the entity type node and contains additional fields for the latitude and longitude. When a field is attached to a bundle, it's attached as a field instance. This distinction allows a field to be attached to multiple bundles without having to duplicate the field.

Currently, the wind farm content type has no fields. The title is actually stored as part of the node table. Let's add a field that contains a description of a Wind Farm facility. Both the basic page and article have a body field and many content types have a similar field. Recognizing that, Drupal has a helper function to add the body field with logical defaults. A body field is optional, so if there's no need for it, it can be emitted cleanly. Navigate to hook_install after the node_type_save.

The function node_add_body_field takes two parameters; a node type and a translated field for the label. It handles the creation of the field if necessary and creates an instance to relate the fields of the content type. Add a field for the body, node_add_body_field which takes the node type, and then Description as a translated string. If I were to save right now and install these changes, I would have a Wind Farm with a facility name and description; functional but too minimal to be useful.

Now comes the true custom functionality, adding the custom fields to the content type. There are two steps: the creation of the field itself, then attaching the field as an instance to the content type. I will be using the function field_create_ field which takes a standardized array definition of a field structure to create the fields themselves. While I could just call field_create_field with an array, the resulting code can get a bit messy. Therefore, I will create an array keyed by the field name with a nested array containing the field definition.

At the end, I'll loop through the array, and call field_create_field with each value; Create fields, $fields = array() The fields name needs to be all in lowercase and a maximum 32 characters long. It also needs to be completely unique in any Drupal site installation. The only allowed special character is an underscore which I can use instead of a space. It's best practice to start with a content type name followed by a concise description of the contents.

The first field I will add is for the number of units at a given Wind Farm; $fields 'windfarm_unit_count' = array. The first key is the 'field_name' which is the same as the key; 'windfarm_unit_count'. Next, the type. Drupal provides several field types. The defaults include file, image, number decimal, number integer, number float, text, and text long.

As the count is a whole number, I'll use 'number_integer'. The next key is optional; the cardinality, which refers to the number of values that can be stored in the field. The default is 1, meaning 1 value per field. If you set cardinality to the constant field cardinality unlimited, then there is no limit to the number of values that can be stored; Optional, 'cardinality' => 1.

Finally, 'settings' for the data itself. A maximum length is needed for the default form elements that will be generated automatically. Settings is a nested array, so we'll set the 'max_length' to 5. That's all that is needed for a field. Next, I'll define the fields for latitude and longitude using number_float and a maximum length of 20; $fields 'windfarm_latitude' = array(, so the 'field_name' is 'windfarm_latitude'.

The 'type' is 'number_float', 'settings' is an array that contains the 'max_length' of the form element which will be 20. I am going to copy the latitude, and paste it for the longitude. The last field needed is a text field to contain the name of the turbine manufacturer.

I'll use a maximum length of 60; $fields 'windfarm_turbine_manufacturer' = array(, 'field_name', the same, the 'type' is 'text' and for the 'settings', I'll copy those, 'max_length' will be 60.

Now that the fields have been defined, I'll iterate through the array and call field_create_field on each field; foreach ($fields as $field) {, field_create_field ($field). By creating the fields, there is now a place to store the data. However, there is currently no way for the content type to know about the fields. Therefore, I will create field instances for each field which will relate the field to the bundle which in this case is the content type windfarm.

To do so, I'll use the function field_create_ instance which takes one parameter; a standardized array definition of an instance. Similar to fields, I will define them one at a time and iterate over the array and create each of them. I will also leave off two settings for each until the loop as they're exactly the same. Start by creating an empty array for the instances; Create Field Instances, $instances = array().

I will need to create a field instance for each field that was created: windfarm's unit count, windfarm's latitude, windfarm's longitude, and windfarm's turbine manufacturer. I'll keep them in the same order that the fields were created in. Instances have a dual purpose. Not only do they relate a field to the bundle, they also provide the definitions for how the user interfaces interact with the field; $instances 'windfarm_unit_count' = array(). Similar to field creation, the first thing that should be defined is the field's name; 'field_name' => 'windfarm_unit_count'.

Next, a label which is user facing. The value is a string that should be wrapped in the t variable for localization. The label is used both in generated forms for editing and on the default display; $t(Number of Units). Following the label is a description of the field. This can be thought of as help text, as by default, it's only shown when editing a field. Like the label, it should be wrapped in the t variable.

The description is optional but highly recommended, $t( 'Number of individual units at a given Facility'). In Drupal, a widget provides the form API elements used when creating and editing content along with standardized validation. While I can define my own widgets, Drupal comes with a number of widgets that can be leveraged to save time. In particular, text which includes textfield, textarea, and textarea with summary, options including select, buttons, and on and off, then file and image.

For this module, all I need is text to text field. The widget is set with an array containing a type. Other options are available such as weight for specifying the order of elements in the form. I will cover weight in an upcoming segment. So 'widget' => array. Then, the 'type' => 'text_textfield'. An optional key is required. This forces the user to provide a value.

If left out, the field won't be required; 'required' => TRUE; 'settings'. Settings is a nested array, similar to the field definition. In this case, only one thing is needed; text processing. This affects several things including the widget and display. If set to 0, then the content will be treated like plain text and sanitized. If set to 1, then the interface will allow the selection of the text format like plain text, filtered HTML, and full HTML.

For a number, leaving it at 0 is optimal; 'text_processing' => 0. That's all that is needed for the first instance. The next windfarms_latitude will be very similar for the first half; $instances 'windfarm_latitude' = array, name is windfarm_latitude, 'label' is passed with the t variable, ('Latitude'), the 'description' => $t('Signed degrees format (DDD.dddd)'), the 'widget' => array(), containing a 'type' => 'text_textfield'.

For 'settings', do an array of 'text_processing' which again I'll set to 0 as this is a number. Now that I defined the label and widget settings, I will add a new section called display. Display controls how the content type is displayed. Similar to settings, display takes an array keyed by the name of how the content is being viewed. Default is used to refer to any view that doesn't already have an explicit method for displaying the content.

You can also specify something for default than something else for a particular view such as full, which is used when viewing the node itself. While it's useful to know the latitude and longitude of a Wind Farm, I want to hide it from users. Therefore, I'll set the type to hidden for all views. So display is going to be set to an array, key default is a nested array, and the type will be hidden.

Longitude can be set up in the exact same way. I'll paste from the previous instance. Change latitude to longitude, and the label to longitude. Finally, the turbine manufacturer; $instances 'windfarm_turbine_manufacturer' = array(, the field name which I will set to the value above, the 'label' which is turbine_manufacturer, the description which is the name of the Turbine Manufacturer.

Then, the 'widget' which I'll set to array, 'type' => 'text_textfield'. I'll add an additional setting for display. A modifier that will show the label for the turbine manufacturer in-line with the value, as opposed to above, which is the default and hidden which I used previously; 'display' => array, 'default' and array again, and the 'label' will be inline.

Now that the instances have been defined, I'll set up the loop to create each instance; foreach ($instances as $instance). As mentioned before, two keys are required that haven't been set yet. The first defines the entity type, which in this case is a node; $instance 'entity_type' = 'node'. The second is the bundle. In the context of a node, the bundle is the content type.

And since the content type is windfarm, the bundle is set to windfarm; $instance 'bundle' = 'windfarm'. Finally, called Field Create Instance with a standardized array; field_create_instance($instance). Save, then return to the browser. As the content type is created when the module is installed, I will have to disable the module by going to Modules, scroll to the bottom, uncheck Enabled next to Wind Farms and save configuration.

Then, go to Uninstall, and uninstall the Wind Farms module, and confirm. And go back to list, enable Wind Farms, and save configuration. Then, go to Content > Add Content, and the new content type Wind Farm should be listed.

We'll enter in some valid data, Caney River Wind Project for the Facility Name. For the Description, I will add the actual location which is in Elk County, Kansas. There are 111 units, and the Latitude which is at 37.448424 degrees, and the Longitude which is -96.425027, and the Manufacturer is Vestas.

Save the Wind Farm. The Facility Name is used as the title of the page. The Description is shown underneath. The label for Number of Units is shown above the Content, while the Turbine Manufacturer is shown in-line. Latitude and Longitude are not shown at all. There's also a new tab visible put there by the Develop Module called Devel. Click on it now. The Devel tab just displays the contents of the nodes including the keys and any nested values.

It's very useful if you want to know the node structure. For example, click down to body which has an Array. It has one key, und, which is actually the name of the language. Currently, the content of language is not defined. So Drupal refers to that as und for short. The language contains only one element which is same as the cardinality. You can see that there is a value which is how it is stored in the database, a format which defaulted to filtered _html, and a safe_value. This is what shown to the user and has been properly sanitized.

There are two tabs of the Devel; the first default is Load. This is the node itself. The second, Render, is the standardized array structure that is used for displaying the contents of the node when the contents are rendered by the theme. Go back and edit the node, and put in some bogus data for the Number of Units like the word apple. Then save. A PDOException; that's pretty catastrophic and indicates that I attempted to save text in a numeric database field. Clearly, validation is needed to prevent this from happening.

Find answers to the most frequently asked questions about Drupal 7 Custom Module Development .

Expand all | Collapse all
please wait ...
Q: gmap3_tools is not working the way I expected it to. What version of gmap3_tools should I be using?
A: Use the free exercise file containing the version of gmap3_tools used for recording; the published version of the module on has changed since recording and is not backwards compatible.
Q: I attempted to run the Drupal site root from the project files, but the site isn't loading. Why not?
A: The Drupal configuration file in sites/default/settings.php contains database configuration specific to the environment used to record the movie. This may be different than your environment. Edit the file and search for "windfarms" - you may need to change the database host, username, password, db name and port to match your specific environment.
Share a link to this course

What are exercise files?

Exercise files are the same files the author uses in the course. Save time by downloading the author's files instead of setting up your own files, and learn by following along with the instructor.

Can I take this course without the exercise files?

Yes! If you decide you would like the exercise files later, you can upgrade to a premium account any time.

Become a member Download sample files See plans and pricing

Please wait... please wait ...
Upgrade to get access to exercise files.

Exercise files video

How to use exercise files.

Learn by watching, listening, and doing, Exercise files are the same files the author uses in the course, so you can download them and follow along Premium memberships include access to all exercise files in the library.

Exercise files

Exercise files video

How to use exercise files.

For additional information on downloading and using exercise files, watch our instructional video or read the instructions in the FAQ .

This course includes free exercise files, so you can practice while you watch the course. To access all the exercise files in our library, become a Premium Member.

* Estimated file size

Are you sure you want to mark all the videos in this course as unwatched?

This will not affect your course history, your reports, or your certificates of completion for this course.

Mark all as unwatched Cancel


You have completed Drupal 7 Custom Module Development.

Return to your organization's learning portal to continue training, or close this page.


Upgrade to View Courses Offline


With our new Desktop App, Annual Premium Members can download courses for Internet-free viewing.

Upgrade Now

After upgrading, download Desktop App Here.

Become a member to add this course to a playlist

Join today and get unlimited access to the entire library of video courses—and create as many playlists as you like.

Get started

Already a member ?

Exercise files

Learn by watching, listening, and doing! Exercise files are the same files the author uses in the course, so you can download them and follow along. Exercise files are available with all Premium memberships. Learn more

Get started

Already a Premium member?

Exercise files video

How to use exercise files.

Ask a question

Thanks for contacting us.
You’ll hear from our Customer Service team within 24 hours.

Please enter the text shown below:

Exercise files

Access exercise files from a button right under the course name.

Mark videos as unwatched

Remove icons showing you already watched videos if you want to start over.

Control your viewing experience

Make the video wide, narrow, full-screen, or pop the player out of the page into its own window.

Interactive transcripts

Click on text in the transcript to jump to that spot in the video. As the video plays, the relevant spot in the transcript will be highlighted.

Learn more, save more. Upgrade today!

Get our Annual Premium Membership at our best savings yet.

Upgrade to our Annual Premium Membership today and get even more value from your subscription:

“In a way, I feel like you are rooting for me. Like you are really invested in my experience, and want me to get as much out of these courses as possible this is the best place to start on your journey to learning new material.”— Nadine H.

Start your FREE 10-day trial

Begin learning software, business, and creative skills—anytime,
anywhere—with video instruction from recognized industry experts. provides
Unlimited access to over 4,000 courses—more than 100,000 video tutorials
Expert-led instruction
On-the-go learning. Watch from your computer, tablet, or mobile device. Switch back and forth as you choose.
Start Your FREE Trial Now

A trusted source for knowledge.


We provide training to more than 4 million people, and our members tell us that helps them stay ahead of software updates, pick up brand-new skills, switch careers, land promotions, and explore new hobbies. What can we help you do?

Thanks for signing up.

We’ll send you a confirmation email shortly.

Sign up and receive emails about and our online training library:

Here’s our privacy policy with more details about how we handle your information.

Keep up with news, tips, and latest courses with emails from

Sign up and receive emails about and our online training library:

Here’s our privacy policy with more details about how we handle your information.

submit Lightbox submit clicked
Terms and conditions of use

We've updated our terms and conditions (now called terms of service).Go
Review and accept our updated terms of service.