Programmatically creating CCK nodes in PHP (interaction with the Path module)

I’ve been experimenting with the Drupal Content Construction Kit, which promised to be a more flexible way to deal with custom node types in the Drupal content management system. However, I’m a finicky sort of person who likes being able to reproduce the setup from a fresh start, and CCK isn’t well-known for that. In fact, CCK nodes aren’t well-known for being easy to move from one server to another.

Following the instructions for programmatically creating, inserting, and updating CCK nodes will get you most of the way there. Here are some of the gotchas you’ll want to watch out for.

I was using Path to define aliases for my nodes and the path aliases were just not getting created. After lots and lots of tracing with XDebug, I found out that it was checking for user_access, but no user was active during the installation process. Solution: create the admin user and load it into a global $user variable.

I also spent a fair bit of time being very annoyed with CCK and creating nodes programmatically in my install profile. Turns out that you first need to use install_add_content_type to create the base node type, _then_ follow the instructions to drupal_execute the form that adds custom fields.

Here’s a quick sketch of the code:

function profilename_profile_final() {
  // lots of other code here
  install_add_user('admin', 'admin', '[email protected]', array(), 1);
  global $user;
  $user = user_load(array('uid' => 1));
    // take this from Install Profile Wizard
  node_get_types('types', NULL, TRUE);  // flush cache
  $content = array();
  $content['type'] = array(
   // take this from content copy export
  $content['fields'] = array(
   // take this from content copy export
function _install_create_content($content) {
  global $_install_macro;
  $type_name = $content['type']['type'];
  $_install_macro[$type_name] = $content;
  include_once drupal_get_path('module', 'node') .'/';
  include_once drupal_get_path('module', 'content') .'/';
  $macro = 'global $_install_macro; $content = $_install_macro['. $type_name .'];';
  drupal_execute('content_copy_import_form', array('type_name' => $type_name, 'macro' => $macro));

Now I feel more confident about CCK…

One Pingback/Trackback

  • Hi Sacha — great posts on your experimentation with install profiles recently. I originally wrote install_profile_api — recall that all the install_ functions are essentially helper functions as we wait for Drupal core to gain its own data setters / getters.

    It sounds like we could extend install_add_content_type to take an optional second argument that is the $content array from content copy export. What do you think? If you have time, I’d love a patch:

  • Pingback: Weekly review | sacha chua :: enterprise 2.0 consultant, storyteller, geek()

  • Hi!
    Thanks for your instructions.
    I used them to create install profile for one of my sites.
    But I have the following problem with it:
    When I try to set value for one of my CCK fields which has ‘Select list’ type,
    the value is ignored.
    Here is my code:

    $values[“field_order_provider”][0][“value”] = $row[“Provider”];

    For nodes are created by hands the field looks like this:

    [0] => Array
    [value] => 1

    Any ideas?

  • Thanks for this starter!

    I’m now just copying the export wizard text output directly into a file I distribute with my profile, and then invoking it!
    I don’t need to make the content type beforehand – it all comes together.

    Plus some updates for todays version of CCK.

    _install_create_content_from_file(dirname(__FILE__). '/speciespage.content-type.php');

    * Programatically create content type and fields
    * Based on
    function _install_create_content_from_file($filename) {
    $content_string = file_get_contents($filename);
    $type_name = '';
    drupal_set_message("Creating content type definition from $filename" );

    include_once drupal_get_path('module', 'content') .'/modules/content_copy/content_copy.module';

    $values = array('type_name' => $type_name, 'macro' => $content_string);
    $form_state = array('values' => $values);
    drupal_execute('content_copy_import_form', $form_state);

  • mentus

    Thanks Sacha, it got working well in my project. mentus