Creating Content Types Programmically

By Paulus, 3 March, 2012

There are two ways to create content types in Drupal. The first is using hook_node_info in your module. When using this method, this only creates a content type with a title and a body (providing you implement the hook_form() function.)

function blog_node_info() {
  return array(
    'blog' => array(
      'name' => t('Blog entry'),
      'module' => 'blog',
      'description' => t('A blog entry is a single post to an online journal, or blog.'),
      'has_title' => TRUE,
      'has_body' => TRUE,
    )
  );
}

function blog_form($node, $form_state) {
    return node_content_form($node, $form_state);
}

The other way is to programmically recreate a content type by exporting the content type with the Content Copy module. For example, you're working on module that relies on content type that you created along with a number of CCK fields. The first step in this method is to enable the Content Copy module.  Once the module is enabled head over to admin/content/types/export to select the content type you wish to export. The export will be an array so you can use it in a module.

$content['type']  = array (
  'name' => 'Membership',
  'type' => 'product',
  'description' => 'This node displays the representation of a membership for sale on the website. ',
  'title_label' => 'Name',
  'body_label' => 'Description',
  'min_word_count' => '0',
  'help' => '',
  'node_options' =>
  array (
    'status' => true,
    'revision' => true,
    'promote' => false,
    'sticky' => false,
  ),
  'old_type' => 'product',
  'orig_type' => 'product',
  'module' => 'uc_product',
  'custom' => '0',
  'modified' => '1',
  'locked' => '1',
  'reset' => 'Reset to defaults',
  'uc_product_shippable' => 0,
  'uc_image' => '',
  'comment' => '0',
  'comment_default_mode' => '4',
  'comment_default_order' => '1',
  'comment_default_per_page' => '50',
  'comment_controls' => '3',
  'comment_anonymous' => 0,
  'comment_subject_field' => '1',
  'comment_preview' => '1',
  'comment_form_location' => '0',
);
$content['fields']  = array (
  0 =>
  array (
    'label' => 'Image',
    'field_name' => 'field_image',
    'type' => 'filefield',
    'widget_type' => 'imagefield_widget',
    'change' => 'Change basic information',
    'weight' => '31',
    'file_extensions' => 'png gif jpg jpeg',
    'progress_indicator' => 'bar',
    'file_path' => '',
    'max_filesize_per_file' => '',
    'max_filesize_per_node' => '',
    'max_resolution' => 0,
    'min_resolution' => 0,
    'custom_alt' => 0,
    'alt' => '',
    'custom_title' => 0,
    'title_type' => 'textfield',
    'title' => '',
    'use_default_image' => 0,
    'default_image_upload' => '',
    'default_image' => NULL,
    'description' => '',
    'required' => 0,
    'multiple' => '1',
    'list_field' => '0',
    'list_default' => 1,
    'description_field' => '0',
    'op' => 'Save field settings',
    'module' => 'filefield',
    'widget_module' => 'imagefield',
    'columns' =>
    array (
      'fid' =>
      array (
        'type' => 'int',
        'not null' => false,
        'views' => true,
      ),
      'list' =>
      array (
        'type' => 'int',
        'size' => 'tiny',
        'not null' => false,
        'views' => true,
      ),
      'data' =>
      array (
        'type' => 'text',
        'serialize' => true,
        'views' => true,
      ),
    ),
    'display_settings' =>
    array (
      'label' =>
      array (
        'format' => 'above',
        'exclude' => 0,
      ),
      'teaser' =>
      array (
        'format' => 'image_plain',
        'exclude' => 0,
      ),
      'full' =>
      array (
        'format' => 'image_plain',
        'exclude' => 0,
      ),
      4 =>
      array (
        'format' => 'image_plain',
        'exclude' => 0,
      ),
      'token' =>
      array (
        'format' => 'image_plain',
        'exclude' => 0,
      ),
    ),
  ),
);
$content['extra']  = array (
  'title' => '-5',
  'body_field' => '-4',
  'revision_information' => '20',
  'author' => '20',
  'options' => '25',
  'comment_settings' => '30',
  'menu' => '0',
  'path' => '30',
  'shipping' => '0',
  'base' => '-1',
  'body' => '1',
);

In a hook_install or hook_enable function, and after making sure the content type doesn't already exist, you would do the following:

module_load_include('inc', 'content', 'includes/content.crud');

$content['type']  = array (
  'name' => 'Membership',
  'type' => 'product',
  'description' => 'This node displays the representation of a membership for sale on the website. ',
  'title_label' => 'Name',
  'body_label' => 'Description',
  'min_word_count' => '0',
  'help' => '',
  'node_options' =>
  array (
    'status' => true,
    'revision' => true,
    'promote' => false,
    'sticky' => false,
  ),
  'old_type' => 'product',
  'orig_type' => 'product',
  'module' => 'uc_product',
  'custom' => '0',
  'modified' => '1',
  'locked' => '1',
  'reset' => 'Reset to defaults',
  'uc_product_shippable' => 0,
  'uc_image' => '',
  'comment' => '0',
  'comment_default_mode' => '4',
  'comment_default_order' => '1',
  'comment_default_per_page' => '50',
  'comment_controls' => '3',
  'comment_anonymous' => 0,
  'comment_subject_field' => '1',
  'comment_preview' => '1',
  'comment_form_location' => '0',
);
$content['fields']  = array (
  0 =>
  array (
    'label' => 'Image',
    'field_name' => 'field_image',
    'type' => 'filefield',
    'widget_type' => 'imagefield_widget',
    'change' => 'Change basic information',
    'weight' => '31',
    'file_extensions' => 'png gif jpg jpeg',
    'progress_indicator' => 'bar',
    'file_path' => '',
    'max_filesize_per_file' => '',
    'max_filesize_per_node' => '',
    'max_resolution' => 0,
    'min_resolution' => 0,
    'custom_alt' => 0,
    'alt' => '',
    'custom_title' => 0,
    'title_type' => 'textfield',
    'title' => '',
    'use_default_image' => 0,
    'default_image_upload' => '',
    'default_image' => NULL,
    'description' => '',
    'required' => 0,
    'multiple' => '1',
    'list_field' => '0',
    'list_default' => 1,
    'description_field' => '0',
    'op' => 'Save field settings',
    'module' => 'filefield',
    'widget_module' => 'imagefield',
    'columns' =>
    array (
      'fid' =>
      array (
        'type' => 'int',
        'not null' => false,
        'views' => true,
      ),
      'list' =>
      array (
        'type' => 'int',
        'size' => 'tiny',
        'not null' => false,
        'views' => true,
      ),
      'data' =>
      array (
        'type' => 'text',
        'serialize' => true,
        'views' => true,
      ),
    ),
    'display_settings' =>
    array (
      'label' =>
      array (
        'format' => 'above',
        'exclude' => 0,
      ),
      'teaser' =>
      array (
        'format' => 'image_plain',
        'exclude' => 0,
      ),
      'full' =>
      array (
        'format' => 'image_plain',
        'exclude' => 0,
      ),
      4 =>
      array (
        'format' => 'image_plain',
        'exclude' => 0,
      ),
      'token' =>
      array (
        'format' => 'image_plain',
        'exclude' => 0,
      ),
    ),
  ),
);
$content['extra']  = array (
  'title' => '-5',
  'body_field' => '-4',
  'revision_information' => '20',
  'author' => '20',
  'options' => '25',
  'comment_settings' => '30',
  'menu' => '0',
  'path' => '30',
  'shipping' => '0',
  'base' => '-1',
  'body' => '1',
);

$form_state = array();
$form = content_copy_import_form($form_state, $content['type']['type']);
$form_state['values']['type_name'] = $type_name ? $type_name : '';
$form_state['values']['macro'] = '$content = '. var_export($content, 1) .';';
$form_state['values']['op'] = t('Import');
content_copy_import_form_submit($form, $form_state);