I am trying to create a .INSTALL file which creates a content type (Apples) for my module (Fruit). I have dropped the following file (fruit.install) into my module folder with the .INFO file and .MODULE file. After enabling the Fruit module, I look into the database and find that there is no new entry in the node_type table. I must be missing a vital step? or I have made an obvious mistake, I think?


 * Implements hook_install()

function fruit_install() {

    // * If the content type does not exist then create it.
    if (!in_array('Apples', node_type_get_names())) {
        $type = array(
            'type' => 'apples',
            'name' => 'Apples',
            'base' => 'node_content',
            'custom' => 1,
            'modified' => 1,
            'locked' => 0,
        $type = node_type_set_defaults($type);
        // * Set 'Apples' options
        variable_set('node_preview_apples', 0);     // Set 'Preview before submitting' to 'Disabled'

3 Answers 3


The reason I was not seeing my 'Apples' content type appear in the node_type table was because I did not realise that I had to uninstall my module then reinstall it every time I wanted to test my code changes. I was just disabling the 'Fruit' module and expecting my .INSTALL file to do its work when I re-enabled the module again. You have to disable and uninstall (not just disable) then re-enable. Apparently you can manually remove the module from the system table also, but I did not go there.

The code I pasted in above does work - although it may not be the 'correct' way of creating a content type. I'm not sure. My method mirrors how I would acheive the same with the Field UI: Add a new content type, set the content type options, add any new fields, then create the required instances of those new fields. This seems logical to me, but you may find the other solutions suggested here to be better.


You can look at what the Forum module does.

  • forum_install() sets the node_options_forum Drupal variable
  • forum_enable() creates the vocabulary referred from that field, the taxonomy field to use with the Forum content type, and adds the body field to the content type

It doesn't call node_type_set_defaults(), nor node_type_save(). Eventually, forum_enable() calls node_types_rebuild(), which calls any implementation of hook_node_info(), including the one done from the Forum module itself.

  foreach (module_implements('node_info') as $module) {
    $info_array = module_invoke($module, 'node_info');
    foreach ($info_array as $type => $info) {
      $info['type'] = $type;
      $_node_types->types[$type] = node_type_set_defaults($info);
      $_node_types->types[$type]->module = $module;
      $_node_types->names[$type] = $info['name'];

  // …

  if ($rebuild) {
    foreach ($_node_types->types as $type => $type_object) {
      if (!empty($type_object->is_new) || !empty($type_object->disabled_changed)) {

Another module, which doesn't need to add any field to the content type, except the node body, does all in blog_install().

function blog_install() {
  // Ensure the blog node type is available.
  $types = node_type_get_types();

In short, creating a content type just require two steps (if the content type doesn't use extra fields):

  • Implement hook_node_info()
  • Call the following functions: node_types_rebuild(), node_type_get_types(), node_add_body_field()
  • Change the value of specific Drupal variables, if values different from the default ones are going to be used

First thing: Don't put all that code inside hook_install() itself. Instead, declare another function, perhaps in an include, that creates your content type, and call it from hook_install().

The functions you'll want to create are instances of hook_node_info() and hook_form():

function fruit_node_info() {
  return array(
    'event' => array(
    'name' => t('Apple'),
    'base' => 'event',
    'description' => t('An apple content type'),
    'has_title' => TRUE

function apple_form($node,$form_state) {
  $form['title'] = array(
    '#type' => 'textfield',
    '#title' => t('event Title'),
    '#default_value' => !empty($node->title) ? $node->title : '',
    '#required' => TRUE,
    '#weight' => -5
  return $form;

(This is adapted from this stackoverflow question. I have not personally tested it.)

The code you're using doesn't appear to make use of hook_node_info() or hook_form() at all, which could be the reason your node type isn't showing up. I also notice that your function doesn't return anything, and that you're setting variables after you've already saved your node type, all of which could be contributing to your problem.

  • Thanks beth. Why separate out the content type creation into an include? Readability? or is there a performance benefit?
    – dbj44
    May 29, 2013 at 8:37
  • Just readability, if you have a lot of hooks calling a lot of functions and you want to group the functions by purpose, or something like that.
    – beth
    May 29, 2013 at 15:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.