5.x node.module node_type_save($info)
6.x node.module node_type_save($info)
7.x node.module node_type_save($info)

Saves a node type to the database.


object $info: The node type to save; an object with the following properties:

  • type: A string giving the machine name of the node type.
  • name: A string giving the human-readable name of the node type.
  • base: A string that indicates the base string for hook functions. For example, 'node_content' is the value used by the UI when creating a new node type.
  • description: A string that describes the node type.
  • help: A string giving the help information shown to the user when creating a node of this type.
  • custom: TRUE or FALSE indicating whether this type is defined by a module (FALSE) or by a user (TRUE) via Add Content Type.
  • modified: TRUE or FALSE indicating whether this type has been modified by an administrator. When modifying an existing node type, set to TRUE, or the change will be ignored on node_types_rebuild().
  • locked: TRUE or FALSE indicating whether the administrator can change the machine name of this type.
  • disabled: TRUE or FALSE indicating whether this type has been disabled.
  • has_title: TRUE or FALSE indicating whether this type uses the node title field.
  • title_label: A string containing the label for the title.
  • module: A string giving the module defining this type of node.
  • orig_type: A string giving the original machine-readable name of this node type. This may be different from the current type name if the 'locked' key is FALSE.

Return value

int A status flag indicating the outcome of the operation, either SAVED_NEW or SAVED_UPDATED.

6 calls to node_type_save()
DrupalWebTestCase::drupalCreateContentType in modules/simpletest/drupal_web_test_case.php
Creates a custom content type based on default settings.
example_profile_tasks in developer/example.profile
Perform any final installation tasks for this profile.
node_type_form_submit in modules/node/content_types.inc
Form submission handler for node_type_form().
standard_install in profiles/standard/standard.install
Implements hook_install().
_book_install_type_create in modules/book/book.install
Creates the book content type.

... See full list


modules/node/node.module, line 526
The core that allows content to be submitted to the site. Modules and scripts may programmatically submit nodes using the usual form API pattern.


function node_type_save($info) {
  $existing_type = !empty($info->old_type) ? $info->old_type : $info->type;
  $is_existing = (bool) db_query_range('SELECT 1 FROM {node_type} WHERE type = :type', 0, 1, array(':type' => $existing_type))->fetchField();
  $type = node_type_set_defaults($info);

  $fields = array(
    'type' => (string) $type->type,
    'name' => (string) $type->name,
    'base' => (string) $type->base,
    'has_title' => (int) $type->has_title,
    'title_label' => (string) $type->title_label,
    'description' => (string) $type->description,
    'help' => (string) $type->help,
    'custom' => (int) $type->custom,
    'modified' => (int) $type->modified,
    'locked' => (int) $type->locked,
    'disabled' => (int) $type->disabled,
    'module' => $type->module,

  if ($is_existing) {
      ->condition('type', $existing_type)

    if (!empty($type->old_type) && $type->old_type != $type->type) {
      field_attach_rename_bundle('node', $type->old_type, $type->type);
    module_invoke_all('node_type_update', $type);
    $status = SAVED_UPDATED;
  else {
    $fields['orig_type'] = (string) $type->orig_type;

    field_attach_create_bundle('node', $type->type);

    module_invoke_all('node_type_insert', $type);
    $status = SAVED_NEW;

  // Clear the node type cache.

  return $status;


woland.m’s picture

If you want to create a content-type on the fly you should use node_content as $info->base, otherwise your content type will be deleted when node_types_rebuild() is called(on cache clear, cron etc).

kenianbei’s picture

For setting node options like menu, comments, etc, see http://drupal.org/node/1169864.

mlncn’s picture

$type->old_type is what node_type_save() checks for when updating a node type, if it's not set it will create a new node type even if orig_type is set to an existing bundle. So really all you need to do right before saving a modified content type is set the old_type to the orig_type, such as:

$type = node_type_load('example');
$type->type = 'new_machine_name';
$type->old_type = $type->orig_type;  // This will be 'example'.
node_type_save($type); // This will now result in SAVED_UPDATED (2)

Why orig_type is documented but old_type is used for renaming a node type, i have no idea and would greatly appreciate enlightenment.

RaisinBranCrunch’s picture

It seems as though nothing like this exists for Drupal 8 yet? Is there no convenient way to dynamically create a content type in D8?

mcrittenden’s picture

Only do this if you can't just update the site configuration instead, like: https://www.drupal.org/node/2087879

$info = NodeType::load('article');