I am writing an install profile which adds some initial content to the site. For adding content I have written a custom function in .install file. In this function, I am preparing a node object & using node_save to save content to the site. The content type in question has an image field. I am preparing $file object, copying files to public folder and assigning the $file object to the image field. When I run this code snippet independently in (an installed site), the nodes get created properly along with image fields. However, when this code is run as a part of install profile's .install file, the nodes are created without image field values attached to created nodes. Everything else works normally, i.e. nodes are created, files are copied from profile folder to files folder, file entities are created in the database, only problem is that image field values of created nodes are blank (not populated).

Here's the code that I am using in .install file


/*
Content Type: banner
Fields: title, banner image (field_home_banner_image)
I have 4 images in my_install_profile/images folder, named banner1.jpeg, banner2.jpeg... etc)
I am running a loop to create 4 nodes & attach 4 images as above to the nodes
*/
  //create banner image nodes
  
  for ($i = 0; $i < 4; $i++) {
    $j = $i + 1;
  
   // Create a node object, and add node properties.
  $newNode = (object) array('type' => 'banner'); //banner is the content type, with title & image fields
  node_object_prepare($newNode);
  $newNode->type = 'banner';
  $newNode->title = 'Banner-'.$j;
  $newNode->uid = 1;
  $newNode->comment = 0;
  $newNode->promote = 0;
  $newNode->moderate = 0;
  $newNode->sticky = 0;
  $newNode->language = 'und';

//I am storing images in /images folder of my install profile
  $file_path = drupal_get_path('profile', '<name_of_profile>') . '/images/banner' . $j . '.jpeg';
  
//Preparing file object
    $file = (object)array(
      "uid" => 1,
      "uri" => $file_path,
      "filemime" => file_get_mimetype($file_path),
      "status" => 1
    );

//copying files from profile/images folder to public folder. This works, as the files are copied to the files folder & also entries are created in database tables

    $file = file_copy($file, 'public://', FILE_EXISTS_REPLACE);

    $newNode->field_home_banner_image['und'][0] = (array)$file;

// The above line tries to attach $file object to the file field, and THIS NOT WORKING from .install file
// I also tried this
// $newNode->field_home_banner_image[LANGUAGE_NONE][0] = (array)$file;
// and this
// $newNode->field_home_banner_image['und'][] = (array)$file;


// Save the node.
    node_submit($newNode);  
    node_save($newNode); 

//Nodes get saved, but without image field values

  drupal_set_message('node '.$newNode->title . ' added');
  }

Just with to mention again, when I run the above code snippet in an installed site, nodes get created along with image filed values. But when this is run as a part of .install file of install profile, nodes get created without image filed values.

I am missing something or is there any different function call needed for writing node_save function in an install profile.

Any help appreciated.

Prasad
====================
UPDATE: Solved
====================
Solved the problem by adding this function in .profile file rather than .install file. It seems that Drupal is not fully bootstrapped while .install file is running, so field related functions are not available.

Comments

weseze’s picture

An install_hook IS run from a full bootstrap, so that isn't the problem.

I have also had this problem with custom content types defined in modules. The field instances are not known yet or something like that.
The solution is to put a call to "node_types_rebuild();" before you start saving nodes.

JoshuaHartmann’s picture

That is awesome!
You just saved me a ton of time. If ever you are in Brisbane I owe you a coffee.

Also side note I notice when I use the above the preview in the edit form is broken, any suggestions on how to fix this? (will google)
- Josh

joris_lucius’s picture

Great, thanks!
Your solution helped us out to add nodes on installing our profiles.

We used it like this

/**
 * Implements hook_install_tasks().
 */
function openlucius_install_tasks(&$install_state) {
  $tasks = array();

  $tasks['_openlucius_create_first_group'] = array(
    'type' => 'normal',
  );

  return $tasks;
}

/**
 * Custom function to create first group
 */
function _openlucius_create_first_group(){

  node_types_rebuild();

  $node = new stdClass(); // We create a new node object
  $node->type = "ol_group"; // Or any other content type you want
  $node->title = "First Group, Yihaaa!";
  $node->uid = 1; // Or any id you wish
  node_object_prepare($node); // Set some default values.

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

-- Cheers, Joris

carsoncho’s picture

Thank you guys for sharing, this is exactly what I needed for the install profile I'm working on. I can now successfully create nodes from within the profile. Combining the code from the original post and everything said in the above comments, I now have something like this inside of the .install file:

function my_profile_install_tasks(&$install_state) {
  $tasks = array();

  $tasks['_my_profile_create_front_page_sliders'] = array(
      'type' => 'normal',
  );

  return $tasks;
}

/**
 * Custom function to create front page slider nodes
 */
function _my_profile_create_front_page_sliders() {

  node_types_rebuild(); 

  for ($i = 0; $i < 3; $i++) {
    $j = $i + 1;

    // Create a node object, and add node properties.
    $newNode = (object) array('type' => 'front_page_slide'); // We create a new node object,
    node_object_prepare($newNode); // Set some default values.
    $newNode->type = 'front_page_slide'; // Or any other content type you want
    $newNode->title = 'Slide-'.$j;
    $newNode->uid = 1; // Or any id you wish
    $newNode->comment = 0;
    $newNode->promote = 0;
    $newNode->moderate = 0;
    $newNode->sticky = 0;
    $newNode->language = LANGUAGE_NONE;

    $newNode->field_heading_2[$newNode->language][]['value'] = 'Subheading-'.$j;

    // I am storing images in /images folder of my install profile
    $file_path = drupal_get_path('profile', '<name_of_profile>') . '/images/banner-' . $j . '.jpg';

    // Preparing file object
    $file = (object)array(
        "uid" => 1,
        "uri" => $file_path,
        "filemime" => file_get_mimetype($file_path),
        "status" => 1
    );

    // copying files from profile/images folder to public folder. This works, as the files are copied to the files folder & also entries are created in database tables
    $file = file_copy($file, 'public://', FILE_EXISTS_REPLACE);
    // Set our field to use the newly copied file
    $newNode->field_slider_image[$newNode->language][] = (array)$file;

    // Save the node.
    node_submit($newNode); // Prepare node for a submit
    node_save($newNode); // After this call we'll get a nid
  }
}