Sunday, April 3, 2011

Drupal 7 Field API - Setup a new content type on install and add fields

At the moment we are building a Drupal 7 site which requires everything to be enabled on install via modules / custom profiles. Below is a content type with some extra fields added using Field API so you can see how they are added. This should go in the module *.install file. We go through the standard process of setting up a content type, and call installed_fields and installed_instances functions.
You might want to rename it from ‘article’ to something else, from what I remember on the standard install profile, Drupal 7 already creates a content type called article.







function article_install() {
  // get the translation function relevant to our current localisation
  $t = get_t();
  // define the content type as an array (same as in hook_node_info())
  $article = array(
    'type' => 'article',
    'name' => $t('Article'),
    'base' => 'node_content',
    'description' => $t('Content type to handle articles.'),
    'body_label' => $t('Article Description'),
    'promote' => 0,
    'status' => 1,
    'comment' => 0,
  );

  // set default values for anything not explicitly defined in the above array
  $content_type = node_type_set_defaults($article);

  // add the body field to the content type
  node_add_body_field($content_type, 'Body');

  // create the content type
  node_type_save($content_type);

  variable_set('node_options_article', array('status'));
  // hide comments for this node. http://api.drupal.org/api/drupal/modules--comment--comment.module/7
  variable_set('comment_article', 'COMMENT_NODE_HIDDEN');

  // Hide date and author information
  variable_set('node_submitted_article', FALSE);

  // Create all the fields we are adding to our content type.
  // http://api.drupal.org/api/function/field_create_field/7
  foreach (_article_installed_fields() as $field) {
    field_create_field($field);
  }

  // Create all the instances for our fields.
  // http://api.drupal.org/api/function/field_create_instance/7
  foreach (_article_installed_instances() as $instance) {
    $instance['entity_type'] = 'node';
    $instance['bundle'] = 'article';
    field_create_instance($instance);
  }

  // adjust the weight so it's called after a dependant module called 'categories'
  $weight = db_query("SELECT weight FROM {system} WHERE name = :name", array(':name' => 'categories'))->fetchField();
  db_update('system')->fields(array(
    'weight' => $weight + 1,
  ))
  ->condition('name', 'article')
  ->execute();
}


function _article_installed_fields() {
  $t = get_t();
  $fields = array(
    // text field
    'article_source' => array(
      'field_name'   => 'article_source',
      'label'        => $t('Artcile Source'),
      'cardinality'  => 1,
      'type'         => 'text',
      'settings'     => array(
        'max_length'  => 1000,
      ),
    ),
    // taxonomy term reference field, referencing a vocabulary called 'authors'
    'article_author' => array(
      'field_name' => 'article_author',
      'type' => 'taxonomy_term_reference',
      'cardinality' => FIELD_CARDINALITY_UNLIMITED,
      'settings' => array(
        'allowed_values' => array(
          array(
            'vocabulary' => 'authors',
            'parent' => 0,
          ),
        ),
      ),
    ),
      // node refererence auto complete field (see the instance), referencing a content-type called 'work'
    'article_work_ref' => array(
      'field_name'  => 'article_work_ref',
      'label'       => $t('Work refrerence'),
      'cardinality' => FIELD_CARDINALITY_UNLIMITED,
      'type'        => 'node_reference',
      'settings'    => array(
        'referenceable_types'  => array('work'),
      ),
    ),
    // a text (textarea) field
    'article_pullquote' => array(
      'field_name'   => 'article_pullquote',
      'label'        => $t('Pull Quote'),
      'cardinality'  => 1,
      'type'         => 'text',
      'settings'     => array(
        'max_length'  => 1000,
      ),
    ),
    // image field
    'article_image' => array(
      'field_name' => 'article_image',
      'label' => $t('Image'),
      'cardinality' => 1,
      'type' => 'image',
      'settings' => array(
        'default_image' => 0,
        'uri_scheme' => 'public',
      ),
    ),
    // date field (date module required)
    'article_date' => array(
      'field_name'   => 'article_date',
      'label'        => $t('Date'),
      'cardinality'  => 1,
      'type'         => 'date',
    ),
  );
  return $fields;
}


function _article_installed_instances() {
  $t = get_t();
  $instances = array(
    // instance of the text field above
    'article_source' => array(
      'field_name'  => 'article_source',
      'label'       => $t('Article Source'),
      'cardinality' => 1,
      'widget'      => array(
        'type'       => 'text_textfield',
        'settings'   => array('size' => 60),
      ),
    ),
    // instance of the taxonomy term reference field above
    'article_author' => array(
      'field_name' => 'article_author',
      'entity_type' => 'node',
      'label' => $t('Author'),
      'bundle' => 'article',
      'required' => FALSE,
      'widget' => array(
        'type' => 'options_select',
      ),
    ),
      // instance of the node reference 'work' auto complete field above
    'article_work_ref' => array(
      'field_name'  => 'article_work_ref',
      'label'       => $t('Work refrerence'),
      'cardinality' => FIELD_CARDINALITY_UNLIMITED,
      'widget'      => array(
        'type'          => 'node_reference_autocomplete',
      ),
    ),
    // instance of the textarea field above
    'article_pullquote' => array(
      'field_name'  => 'article_pullquote',
      'label'       => $t('Pull Quote'),
      'cardinality' => 1,
      'widget'      => array(
        'type'       => 'text_textarea',
        'settings'   => array('rows' => 5),
      ),
    ),
    // instance of the image field above
    'article_image' => array(
      'field_name' => 'article_image',
      'label' => $t('Image'),
      'cardinality' => 1,
      'type' => 'article_image',
      'settings' => array(
        'alt_field' => 1,
        'file_directory' => 'image',
        'file_extensions' => 'png gif jpg jpeg',
        'max_filesize' => '',
        'max_resolution' => '',
        'min_resolution' => '',
        'title_field' => 1,
        'user_register_form' => FALSE,
      ),
      'widget' => array(
        'settings' => array(
          'preview_image_style' => 'thumbnail',
          'progress_indicator' => 'throbber',
        ),
      ),
      'display' => array(
        'default' => array(
          'label' => 'hidden',
          'type' => 'image',
          'settings' => array('image_style' => 'bfi_common_features_image', 'image_link' => ''),
          'weight' => -1,
        ),
        'teaser' => array(
          'label' => 'hidden',
          'type' => 'image',
          'settings' => array('image_style' => 'thumbnail', 'image_link' => 'content'),
          'weight' => -1,
        ),
      ),
    ),
    // instance of the date field above
    'article_date' => array(
      'field_name'  => 'article_date',
      'label'       => $t('Date'),
      'cardinality' => 1,
      'widget'      => array(
        'type'       => 'date_select',
        'settings'   => array(
          'input_format' => date_default_format('date_select'),
          'increment' => 1,
          'year_range' => '-3:+3',
        ),
        'behaviors' => array(
          'multiple values' => FIELD_BEHAVIOR_CUSTOM,
          'default value' => FIELD_BEHAVIOR_CUSTOM,
        ),
      ),
    ),
  );
  return $instances;
}



function article_uninstall() {
  // Gather all the example content that might have been created while this
  // module was enabled.  Simple selects still use db_query().
  // http://api.drupal.org/api/function/db_query/7
  $sql = 'SELECT nid FROM {node} n WHERE n.type = :type';
  $result = db_query($sql, array(':type' => 'article'));
  $nids = array();
  foreach ($result as $row) {
    $nids[] = $row->nid;
  }

  // Delete all the nodes at once
  // http://api.drupal.org/api/function/node_delete_multiple/7
  node_delete_multiple($nids);


  // Loop over each of the fields defined by this module and delete
  // all instances of the field, their data, and the field itself.
  // http://api.drupal.org/api/function/field_delete_field/7
  foreach (array_keys(_article_installed_fields()) as $field) {
    field_delete_field($field);
  }

  // Delete our content type
  // http://api.drupal.org/api/function/node_type_delete/7
  node_type_delete('article');

  // Purge all field information
  // http://api.drupal.org/api/function/field_purge_batch/7
  field_purge_batch(1000);
}

37 comments:

  1. Awesome example. Thanks a lot.

    ReplyDelete
  2. Thanks for the example.

    You might want to check the terms of service for Google ads, though, as I think that it is a violation to tell people to click on ads on your site to promote the content (per your text at the top). Google can get pretty picky about this, so I would hate to see you banned from using their ads.

    ReplyDelete
  3. Still didn't know how to use this

    ReplyDelete
  4. This is great. I was having a lot of trouble attaching a field of taxonomy_term_reference (or whatever), this is perfect. THanks again.

    ReplyDelete
  5. How can I create checkbox field?

    ReplyDelete
  6. I found your entry interesting do I’ve added a Trackback to it on my weblog :) …

    ReplyDelete
  7. i'm trying but won't work, content type in structure dont show any new content type :-S else when i add hook_node_info and hook_form but dont had any field i already declare at install file

    ReplyDelete
  8. It always shows me that I have an error, some field type doesn't exists, then I tried disabling all other types and just tested with text and image.

    After successfull creation of content type I added content with the content type and found that the image field is not displayed correctly, then I came to know that the bfi_common_features_image should be replaced with one of this (large, thumbnail, medium). I used medium and I was able to get the image correctly.

    You can find the code that I have edited to work for me here at http://pastebin.com/0Q8XmswZ

    ReplyDelete
  9. thanks alot for the example of the taxonomy_term_reference

    ReplyDelete
  10. how can I integrate this with field groups?

    ReplyDelete
  11. Great post, what you said is really helpful to me. I can't agree with you anymore. I have been talking with my friend about, he though it is really interesting as well.

    ReplyDelete
  12. You can use the "bundle copy" module to export existing content type (created on /admin/structure/types) and see the structure of "fields" and "instances" keys to reuse it in your install files ;)

    ReplyDelete
  13. It is really a good blog. I am completely convinced with his thoughts. I will stay in touch for more information. Thanks for sharing.

    ReplyDelete
  14. Put a width to the main div please...

    ReplyDelete
  15. Great information about drupal 7 content type installation and installation.

    ReplyDelete
  16. Hi Anish,

    I'm trying to set up a user_reference (coming from a view) at time of install. Do you know how that's done?

    Cheers,
    Barnabas

    ReplyDelete
  17. Great post, what you said is really helpful to me.

    ReplyDelete
  18. I just found this blog and have high hopes for it to continue.
    Keep up the great work, its hard to find good ones. I have added to my favorites. Thank You

    ReplyDelete
  19. It is really a good blog. I am completely convinced with his thoughts. I will stay in touch for more information. Thanks for sharing.

    ReplyDelete
  20. thanks for this post I really liked it

    ReplyDelete
  21. Good Keep it up,Thank you so much for sharing this one really well defined all peaceful info regarding Drupal Developer,I Really like it,Love it- Drupal developers for hire

    ReplyDelete
  22. Interesting blog. It would be great if you can provide more details about it. Thanks you
    App Development company | web design and development company

    ReplyDelete
  23. I recently came across your blog and have been reading along. I think I will leave my first comment. I don’t know what to say except that I have enjoyed reading.Nice blog. buying steroids I will keep visiting this blog very often. Steroids discounted

    ReplyDelete
  24. Keren tulisannya bisa jadi refrensi juga nih, thanks.. --> #Yuk Cek dulu blog kita Media Informasi Online di Kota Medan

    ReplyDelete
  25. Outstanding information, your technical support is too much trustworthy. I love this blog posting. keep it up.
    Germany VPS Hosting

    ReplyDelete
  26. Such a Mind-blowing Post that You have shared here, This is an amazing superb article Keep Sharing this...
    Thanks thanks a lotttttttt!!!!
    Australia Dedicated Server Hosting

    ReplyDelete