How to programmatically create nodes, comments and taxonomies in Drupal 7

23 May · by Tim Kamanin · 5 min read

I've been busy with a migration work for my client recently. There is an established website built with some proprietary CMS with a decent amount of articles / pages, different categories and user comments. My team was hired to make a complete migration from this money-sucking old-fashioned proprietary CMS to a modern shiny open-source Drupal 7. I like this kind of tasks. It's always a pleasure to help people get rid of an old and proprietary technologies.

To accomplish this task, I needed to create nodes, comments and taxonomies programmatically in Drupal 7 , which is a pretty trivial task for Drupal 6. But in D7 with the introduction of entities and fields in core (aka CCK in core) things have changed a bit. In today's post I 'll show you how to programmatically create nodes, comments and taxonomies in Drupal 7.

In detail you'll find out how to:

1. Programmatically create a node:

  • Initialize a node object
  • Add body field
  • Add custom fields
  • Add file / image field
  • Add a term to a node
  • Save a node

2. Programmatically create a comment

3. Programmatically create a term

1. How to programmatically create a node

1.1 Initialize a node object

$node = new stdClass(); // We create a new node object
$node->type = "page"; // Or any other content type you want
$node->title = "Your title goes here";
$node->language = LANGUAGE_NONE; // Or any language code if Locale module is enabled. More on this below *
$node->path = array('alias' => 'your node path'); // Setting a node path
node_object_prepare($node); // Set some default values.
$node->uid = 1; // Or any id you wish

*We set LANGUAGE_NONE for $node- >language, if you don't have the locale module enabled, the node will not be assigned any particular language. So that's why we put here the constant LANGUAGE_NONE. In Drupal, nodes and fields can exist in more that one language, so if your site is multilingual you should specify the language code for your field. You can configure languages and get language codes by going this path in Drupal administration: Configuration -> Regional and language -> Languages.

1.2 Add a body field

// Let's add standard body field
$node->body[$node->language][0]['value'] = 'This is a body text';
$node->body[$node->language][0]['summary'] = 'Here goes a summary';
$node->body[$node->language][0]['format'] = 'filtered_html'; // If field has a format, you need to define it. Here we define a default filtered_html format for a body field

1.3 Add custom fields

// Let's add some CCK/Fields API field. This is pretty similar to the body example 
$node->field_custom_name[$node->language][0]['value'] = 'This is a custom field value';
// If your custom field has a format, don't forget to define it here
$node->field_custom_name[$node->language][0]['format'] = 'This is a custom field value';
// And etc. you can add as much fields here as your content type has. The sky is the limit... and the server specs, of course ;)

1.4 Add file / image fields

// Some file on our system
$file_path = drupal_realpath('somefile.png'); // Create a File object
$file = (object) array(
  'uid' => 1,
  'uri' => $file_path,
  'filemime' => file_get_mimetype($file_path),
  'status' => 1,
$file = file_copy($file, 'public://'); // Save the file to the root of the files directory. You can specify a subdirectory, for example, 'public://images' 
$node->field_image[LANGUAGE_NONE][0] = (array)$file; //associate the file object with the image field:

1.5 Add a term to a node

$node->field_tags[$node->language][]['tid'] = 1;

field_tags here is the name of a term reference field attached to your content type, 1 is a term id you wish to assign to a node. Simple!

1.6 Save a node

$node = node_submit($node); // Prepare node for a submit
node_save($node); // After this call we'll get a nid

2. How to programmatically create a comment

// Let's create a managed object $comment = new stdClass(); // We create a new comment object
$comment->nid = $node->nid; // nid of a node you want to attach a comment to
$comment->cid = 0; // leave it as is
$comment->pid = 0; // parent comment id, 0 if none 
$comment->uid = 1; // user's id, who left the comment
$comment->mail = ''; // user's email
$comment->name = 'User name'; // If user is authenticated you can omit this field, it will be auto-populated, if the user is anonymous and you want to name him somehow, input his name here
$comment->thread = '01/'; // OPTIONAL. If you need comments to be threaded you can fill this value. Otherwise omit it.
$comment->hostname = '127.0.01' // OPTIONAL. You can log poster's ip here
$comment->created = time(); // OPTIONAL. You can set any time you want here. Useful for backdated comments creation.
$comment->is_anonymous = 0; // leave it as is
$comment->homepage = ''; // you can add homepage URL here
$comment->status = COMMENT_PUBLISHED; // We auto-publish this comment
$comment->language = LANGUAGE_NONE; // The same as for a node
$comment->subject = 'Comment subject'; 
$comment->comment_body[$comment->language][0]['value'] = 'Comment body text'; // Everything here is pretty much like with a node
$comment->comment_body[$comment->language][0]['format'] = 'filtered_html'; 
$comment->field_custom_field_name[LANGUAGE_NONE][0]['value'] = 'Some value'; // OPTIONAL. If your comment has a custom field attached it can added as simple as this // preparing a comment for a save
comment_submit($comment); // saving a comment

3. How to programmatically create a taxonomy term

This one is the most easiest part of the tutorial. To create a term you just need to do the following:

$term = new stdClass();
$term->name = 'Term Name';
$term->vid = 1; // '1' is a vocabulary id you wish this term to assign to
$term->field_custom_field_name[LANGUAGE_NONE][0]['value'] = 'Some value'; // OPTIONAL. If your term has a custom field attached it can added as simple as this
taxonomy_term_save($term); // Finally, save our term

Well, that's all for today my friends, hope this article helps you. Please leave your comments and additions and if you liked the post, share it on twitter and facebook, spread the knowledge!


Required for comment verification

Hasan Raza

Nice and easy to follow tutorial, thanks

Reply · 2 months, 1 week ago
Gaurav Chawla

Thanks a lot.To the point and perfect explanation.Really helpful for newbies like me.

Reply · 6 years, 7 months ago

Thank you so much for the post! it was very very helpful!

Reply · 6 years, 7 months ago

I played around with this some more and the file object was created without a problem but it just wouldn´t attach to the node (erro display cannot be NULL). Setting the following array item to the file object fixed it.

 'display' => 1
Reply · 6 years, 7 months ago

Thanks for sharing! Doesn´t the file field on the note need a "display" value? Busla.

Reply · 6 years, 7 months ago

Just to add something....... can i add a user programatically by following code?? $account = new stdClass; $account->is_new = TRUE; $account->name = 'foo'; $account->pass = user_hash_password('bar'); $account->mail = ''; $account->init = ''; $account->status = TRUE; $account->roles = array(DRUPAL_AUTHENTICATED_RID => TRUE); $account->timezone = variable_get('date_default_timezone', ''); user_save($account);

Reply · 6 years, 7 months ago

Hi, Thanks for your article. Any idea/suggestion on how to get the new nid before saving? I need to get the nid of the new node before saving so i can use as reference. Thanks a lot.

Reply · 6 years, 7 months ago
Christopher Stevens

Hey Tim, Thanks for the great Drupal 7 migration tips. Today I'm helping a friend move his blog from a blogspot account he can't remember how to login to using scrapy, a Python based web crawler. It's converting pages into easy-to- digest JSON data (as soon as I can finish getting that all figured out). All this is kind of sad as there is a helpful export option in blogger and some helpful modules to import those exports... but this is good fun practice in the grand scheme of things. You post is SUPER helpful in getting these comments to transfer with the nodes. Have you tried posting user comments without an email? I don't have access to that info, but perhaps can assign them all to a single generic email or something if needed. Thanks for the great post. Chris

Reply · 6 years, 7 months ago

How about programmatically create custom block? Can you please help and advise? Thanks for the share btw. :)

Reply · 6 years, 7 months ago

It was pretty cool. It has helped me a lot. Thanks.

Reply · 6 years, 7 months ago

And you can add as many as you like! (if field is multivalue XD)

node->field_tags[$node->language][]['tid'] = 1;
node->field_tags[$node->language][]['tid'] = 2;
node->field_tags[$node->language][]['tid'] = 3;

Thanks for the tip!

Reply · 6 years, 7 months ago
Ahmar Ali

Thanks for great article. I am new to Drupal and come from WP background. I am developing a small system for my client who is using Drupal to add nodes into the website externally. I see I can pull the products from API and put them as nodes . I will have to use create node functionality. But where exactly I have to put this code ? I mean in which file I do it extract products from API and then add them as nodes. Please help thanks.

Reply · 6 years, 7 months ago

Useful!! It helps me very much!

Reply · 6 years, 7 months ago

THANK YOU! Man, you are great! Your article did my day. Thank you From Russia with Love, Denis

Reply · 6 years, 7 months ago

Just another typo error. in 1.4 (file/image saving) you wrote:

  'filemime' => file_get_mimetype($filepath),

but it should be $file_path not $filepath:

  'filemime' => file_get_mimetype($file_path),

Thanks again for your article ;)

Reply · 6 years, 7 months ago

Thanks a lot. You saved my life. I have spent too much hours searching around, before discovering your tutorial.

Reply · 6 years, 7 months ago

How about sanitation? Do I need to use check_plain() or does node_save take care of that?

Reply · 6 years, 7 months ago

Hi, This is the type of code i want. I also know that i need to create a custom module to use this code. But in drupal, a module is called using a hook. So please tell me which hook i need to use to call this function. My basic requirement is ..... I have a csv file and i need to import data from that.

Reply · 6 years, 7 months ago
Bill Szkotnicki

Hi, I am trying to make this work but I get ------> Undefined class constant 'MYSQL_ATTR_USE_BUFFERED_QUERY' even with just this: define('DRUPAL_ROOT', '/var/www/html/drupaldev/'); require_once DRUPAL_ROOT . '/includes/'; drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL); exit; My drupal installation is working perfectly otherwise and pdo_mysql is enabled. Any ideas? Thanks, Bill

Reply · 6 years, 7 months ago

Thanks for this article, very useful. However I had a bug regarding the author of my new node. node_object_prepare($node) seems to reset $node->uid. Therefore I needed to this line $node->uid = '1'; AFTER this one: node_object_prepare($node); This is for Drupal 7.12, while creating nodes in a cron job. I don't know if this is true for earlier versions of Drupal 7.

Reply · 6 years, 7 months ago

I have a error when i using a query to read a node in a database to write in my database is: PDOException: in drupal_write_record() (line 6868 of C:\xampp\htdocs\emerald\includes\ my query can read data in db but it only read 7line in db, and it have a problem like this, so it's not work. Can you show me how to resolve my problem. Thanks

Reply · 6 years, 7 months ago
Robert Weinstein

Thanks for the very useful how-to, I have a question on one of the steps: $node->uid = 1; // Or any id you wish Forgive me if this is obvious as I am new to Drupal. Would we not want to get whatever the next node uid is after the last node was created assuming we are beyond the first node creation? I also see: node_save($node); // After this call we'll get a nid Does this then mean that in the first piece of code uid=1 is just a placeholder id for the content UNTIL the node is created and the system will automatically "do the rest" and give it the next node id in the series (along with pathauto etc..)? Thanks in advance

Reply · 6 years, 7 months ago

I am pretty new with D7. Could you point out which libraries need to be included in the script in order to have access to all D7 functions? Regards

Reply · 6 years, 7 months ago
Sergio Nunes

In 1.5 case how would you attach "yellow" term into the tags field? Many Thanks, Sergio

Reply · 6 years, 7 months ago

Hi, Thanks for the great clear tutorial! I want to import a book with approx 200 pages from an XML, the book is structured in different chapters. In the XML I have the parent id (the chapter they belong to, chapter is just a page as well) of each page. How can I set which book a page belongs to and what is the parent of each book (I tried $node->pid but this didn't work) Thanks! Joris

Reply · 6 years, 7 months ago

Thank you :)

Reply · 6 years, 7 months ago
Marc Isaacson

Thanks so much for this write up. It helped me to do exactly what I needed to do!

Reply · 6 years, 7 months ago
Rafael Silva

That's very nice, but I was wondering if you have considered using Migrate module. I recently used it to migrate some data to a D6 website and it was pretty slick!

Reply · 6 years, 7 months ago
Florian Loretan

You use $node->language as the language key in field structures:

$node->body[$node->language][0]['value'] = 'This is a body text';

However, the language of the field is not always the language of the node. The language code to be used should be retrieved using field_language() instead.

Reply · 6 years, 7 months ago

But where this file should be stored? in module folder?

Reply · 6 years, 7 months ago

Thanks for this article really helped me, I am using drupal 6 for creating a node programmaticlly, and in drupal 6 the function to save a term is taxonomy_save_term($term); maybe this will help someone like me found this article and working on drupal 6 ;) Again thanks for sharing.

Reply · 6 years, 7 months ago