57

How can I approach implementing the following in Drupal 7?

What I need to do is create a module which defines a new fieldable entity, called 'Company'. I have a list of, let's say, 20 fields that need to be filled out by each Company instance. These questions are predefined and some may contain custom validation.

At the moment, I'm at the point when I can add new fields to the Company entity. This works fine at the moment. My issue is that I need all these fields to be there as soon the module is installed, so adding them via the interface isn't an option.

I was wondering how can I approach this? I'd assume it comes down being able to do what can be done using the 'Manage Fields' UI programmatically.

3
  • I'm not clear on the full scope of your needs, but I think this thread will be useful for you: drupal.org/node/721552 It shows sample code for creating a custom content type with fields when a module is first installed. You'll probably have to dig through the API to get the exact field settings you need, but this would be a good starting point. Basically, you will need to look into node_type_set_defaults() and node_type_save(), as well as, of course, hook_install(). Commented Jul 29, 2011 at 14:29
  • If you're doing this in code as opposed to Features, take a look at the Fields Example and the Node Example in the Examples Project.
    – rfay
    Commented Aug 2, 2011 at 19:43
  • A few words of guidance. If you want to retain a level of control over the configuration of the fields, use Features to record and apply them. If you want to define them as a one-shot operation and let their configuration be overridden freely in the future, choose a code solution in an .install file. Commented Oct 29, 2013 at 16:14

9 Answers 9

41

Use field_create_field() to create the field itself and field_create_instance() to have an instance for the given entity bundle.

When creating fields as part of a custom module, you may or may not want to delete the field when the module is uninstalled. To do so, you can use field_delete_field() if you want to delete the field and all field instance, or if you want to delete specific instances you can use field_delete_instance().

2
  • How we delete the fields we created when uninstall the module ?
    – Ashok KS
    Commented Sep 10, 2013 at 10:25
  • Ashok, I added a clarification for you in an edit I just made to the answer. Commented Oct 29, 2013 at 15:45
9

Example on how to programatically add fields to the user profile and how to avail them, or not, into the User Registration form.


function MYMODULE_enable() {
  // Check if our field is not already created.
  if (!field_info_field('field_myField')) {

    // Create the field base.
    $field = array(
      'field_name' => 'field_myField', 
      'type' => 'text', 
    );
    field_create_field($field);

    // Create the field instance on the bundle.
    $instance = array(
      'field_name' => 'field_myField', 
      'entity_type' => 'user', 
      'label' => 'My Field Name', 
      'bundle' => 'user', 
      // If you don't set the "required" property then the field wont be required by default.
      'required' => TRUE,
      'settings' => array(
        // Here you inform either or not you want this field showing up on the registration form.
        'user_register_form' => 1,
      ),
      'widget' => array(
        'type' => 'textfield',
      ), 
    );
    field_create_instance($instance);
  }
}
2
  • 3
    This should be implemented in the hook_install().
    – revagomes
    Commented Jul 25, 2013 at 8:26
  • If all you want to do is to add a new field to an existing content type and from there on continue in the backend, that approach is totally fine. Activate the module, deactivate it, done. The new field is there, editable, the module can be deleted.
    – leymannx
    Commented Jul 21, 2015 at 10:06
8

If you need to quickly create / delete fields from an existing Content Type or or Entity, without neither using the UI nor programming, you can use these little-known Drush commands:

drush field-create <bundle(for nodes)> <field_name>,<field_type>,[widget_name] --entity_type : Type of entity (e.g. node, user, comment). Defaults to node.

E.g.: Create two new fields for Article:

drush field-create article city,text,text_textfield subtitle,text,text_textfield

Other commands:

drush field-delete <field_name> [--bundle] [--entity_type]
drush field-info [field | types]
drush field-update <field_name> Return URL for field editing web page.
drush field-clone <source_field_name> <dst_field_name>
4

As pointed by others, you can use the Field API functions from the hook_install() implementation of your module to create fields and their instances for you content type. See the node_example_install() for example usage of the function.

Another solution is to use the Features module. Features can export various site components to code in a module. Content types and fields are amongst these exportable. You can either generate a Features module and override your existing code, Features will then do its best to avoid breaking your code. Or you can generate a dummy module and copy./paste the fields-related code to your module. This requires basics understanding of how Features works.

3

In your install file you'll need to define both the 'hook_install' and the 'hook_uninstall'. Example included but read all about the extra keys in the API references (code is untested so might be typo's in there).

In the hook_install you can add the fields using:

field_create_field, This function builds a template for a field.

field_create_instance Can be used after creating the field to add it to content_types (also known as bundles).

NOTE The names of various field types can be found in the modules that generate them (it's the key of the array item in their hook_field_info). You can find all the core field implementing modules in the modules/field/modules folder.

Settings can also be derived from the field modules. The settings you set in the field_create_field are the site wide ones. The ones you set in field_instance_create are the node_type specific ones

    MY_MODULE_install(){
      // Generate the base for the field
      $field = array( 
        'field_name' => 'FIELD_MACHINE_NAME', 
        'type' => 'FIELD_TYPE' // See note above for what to put here
      );
      // Instance 
      $instance = array(
        'field_name' => 'FIELD_MACHINE_NAME', 
        'entity_type' => 'node', 
      ); 

      // Create instances of the field and add them to the content_types
      $node_types = node_type_get_types(); 
      foreach($node_types as $node_type){
         $instance['bundle'] = $node_type->type; 
         field_create_instance($instance); 
      }
    }

In the hook_uninstall

field_delete_instance and field_delete_field can be used to remove them again, field_delete_field is called automatically if you delete the last instance (normally).

    MY_MODULE_uninstall(){
      $node_types = node_type_get_types(); 
      foreach($node_types as $node_type){
        if($instance = field_info_instance('node', 'FIELD_MACHINE_NAME', $node_type->type)) {
          field_delete_instance($instance);
        }
      }
    }
2

I recently had a similar need for a project, here is how I approached it, hope it helps somebody.

Basically you will create the fields you need using the fields UI, export them to code and then include them in your custom module. You will need the Devel module enabled.

I also created a Gist with this info.

Here we go....

  1. Create the fields you need, using the usual Drupal UI.
  2. On the same site, go to example.com/devel/php
  3. Paste the following code into the "PHP code to execute" textbox.
  4. Set the first 3 variables and then click execute

    $entity_type = 'node';    
    $field_name = 'body';    
    $bundle_name = 'article'; 
    
    $info_config = field_info_field($field_name);
    $info_instance = field_info_instance($entity_type, $field_name, $bundle_name);
    unset($info_config['id']);
    unset($info_instance['id'], $info_instance['field_id']);
    include_once DRUPAL_ROOT . '/includes/utility.inc';
    $output = "\$fields['" . $field_name . "'] = " . drupal_var_export($info_config) . ";\n";
    $output .= "\$instances['" . $field_name . "'] = " . drupal_var_export($info_instance) . ";";
    drupal_set_message("<textarea rows=30 style=\"width: 100%;\">" . $output . '</textarea>');
    
  5. You will get 2 arrays, something like this, hopefully with all the properties filled in.

$fields['field_some_field'] = array(
  'properties of the field'
);

$instances['field_some_field'] = array(
  'properties of the instance'
);

Now add the following code to your .install file. Replace all instances of mymodule with the actual module name. Paste the code from the devel output into the _mymodule_field_data and _mymodule_instance_data, as noted int the respective functions below. You can do this for as many fields as you like, just put all the $fields arrays in the _mymodule_field_data function and all the $instances in the _mymodule_instance_data function.

function mymodule_install() {

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

  // Create all the instances for our fields.
  // http://api.drupal.org/api/function/field_create_instance/7
  foreach (_mymodule_instance_data() as $instance) {
    field_create_instance($instance);
  }
}

// Create the array of information about the fields we want to create.
function _mymodule_field_data() {
  $fields = array();
  // Paste $fields data from devel ouput here.
  return $fields;
  }

// Create the array of information about the instances we want to create.
function _mymodule_instance_data() {
  $instances = array();
  // Paste $instances data from devel output here.
  return $instances;
}
1
0

You could also consider using the Features module to create the fields at install time.

As Features generates code for fields, an option is just to use the Feature module to generate the code into a dummy module and then copy & paste into your module's .install file.

The benefit being is the module doesn't depend on the Features module in your target environment.

1
  • 1
    Altough Features is a good way to export fields to code, that's not how to use Features. Features doesn't use the Field API CRUD to create fields from the generated .install. Commented Aug 1, 2011 at 11:04
0

You can use the customcompanymodule code given below to programatically create a content type with its various fields.

You can add this code in a .install file of your custom module. It will programmatically add a content type called "company" and its various types of fields (text, numeric, date (note: you will need to install Date module as Date field is not provided by default), image, list).

I have also added the uninstall code that will remove the content type "company" along with all of its fields and data when you will uninstall your 'customcompanymodule' module.

You can modify/remove these fields as per your needs:

function customcompanymodule_install() {
     $t = get_t();
     node_types_rebuild();
     $company = array(
    'type' => 'company',
    'name' => $t('Company'),
    'base' => 'node_content',
    'module' => 'node',
    'description' => $t('Content type to handle companys.'),
    'body_label' => $t('Company Description'),
    'title_label' => $t('Company Title'),
    'promote' => 0,
    'status' => 1,
    'comment' => 0,
);
$content_type = node_type_set_defaults($company);

node_type_save($content_type);

foreach (_company_installed_fields() as $field) {
    field_create_field($field);
}

foreach (_company_installed_instances() as $instance) {
    $instance['entity_type'] = 'node';
    $instance['bundle'] = 'company';
    field_create_instance($instance);
}

$weight = db_query("SELECT weight FROM {system} WHERE name = :name",    array(':name' => 'categories'))->fetchField();
db_update('system')->fields(array(
            'weight' => $weight + 1,
        ))
        ->condition('name', 'company')
        ->execute();
}

function _company_installed_fields() {
$t = get_t();
$fields = array(
    'company_startdate' => array(
        'field_name' => 'company_startdate',
        'label' => $t('Company Start Date'),
        'cardinality' => 1,
        'type' => 'datetime',
        'module' => 'date',
        'settings' => array(
            'granularity' => array(
                'month' => 'month',
                'day' => 'day',
                'hour' => 'hour',
                'minute' => 'minute',
                'year' => 'year',
                'second' => 0,
            ),
            'tz_handling' => 'site',
            'timezone_db' => 'UTC',
            'cache_enabled' => 0,
            'cache_count' => '4',
            'todate' => 'required',
        ),
    ),
    'company_totalwinners' => array(
        'field_name' => 'company_totalwinners',
        'label' => $t('Maximum Company Winners'),
        'cardinality' => 1,
        'type' => 'number_integer',
        'module' => 'number',
        'settings' => array(
            'max_length' => 10000,
        ),
    ),
    'company_minwinner' => array(
        'field_name' => 'company_minwinner',
        'label' => $t('Minimum Entries for Company to Activate'),
        'cardinality' => 1,
        'type' => 'number_integer',
        'module' => 'number',
        'settings' => array(
            'max_length' => 10000,
        ),
    ),
    'company_totalentries' => array(
        'field_name' => 'company_totalentries',
        'label' => $t('Company Total Entries'),
        'cardinality' => 1,
        'type' => 'number_integer',
        'module' => 'number',
        'settings' => array(
            'max_length' => 10000,
        ),
    ),
    'company_points' => array(
        'field_name' => 'company_points',
        'label' => $t('Company Points'),
        'cardinality' => 1,
        'type' => 'number_integer',
        'module' => 'number',
        'settings' => array(
            'max_length' => 10000,
        ),
    ),
    'company_image' => array(
        'field_name' => 'company_image',
        'label' => $t('Image'),
        'cardinality' => 1,
        'type' => 'image',
        'settings' => array(
            'default_image' => 0,
            'uri_scheme' => 'public',
        ),
    ),
    'company_description' => array(
        'field_name' => 'company_description',
        'label' => $t('Company Description'),
        'cardinality' => 1,
        'type' => 'text',
        'module' => 'text',
        'length' => '255'
    ),
    'company_winner' => array(
        'field_name' => 'company_winner',
        'label' => $t('Company Description'),
        'cardinality' => 1,
        'type' => 'text',
        'module' => 'text',
        'length' => '255'
    ),
    'field_autowinnerselection' => array(
        'field_name' => 'field_autowinnerselection',
        'label' => $t('Auto Company Winner Selection'),
        'type' => 'list_boolean',
        'module' => 'list',
        'active' => '1',
        'locked' => '0',
        'cardinality' => '1',
        'deleted' => '0'
    ),
);
return $fields;
}

function _company_installed_instances() {
$t = get_t();
$instances = array(
    'company_startdate' => array(
        'field_name' => 'company_startdate',
        'label' => $t('Company Lifespan'),
        'cardinality' => 1,
        'widget' => array(
            'type' => 'date_popup',
            'module' => 'date',
            'settings' => array(
                'input_format' => 'm/d/Y - H:i:s',
                'input_format_custom' => '',
                'year_range' => '-3:+3',
                'increment' => '15',
                'label_position' => 'above',
                'text_parts' => array(),
            ),
        ),
    ),
    'company_totalwinners' => array(
        'field_name' => 'company_totalwinners',
        'label' => $t('Maximum Company Winners'),
        'cardinality' => 1,
        'widget' => array(
            'type' => 'number',
            'module' => 'number',
            'settings' => array('size' => 60),
        ),
    ),
    'company_minwinner' => array(
        'field_name' => 'company_minwinner',
        'label' => $t('Minimum Number of Entries for Company to Activate'),
        'cardinality' => 1,
        'required' => 1,
        'widget' => array(
            'type' => 'number',
            'module' => 'number',
            'settings' => array('size' => 60),
        ),
    ),
    'company_totalentries' => array(
        'field_name' => 'company_totalentries',
        'label' => $t('Company Total Entries'),
        'cardinality' => 1,
        'required' => 1,
        'widget' => array(
            'type' => 'number',
            'module' => 'number',
            'settings' => array('size' => 60),
        ),
    ),
    'company_points' => array(
        'field_name' => 'company_points',
        'label' => $t('Company Points'),
        'cardinality' => 1,
        'required' => 1,
        'widget' => array(
            'type' => 'number',
            'module' => 'number',
            'settings' => array('size' => 60),
        ),
    ),
    'company_image' => array(
        'field_name' => 'company_image',
        'label' => $t('Image'),
        'cardinality' => 1,
        'required' => 1,
        'type' => 'company_image',
        'settings' => array(
            'max_filesize' => '',
            'max_resolution' => '213x140',
            'min_resolution' => '213x140',
            'alt_field' => 1,
            'default_image' => 0
        ),
        'widget' => array(
            'settings' => array(
                'preview_image_style' => 'thumbnail',
                'progress_indicator' => 'throbber',
            ),
        ),
        'display' => array(
            'default' => array(
                'label' => 'hidden',
                'type' => 'image',
                'settings' => array('image_style' => 'medium', 'image_link' => ''),
                'weight' => -1,
            ),
            'teaser' => array(
                'label' => 'hidden',
                'type' => 'image',
                'settings' => array('image_style' => 'thumbnail', 'image_link' => 'content'),
                'weight' => -1,
            ),
        ),
    ),
    'company_description' => array(
        'field_name' => 'company_description',
        'label' => $t('Company Description'),
        'cardinality' => 1,
        'widget' => array(
            'weight' => '-3',
            'type' => 'text_textfield',
            'module' => 'text',
            'active' => 1,
            'settings' => array(
                'size' => '1000',
            ),
        ),
    ),
    'company_winner' => array(
        'field_name' => 'company_winner',
        'label' => $t('Company Winner'),
        'cardinality' => 1,
        'widget' => array(
            'weight' => '-3',
            'type' => 'text_textfield',
            'module' => 'text',
            'active' => 1,
            'settings' => array(
                'size' => '60',
            ),
        ),
    ),
    'field_autowinnerselection' => array(
        'field_name' => 'field_autowinnerselection',
        'required' => 1,
        'label' => $t('Auto Company Winner Selection'),
        'widget' => array(
            'weight' => '-3',
            'type' => 'options_buttons',
            'module' => 'options',
            'active' => 1,
            'settings' => array(),
        ),
    ),
);
return $instances;
}

function customcompanymodule_uninstall() {
$content_types = array(
    'name1' => 'company',
);
$sql = 'SELECT nid FROM {node} n WHERE n.type = :type1';
$result = db_query($sql, array(':type1' => $content_types['name1']));
$nids = array();
foreach ($result as $row) {
    $nids[] = $row->nid;
}
node_delete_multiple($nids);
node_type_delete($content_types['name1']);
field_purge_batch(1000);
}
0

Try this module if you're looking for a way to create fields programmatically in Drupal 8: https://drupal.org/project/field_create

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