In my last few Drupal projects I’ve taken to defining content types in a module. There are many benefits to this:
- Tighter control over functionality.
- Migration is as simple as enabling the new module. One and done! (This benefit applies more to Drupal pre-8, since D8 has all configs, including content type definitions, in core)
- You can always be confident in writing your module code that fields will exist, will be defined a certain way, etc. Saves space on writing endless empty() / isset() checks.
Why not use Features, you might ask? For me, I don’t like the extra complications Features brings, and I don’t like introducing a dependency when I can just as easily use native functionality to achieve the same thing.
Anyways, this post is not about module-defined content types in general. If you aren’t familiar with this subject, I recommend you check out this blog post.
There is a major difficulty with setting up module-defined content types, and that is figuring out what the configuration arrays for the field_create_field / field_create_instance functions. These arrays are quite picky and, to my knowledge, aren’t defined in any documentation (the Drupal 7 FAPI, while similar, is not at all the same thing!)
For a long time I relied on sample projects or cribbing off of other modules to figure out what these arrays should contain. This works for simple field types (text, text_long, etc.) but what about more complex field types? Like entity references, or dates? And what about non-core field types?
You could, of course, create your content type in the UI, then export it with Features and copy the code, but again, this requires you use Features.
Fortunately I recently stumbled upon a better way, which I will now share with you.
- For each field you want field definition code for, create the field through the UI and add it to a content type (it doesn’t have to be your node-defined content type – any will do.)
- Run this code in Devel PHP:
$entity_type = 'node';
$field_name = <field name>;
$bundle_name = <content type name>;
$info_config = field_info_field($field_name);
$info_instance = field_info_instance($entity_type, $field_name, $bundle_name);
include_once DRUPAL_ROOT . '/includes/utility.inc';
$output = "field_create_field(" . drupal_var_export($info_config) . ");\n";
$output .= "field_create_instance(" . drupal_var_export($info_instance) . ");";
drupal_set_message("<textarea rows=30 style=\"width: 100%;\">". $output .'</textarea>');
This will give you a nice output that shows all the configuration code for your field_create_field / field_create_instance inputs.
Note that a lot of the array keys are not necessary. You can prune them as needed (and probably should, for some of the keys. “Storage”, for example. Let Drupal handle that.)
That’s all there is to it! A simple solution that will vastly simplify your life when doing module-defined content types.