You are here

Creating a custom content type & adding fields programmatically in Drupal 7

Although it's very easy to create new content types in the admin section of Drupal, sometimes it's good to do this programmatically to make your brain feel a lot more clever.

Lets pretend we are creating a module called jobs, and in that module we have an install file called jobs.install. The first thing we do is add our hook_install() function that does the following steps:

  1. Add our content type called jobs using an array of default information.
  2. Add the persistant variables needed for our default node settings.
  3. Add the fields.
<?php
/**
 * Implements hook_install().
 */
function jobs_install() {
 
$t = get_t();
 
 
/**** STEP 1 ****/
 
  // machine name of the content type
 
$name = 'jobs';
 
 
// define the node type
 
$jobs = array(
   
'type' => $name,
   
'name' => $t('Jobs'),
   
'base' => 'node_content',
   
'title_label' => $t('Job Title'),
   
'description' => $t('Job advertising post.'),
   
'custom' => TRUE,
  );
 
 
// set other node defaults not declared above
 
$content_type = node_type_set_defaults($jobs);
 
 
// add the body field
 
node_add_body_field($content_type, $t('Job Description'));
 
 
// save the content type
 
node_type_save($content_type);
 

 
/**** STEP 2 ****/
 
  // add peristant variables that control settings
 
variable_set('additional_settings__active_tab_' . $name, 'edit-menu');
 
variable_set('node_preview_' . $name, 2);
 
variable_set('node_options_' . $name, array(0 => 'status', 1 => 'promote'));
 
variable_set('node_submitted_' . $name, 0);
 
variable_set('menu_options_' . $name, array());
 
variable_set('menu_parent_' . $name, 'main-menu:0');
 

 
/**** STEP 3 ****/
 
  // create all the fields we are adding to our content type
 
foreach (_jobs_installed_fields() as $field) {
   
field_create_field($field);
  }

 
// create all the instances for our fields
 
foreach (_jobs_installed_instances() as $instance) {
   
$instance['entity_type'] = 'node';
   
$instance['bundle'] = $jobs['type'];
   
field_create_instance($instance);
  }
}
?>

In step 3, the two functions we are using to add fields are field_create_field() and field_create_instance(). We need to create two functions, _jobs_installed_fields() and _jobs_installed_instances(), that hold the information about our new field types, but how do we get this information? The best way is to use the Drupal Field UI to create the fields we want first and then get the information we need from there. To do this, go to the admin area of your Drupal site, create a new dummy content type (call it dummy) and create a new field as normal. To extract the information from the field we just created, use Devels Execute PHP code to execute the code below:

<?php
include_once DRUPAL_ROOT . '/includes/utility.inc';
 
$field_data = field_info_field('field_name');
unset(
$field_data['id']);
dsm(drupal_var_export($field_data));
 
$instance_data = field_info_instance('node', 'field_name', 'dummy');
unset(
$instance_data['id'], $instance_data['field_id']);
dsm(drupal_var_export($instance_data));
?>

The field_name can be found in the Manage Fields UI page for the field you just created. You should see two array outputs, the first will go in our _jobs_installed_fields() function and the second will go in our _jobs_installed_instances() function. We are using drupal_var_export() to print the array which allows us to copy and paste the array directly into our functions. Do this for as many fields as you like. Note that we are using the function dsm() to output our results so make sure the Devel module is enabled. You should end up with two functions like the below:

<?php
/**
 * Returns a structured array defining the fields created by this content type.
 *
 * @return
 *  An associative array specifying the fields we wish to add to our
 *  new node type.
 */
function _jobs_installed_fields() {
 
$t = get_t();
 
  return array(
   
'field_job_start_date' => array(
     
'translatable' => '0',
     
'entity_types' => array(),
     
'settings' => array(),
     
'storage' => array(
       
'type' => 'field_sql_storage',
       
'settings' => array(),
       
'module' => 'field_sql_storage',
       
'active' => '1',
       
'details' => array(
         
'sql' => array(
           
'FIELD_LOAD_CURRENT' => array(
             
'field_data_field_job_start_date' => array(
               
'value' => 'field_job_start_date_value',
              ),
            ),
           
'FIELD_LOAD_REVISION' => array(
             
'field_revision_field_job_start_date' => array(
               
'value' => 'field_job_start_date_value',
              ),
            ),
          ),
        ),
      ),
     
'foreign keys' => array(),
     
'indexes' => array(),
     
'field_name' => 'field_job_start_date',
     
'type' => 'number_integer',
     
'module' => 'number',
     
'active' => '1',
     
'locked' => '0',
     
'cardinality' => '1',
     
'deleted' => '0',
     
'columns' => array(
       
'value' => array(
         
'type' => 'int',
         
'not null' => FALSE,
        ),
      ),
     
'bundles' => array(
       
'node' => array(
         
'jobs',
          ),
        ),
      )
  );
}

/**
 * Returns a structured array defining the instances for this content type.
 *
 * @return
 *  An associative array specifying the instances we wish to add to our new
 *  node type.
 */
function _jobs_installed_instances() {
 
$t = get_t();
  return array(
   
'field_job_start_date' => array(
     
'label' => 'Start Date',
     
'widget' => array(
       
'weight' => '1',
       
'type' => 'number',
       
'module' => 'number',
       
'active' => 0,
       
'settings' => array(),
      ),
     
'settings' => array(
       
'min' => '',
       
'max' => '',
       
'prefix' => '',
       
'suffix' => '',
       
'user_register_form' => FALSE,
      ),
     
'display' => array(
       
'default' => array(
         
'label' => 'above',
         
'type' => 'number_integer',
         
'settings' => array(
           
'thousand_separator' => ' ',
           
'decimal_separator' => '.',
           
'scale' => 0,
           
'prefix_suffix' => TRUE,
          ),
         
'module' => 'number',
         
'weight' => 1,
        ),
       
'teaser' => array(
         
'type' => 'hidden',
         
'label' => 'above',
         
'settings' => array(),
         
'weight' => 0,
        ),
      ),
     
'required' => 0,
     
'description' => '',
     
'default_value' => NULL,
     
'field_name' => 'field_job_start_date',
     
'entity_type' => 'node',
     
'bundle' => 'jobs',
     
'deleted' => '0',
    ),
  );
}
?>

We need to make sure we now add our hook_uninstall() function. This does the following tasks:

  • Finds all nodes of type jobs, then deletes them.
  • Deletes the jobs content type.
  • Deletes the persistent variables that decide the node settings.
  • Deletes all related fields.
<?php
/**
 * Implements hook_uninstall().
 */
function jobs_uninstall() {
 
// machine name of the content type
 
$name = 'jobs';
 
 
// gather all job nodes created
 
$sql = 'SELECT nid FROM {node} n WHERE n.type = :type';
 
$result = db_query($sql, array(':type' => $name));
 
$nids = array();
  foreach (
$result as $row) {
   
$nids[] = $row->nid;
  }

 
// delete all the job nodes at once
 
node_delete_multiple($nids);
 
 
// remove peristant variables that control settings
 
variable_del('additional_settings__active_tab_' . $name);
 
variable_del('node_preview_' . $name);
 
variable_del('node_options_' . $name);
 
variable_del('node_submitted_' . $name);
 
variable_del('menu_options_' . $name);
 
variable_del('menu_parent_' . $name);
 

 
// find all fields and delete them
 
foreach (array_keys(_jobs_installed_fields()) as $field) {
   
field_delete_field($field);
  }
 
 
// find all fields and delete instance
 
$instances = field_info_instances('node', $name);
  foreach (
$instances as $instance_name => $instance) {
   
field_delete_instance($instance);
  }
 
 
// delete our content type
 
node_type_delete($name);
 
 
// purge all field infromation
 
field_purge_batch(1000);
}
?>

The way I learned how to add content types and fields programmatically was by viewing the Drupal Example Modules. I'd recommend installing that, and have a play around creating your own .install file. Use the Devel module to quickly reinstall the module test your code.

Comments

Pages

Add new comment