I frequently export field definitions so I can programmatically create them in an update.php function. In Drupal 6, the CCK module came bundled with a Content Copy, but (so far) I have found no similar tool in Drupal 7. Here are the tricks I use to do this in a quick an relatively painless way.
Drupal 7 comes with a welcome Field API, which standardizes all the content now stored in nodes, comments, users, and taxonomy terms. The major benefit (in my opinion) is that when you are working with a field—no matter what it is attached to—you can do just about anything you want. But that's beside the point.
The important thing to note is that a field is first it's one thing, and second is attached to a bundle. So, if you've got an image field on your Article content type, you actually have an image field (by itself), and an instance of that field which is attached to the "node" bundle of the type "article". Got it? Good.
If you want export a field definition, you can use the handy field_info_field and field_info_instance functions. Taking our example above, here's how you would call these two functions:
Now that you have your field and instance definitions, you are ready to create them in your script. Drupal 7 brings two functions which look a lot like their export counterparts, field_create_field and field_create_instance. Just pass in your field definitions, and you're done.
Now that you understand how it works, let me show you some easy tricks to incorporate this into your development workflow. After you've created your fields using the Field UI, navigate to /devel/php (this requires the must-have Devel module). Then, execute the following, populating the first three variables:
This will do several things. First, it exports your field and instance definitions. Then, it removes the field IDs, so you don't have any ID conflicts when importing. Lastly, it formats the "create" functions for you, and display it inside a textarea which you can copy and paste it into your script.
If you are like me, you'll do this over and over. Instead of bookmarking this article (or trying to memorize it), wouldn't it be nice if you could just punch a keystroke on your computer and have that all populate in the Devel textarea?
Wait, you can! If you use Google Chrome, you can install the Popchrom extension. Create yourself a trigger called "field_export", and put the code above in. Then, when you click Ctrl + Space (or whatever keystroke you've got Popchrom configured to recognize, this little snippet will replace "field_export". Easy, peasy, rice and cheesy.
I know, I know... we could make a module out of it. Maybe somebody already has. But in the meantime, this gets the job done.
Comments
Submitted by John Kirkilis on Sat, 06/04/2011 - 01:38 Permalink
Copying and Adding Bundles to Entities
Hi Joel,
Correct me if I'm wrong, but D7 won't allow the same field to be instantiated more than once in a bundle, which can suck if you want to use the same type of field multiple times within a given Content Type.
For example, if I create a Content Type called "Item" and a field called "icon". I can only use this icon field once for "Items". If I want each "Item" to have a color_icon field instance, a greyscale_icon field instance, and a black_and_white icon field instance, I cannot reuse that dang "icon" field. I've looked at the database structures and the Field API code, and it looks like there's no getting around this unless someone wrote a module to modify the Field UI for managing a Content Type to add a "duplicate" button for each field that would take the field instance definition with all its accompanying settings and to copy and populate a new instance as your code above suggests.
Similarly, if I wanted to do this with the field_collection field type, under development, I suppose this might require a bit more complexity unless the definitions of the embedded fields of the field_collection come along for free. I created a field_collection of 6 fields and tried to reuse it in the same content type, but was flatly rejected due to the same reason for any field.
Even though I've programmed for many years, I'm new to Drupal. If my basic assumptions are off, please let me know. I'm not so sure I want to create my first module to do something like this, but it could be fun... perhaps.
It looks like you code above creates a snippet that can pasted into one of your custom modules, but I'd prefer a more seamless method with a UI if possible.
Thoughts?
Submitted by Joel Stein on Fri, 06/10/2011 - 20:38 Permalink
It's impossible
You are correct. It is a rather complex issue, creating more than one instance of a field in the same bundle (content type). It wouldn't be as easy as adding a "duplicate" button to the field UI, because each field in a bundle has a unique name, and everything (core and contrib) works off that assumption. At the core (literally), it's impossible to pull off.
Options would include 1) creating new fields (field_color_icon, field_color_greyscale, etc), and 2) creating a new field type which allows you to select different options in a field that stores more than 1 value.
I think #2 is your best bet. The Field API is very strong in Drupal 7, and is well documented.
Submitted by David Seddon on Wed, 06/15/2011 - 10:31 Permalink
Snippet for exporting all fields on a bundle
FIRST, ON SOURCE SITE:
$export_data = array();
$export_data['entity_name'] = 'user';
$export_data['bundle_name'] = 'user';
$instances = field_info_instances($export_data['entity_name'], $export_data['bundle_name']);
foreach ($instances as $field_name => $field) {
$export_data['data'][] = array(
'field' => field_info_field($field_name),
'instance' => field_info_instance($export_data['entity_name'], $field_name, $export_data['bundle_name']),
);
}
var_export($export_data);
--------------------------------
THEN ON DESTINATION SITE:
//First, ensure $import_data = pasted output
foreach ($export_data['data'] as $item) {
field_create_field($item['field']);
field_create_instance($item['instance']);
}
Hope it helps!
Submitted by Matthew Slater on Sun, 06/26/2011 - 12:19 Permalink
re-creating
Thanks this worked well for me, but only once.
can you add a line or two that deletes the existing field and field instance so the import continues to work for developers who have to repeat the process?
Submitted by Joel Stein on Mon, 06/27/2011 - 20:22 Permalink
field_delete_field and field_delete_instance
Just use field_delete_field and field_delete_instance.
Submitted by Martijn on Mon, 07/11/2011 - 08:39 Permalink
copy node reference field (node title) to taxonomy term name
Hi,
Is it possible with this technique to copy a node reference field to a taxonomy term name?
I would like to have the same names as terms, as used on node reference to use also the drupal menu system. Having nodes with references:
- Continent node
- Country node with reference Continent
- Area node with reference Country, Continent
- Village node with reference Area, Country, Continent
- Accommodation node with reference Village, Area, Country, Continent
I would like to make taxonomy terms automated from the references to use as menu items with taxonomy menu and other taxonomy based modules.
Thanks a lot in advance for your reply!
greetings, Martijn
Submitted by marcvangend on Mon, 07/25/2011 - 10:06 Permalink
Thanks
Thanks, that was helpful. I needed to copy a couple of field instances from one bundle to several other bundles within the same site. This is the script I ran on /devel/php:
$origin = 'article';
$bundles = array('blog', 'news');
$fields = array('field_quote', 'field_image');
foreach ($fields as $field) {
$instance_data = field_info_instance('node', $field, $origin);
foreach ($bundles as $bundle) {
$instance_data['bundle'] = $bundle;
field_create_instance($instance_data);
}
}
Submitted by Kjetil Hårtveit on Tue, 07/26/2011 - 16:46 Permalink
Simply
Brilliant!
Submitted by Matthew Slater on Tue, 08/16/2011 - 17:25 Permalink
This is great, thanks.
This is great, thanks.
How about if it issues an extra line before creating the instance and the field, to check if it already exists. I keep getting conflicts when I use this code in my install hook and re-install. Field API doesn't fully delete a field's data when its module is uninstalled. See this from drupal core
function _comment_body_field_create($info) {
// Create the field if needed.
if (!field_read_field('comment_body', array('include_inactive' => TRUE))) {
$field = array(
'field_name' => 'comment_body',
'type' => 'text_long',
'entity_types' => array('comment'),
);
field_create_field($field);
}
Submitted by Sean on Wed, 03/13/2013 - 23:25 Permalink
Thanks
Just wanted to let you know that this was infinitely helpful!
Add new comment