In the project I am currently working on, we can say that features is almost a prohibited word and every time we need a new field on a content type, we have to add it programmatically through a database update. But finding out how to prepare the array so field_create_field and field_create_instance can do their job could be a bit tedious, so here I am going to explain which is, for me, the best, easiest and more straightforward way to do it.
In this example I will show how to add an Entity Reference field to the Article content type, which will let me add unlimited references to nodes of the type Basic Page.
The first thing I do is create the field manually through the admin panel:
Once the field is in the database with the needed structure, I use devel to explore how it was built.
I start with a field_info_field to get the field structure, followed by field_info_instance to get its instance data on the specific bundle.
$field = field_info_field('field_basic_pages');
dsm($field);
$instance = field_info_instance('node', 'field_basic_pages', 'article');
dsm($instance);
So, now that we know how our field and instance are structured, it is just a matter of translating them into code, inside the update hook:
/**
* Implements hook_update_N().
*/
function my_module_update_7001() {
$field_machine_name = 'field_basic_pages';
if (!field_info_field($field_machine_name)) {
$field = array(
'field_name' => $field_machine_name,
'type' => 'entityreference',
'module' => 'entityreference',
'cardinality' => FIELD_CARDINALITY_UNLIMITED,
'settings' => array(
'target_type' => 'node',
'handler_settings' => array(
'target_bundles' => array(
'page',
),
),
),
);
field_create_field($field);
}
if (empty(field_info_instance('node', $field_machine_name, 'article'))) {
$instance = array(
'bundle' => 'article',
'description' => t('References to Basic pages.'),
'entity_type' => 'node',
'field_name' => $field_machine_name,
'label' => t('Basic Pages'),
'widget' => array(
'type' => 'entityreference_autocomplete',
'module' => 'entityreference',
),
);
field_create_instance($instance);
}
}
Finally, once the code is in place, run the update and the field will appear on the content type, ready to be populated.
I hope you find this useful and do not hesitate to contact us with any question you may have.
PS: It is worth mentioning that the array's elements you may need will vary depending on your project and requirements, but all the information would be on the variables printed on the devel page, so do not panic!
TIP: Before creating the field manually, you may want to create a backup of your database and restore it before running the update, since Drupal will not allow you to create a field with an already taken machine name.