Last updated 29 January 2011. Created on 29 January 2011.
Edited by j. ayen green. Log in to edit this page.

A custom module can introduce the need for a custom content type. Requiring the user to create a content type in support of the module is a possibility, but not the ideal one. It is preferable to have the module create the content type.

There is more than one way to do this, and deciding on the approach begins with whether the module can depend on the presence of the Content Construction Kit (CCK), or not. If not, the module will have to perform all of the functions that CCK would otherwise provide, such as the CRUD methods for the content type and the associated database requirements. Another approach would be to use the Features module. The approach use here will be using CCK to do the work.

The creation of a content type in support of a module will typically occur during the installation, as is the case in the following example, though there can be circumstances in which this is not true, such as where the administrative functionality of the module allows the user to create content types, in which case it will occur on demand.

CCK makes the process very easy, by way of its export and import functions. The code examples, below, contain .info and .module files for completeness, but the work is done in the .install and .install.inc files.

  1. Create the content type using the CCK UI. Be sure to set the options such as comment handling and publishing choices to be what you will want as the default for your content type.
  2. Create the fields for the new content type using the CCK UI. It is recommended that you do this with all modules that impact CCK other than the field modules disabled, such as skinnr, five star, etc., unless they, too, will be required by the module creating the content type, otherwise they will add unwanted data.
  3. Use the CCK UI to export the content type you just created, along with its fields.
  4. Copy the export text and pasted it into a file in your text editor, and save it as mymodule.install.inc
  5. Use the CCK UI to delete the new fields and content type.
  6. In the mymodule.install file, add the following lines to the install function:
      $filename = drupal_get_path('module','mymodule') . "/mymodule.install.inc";
      $content = implode ('', file ($filename));
      // Build form state
      $form_state = array(
         'values' => array(
            'type_name' => '<create>',
            'macro' => $content,
         ),
      );
      drupal_execute("content_copy_import_form", $form_state);
    
    1. Below are snippets providing the files needed for a minimal module. The content type has one image file field in addition to the title and body fields.

      mymodule.info

      ; $Id$ 
      name = "my module name"
      description = "my module description."
      core = 6.x
      php = 5.0
      dependencies[] = content
      dependencies[] = content_copy
      dependencies[] = imagefield
      

      mymodule.module

      <?php
      // $Id$
      /**
       * Implementation of hook_help().
       */
      function mymodule_help($path, $arg) {
        switch ($path) {
          case 'admin/modules#description':
            return t('What my module does.');
          case 'admin/help#mymodule':
            return t('<h3>Description:</h3><p>A longer description of what my module does.</p>');
        }
      }
      /**
       * Implementation of hook_perm().
       */
      function mymodule_perm() {
        return array(
          'administer my_content_type', 
          'create my_content_type', 
          'delete my_content_type',
          'delete my_content_type',
          'edit my_content_type', 
          'edit own my_content_type'
         );
      }
      /**
       * Implementation of hook_access().
       */
      function mymodule_access($op, $node, $account) {
        switch ($op) {
          case 'create':
            return user_access('create my_content_type', $account);
            break;
          case 'update':
            return user_access('edit my_content_type', $account) || (user_access('edit own my_content_type', $account) && ($account->uid == $node->uid));
            break;
          case 'delete':
            return user_access('delete my_content_type', $account) || (user_access('delete own my_content_type', $account) && ($account->uid == $node->uid));
            break;
        }
      }
      

      mymodule.install

      <?php
      // $Id: 
      /**
       * Implementation of hook_install().
       */
      function mymodule_install() {
      // install the content type
        $filename = drupal_get_path('module','mymodule') . "/mymodule.install.inc";
        $content = implode ('', file ($filename));
        // Build form state
        $form_state = array(
           'values' => array(
              'type_name' => '<create>',
              'macro' => $content,
           ),
        );
        drupal_execute("content_copy_import_form", $form_state);
      }
      

      mymodule.install.inc

      $content['type']  = array (
        'name' => 'My content type',
        'type' => 'my_content_type',
        'description' => 'What my content type is for',
        'title_label' => 'Title',
        'body_label' => 'Body',
        'min_word_count' => '0',
        'help' => '',
        'node_options' => 
        array (
          'status' => true,
          'promote' => false,
          'sticky' => false,
          'revision' => false,
        ),
        'upload' => '0',
        'forward_display' => 1,
        'nodeblock' => '0',
        'old_type' => 'my_content_type',
        'orig_type' => '',
        'module' => 'node',
        'custom' => '1',
        'modified' => '1',
        'locked' => '1',
        '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' => '-3',
          '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' => 1,
          'alt' => '',
          'custom_title' => 1,
          'title_type' => 'textfield',
          'title' => '',
          'use_default_image' => 0,
          'default_image_upload' => '',
          'default_image' => NULL,
          'description' => '',
          'form_markup' => 
          array (
            'prefix' => '',
            'suffix' => '',
          ),
          'group' => false,
          'required' => 0,
          'multiple' => '1',
          'list_field' => '0',
          'list_default' => 1,
          'description_field' => '1',
          '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,
            ),
            2 => 
            array (
              'format' => 'image_plain',
              'exclude' => 0,
            ),
            3 => 
            array (
              'format' => 'image_plain',
              'exclude' => 0,
            ),
          ),
        ),
      );
      $content['extra']  = array (
        'title' => '-5',
        'body_field' => '-4',
        'revision_information' => '0',
        'author' => '-1',
        'options' => '1',
        'comment_settings' => '2',
        'menu' => '-2',
        'path' => '3',
      );
      

Looking for support? Visit the Drupal.org forums, or join #drupal-support in IRC.

Comments

nahnhnahk’s picture

Very helpful! But how about module uninstall?

oakulm’s picture

Well you shouldn't remove cck content types in uninstall because it might delete quite a alot of information.

hook_uninstall could be something like this:

function my_module_uninstall() {
  db_query("DELETE FROM system WHERE type='module' AND name='my_module'")or die("Error");

  drupal_flush_all_caches();
}
codeinvaders’s picture

Very good example! But as it implements the hook_uninstall () for this case? (I am a novice in the creation of modules)

ibot’s picture

Thank you for this howTo!
Also helpful for me was http://drewish.com/node/118 - since i only wanted to append some fields from my custom module.

sepehr.sadatifar’s picture

my module is almost identical to above code but it didn't run correctlly until I changed hook_install to hook_enable, why is that?
http://atroot.com/module.zip

dustinschaeffer’s picture

I had an issue where my module was not running the mymodule.install code.

I found a comment that explains how to completely remove the module from your sight. Only after you do this can you re-install the module and run the mymodule.install.

http://drupal.org/node/323314#comment-3924410

priyankprajapati’s picture

function mymodule_help($path, $arg) {
switch ($path) {
case 'admin/modules#description':
return t('What my module does.');
case 'admin/help#mymodule':
return t('

Description:

A longer description of what my module does.

');
}
}

in this function what is the use of the case 'admin/modules#description'

please help me,

Thanks