Most of this was written in 2011 and while everything is still perfectly usable, there’s more ground that I want to cover, such as working with i18n, EntityFieldQuery, media, etc. I will hopefully have the time to write a bigger and better guide later in 2013. If you have any requests for things I should write about, let me know in the comments!
I had to import a few thousand items from a legacy database to a Drupal 7 site and found that it was quite easy to do so programmatically. Here I’ll first show you the basic code for adding nodes and then I’ll talk about different field types, including how to add images and term references (taxonomy). If you have any questions, just ask in the comments and I’ll be happy to help!
Basic node creation - example
Put the code below in e.g.
foo_update.php. Make sure it’s not accessible through the web (unless you don’t have shell access and must execute it through the browser and know what you are doing). In other words, put it outside your Drupal directory, and then just run
php foo_update.php. Note that you have to make sure that the input is valid! Test and test again, always make backups and get used to examining nodes with e.g.
drush php-eval 'print_r(node_load($nid))' (see below for more about that).
If you use drush, you can skip the bootstrap part and, from your Drupal root directory, run
drush scr ../foo_update.php (assuming
foo_update.php is one directory above).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
$node->language is important! If you don’t have the locale module enabled, the node will not be assigned any particular language. Or rather, the language code used then is
LANGUAGE_NONE, which is a constant with the value
und (undefined) in Drupal. If you have locale enabled nodes can exist in more than one language, and you should specify the language code. Go to Configuration -> Regional and language -> Languages to configure languages and see what code you should use. For English, it would be
en; for Swedish, it would be
Other things you might want to set:
$node->status(1 or 0): published or not
$node->promote(1 or 0): promoted to front page
$node->sticky(1 or 0): sticky at top of lists
$node->comment: 2 = comments open, 1 = comments closed, 0 = comments hidden
This all you need for basic node creation. I will continue with different field types. The code below should be placed before the
node_submit line. All fields can be accessed with
$node->field_fieldname, where fieldname is the name you find in Structure -> Content types -> Manage fields.
The best way to see how Drupal nodes are made up, and how to work with the various fields, is to simply look at the structure of an existing node. Just create a new PHP file with the first bunch of lines above (including drupal_bootstrap) and add
print_r(node_load($nid)), where $nid is the node id. Or use drush:
drush php-eval 'print_r(node_load($nid))'.
Setting various field types
Text or integer field
Multiple values (make sure the field is configured to allow this):
To set a node’s creation time, you’d think you could just set
$node->created. And you can - if you don’t use
node_submit() (or if you set it after
node_submit()). Looking at the
node_submit() function in
node.module, we find this line:
Which means that
node_submit() will set
$node->created to the current time if
$node->date doesn’t exist. So, if you want to set the creation time, you have to do something like this:
This also means that if you are updating a node programmatically, don’t forget to set
node_submit() will change the creation time. Or, when updating a node, simply don’t use
node_submit(), since all it does is populate author and creation time. See Updating nodes programmatically in Drupal 7 for more about updating.
Date field (datetime, date, datestamp)
If your field is named datetest, you could do:
1 2 3 4 5 6 7 8
Note that you don’t need to specify a complete date; for datetime and date you can just pad with zeros, e.g. “2011-05-00 00:00:00” (datetime), “2011-00-00T00:00:00” (date), etc. For datestamp you could just do e.g.
Important: Also note that while the exact value you specify will be stored in the database, the actual time displayed on the site might be different depending on timezone settings. When you create a new datetime/date/datestamp field, you get to choose between five different timezone handling methods. The default one is “site’s time zone”:
When entering data into the field, the data entered is assumed to be in the site’s time zone. When the data is saved to the database, it is converted to UTC.
However, if you set a date field programmatically like in the above example then no conversion takes place, so make sure you account for the field’s timezone settings. Or in other words, if you use “site’s time zone”, make sure the time is in UTC.
Single on/off checkbox:
Term reference (taxonomy) field
Set the term reference field tags to taxonomy term id 25 (for more than one term, just repeat the line; and note that it doesn’t matter whether the widget type is select list, check boxes/radio buttons or autocomplete):
(If you are trying this with the tags field in the default article content type, and have locale enabled, and have set
$node->language to e.g. ‘en’, and it doesn’t seem to work: I also encountered this oddity (bug?). For some reason tags are saved to
$node->field_tags[und] instead of
$node->field_tags[en], while e.g. body is saved to
$node->body[en] as expected. If I create a new term reference field, it works as it should. So either do that, or change the above to
As you can see, you need the know the taxonomy term’s id. Fortunately, there’s a Drupal function to help us with this:
taxonomy_get_term_by_name(). You supply the name (“Italy”) and it returns an array of matching term objects, so you can do something like this:
1 2 3 4
Unfortunately, you can’t specify a certain vocabulary with this function. This means that if you have the same term name in more than one vocabulary, the above code will just use whatever happens to come first. If you want to specify a certain vocabulary, say the one with id 9, you could do something like this:
1 2 3 4 5 6
(One way of figuring out the vocabulary id is to run
But what if you want to create new vocabulary terms for those that aren’t already in the database? You can use
taxonomy_term_save(), like this:
1 2 3 4 5 6 7
$new_term is very conveniently updated with the tid of our newly created term, which you can get with
If you use the references module for node/user references you can set a reference like this:
This way you can also add multiple references in the same field - just repeat.
Entity field references
I haven’t had time to update this document properly (yet!) but Mark Losey wrote the following in a comment (thanks Mark!):
“If you are using the product reference field in drupal commerce it’s a variation on that:”
Attaching an image to any given image field is easy. Create a file object, copy the file and associate the file object with the image field:
1 2 3 4 5 6 7 8 9 10
Pathauto URL aliases
Joakim Hedlund comments (thanks!) that you can turn off the automatic path aliases generated by pathauto with the following:
Note that you have to turn pathauto off like this if you don’t want it to overwrite custom aliases. See How does Pathauto determine if the ‘Automatic URL alias’ checkbox should be checked or not? for more information.