14
votes

I'm designing a new module in Drupal 8. It's a long-term project that won't be going public for a few months at least, so I'm using it as a way to figure out what's new.

In this module, I want to be able to programmatically create nodes. In Drupal 7, I would do this by creating the object, then calling "node_submit" and "node_save".

These functions no longer exist in Drupal 8. Instead, according to the documentation, "Modules and scripts may programmatically submit nodes using the usual form API pattern." I'm at a loss. What does this mean? I've used Form API to create forms in Drupal 7, but I don't get what the docs are saying here.

What I'm looking to do is programmatically create at least one and possibly multiple new nodes, based on information not taken directly from a user-presented form. I need to be able to:

1) Specify the content type

2) Specify the URL path

3) Set any other necessary variables that would previously have been handled by the now-obsolete node_object_prepare()

4) Commit the new node object

I would prefer to be able to do this in an independent, highly abstracted function not tied to a specific block or form.

So what am I missing?

5
@Clive entity_create() will be removed in Drupal 9 according to your link. Better use the object way : Entity::create() or Node::create() for a node. - v.nivuahc
@v.nivuahc Yep that's true. They weren't deprecated when I wrote the comment though, they were shiny and new ;) - Clive

5 Answers

21
votes

use Drupal\node\Entity\Node;

$node = Node::create(array(
    'type' => 'your_content_type',
    'title' => 'your title',
    'langcode' => 'en',
    'uid' => '1',
    'status' => 1,
    'field_fields' => array(),
));

$node->save();
6
votes

The D8 version of devel/devel_generate module has a good example of this.

From devel_generate :

  $edit_node = array(
    'nid' => NULL, 
    'type' => $node_type, 
    'uid' => $users[array_rand($users)], 
    'revision' => mt_rand(0, 1), 
    'status' => TRUE, 
    'promote' => mt_rand(0, 1), 
    'created' => REQUEST_TIME - mt_rand(0, $results['time_range']), 
    'langcode' => devel_generate_get_langcode($results),
  );
  if ($type->has_title) {
    // We should not use the random function if the value is not random
    if ($results['title_length'] < 2) {
      $edit_node['title'] = devel_create_greeking(1, TRUE);
    }
    else {
      $edit_node['title'] = devel_create_greeking(mt_rand(1, $results['title_length']), TRUE);
    }
  }
  else {
    $edit_node['title'] = '';
  }
  // @todo Remove once comment become field. http://drupal.org/node/731724
  if (Drupal::moduleHandler()->moduleExists('comment')) {
    $edit_node['comment'] = variable_get('comment_' . $node_type, COMMENT_NODE_OPEN);
  }
  $node = entity_create('node', $edit_node);

Using formatted text

Using grep with before/after code lines helped me figure out how to add a node with 'full_html'.

Search the Drupal core code with this :

$ cd drupal/core
$ grep -B 5 -A 5 -r entity_create.*node * > /tmp/temp-grep.txt

Then, open up /tmp/temp-grep.txt in a text editor. Poke around there a bit and you'll see this :

--
modules/editor/src/Tests/EditorFileUsageTest.php-    $body_value .= '<img src="awesome-llama.jpg" data-editor-file-uuid="invalid-editor-file-uuid-value" />';
modules/editor/src/Tests/EditorFileUsageTest.php-    // Test handling of a non-existing UUID.
modules/editor/src/Tests/EditorFileUsageTest.php-    $body_value .= '<img src="awesome-llama.jpg" data-editor-file-uuid="30aac704-ba2c-40fc-b609-9ed121aa90f4" />';
modules/editor/src/Tests/EditorFileUsageTest.php-    // Test editor_entity_insert(): increment.
modules/editor/src/Tests/EditorFileUsageTest.php-    $this->createUser();
modules/editor/src/Tests/EditorFileUsageTest.php:    $node = entity_create('node', array(
modules/editor/src/Tests/EditorFileUsageTest.php-      'type' => 'page',
modules/editor/src/Tests/EditorFileUsageTest.php-      'title' => 'test',
modules/editor/src/Tests/EditorFileUsageTest.php-      'body' => array(
modules/editor/src/Tests/EditorFileUsageTest.php-        'value' => $body_value,
modules/editor/src/Tests/EditorFileUsageTest.php-        'format' => 'filtered_html',
--

Note how 'body' now becomes an array with a 'value' and a 'format'.

5
votes

RE: deprecated entity create

Here is a short example of usage without the deprecated functions. This is particularly helpful for dynamic creation:

//define entity type and bundle
$entity_type="node";
$bundle="article";

//get definition of target entity type
$entity_def = \Drupal::entityManager()->getDefinition($entity_type);

//load up an array for creation
$new_node=array(
  //set title
  'title' => 'test node',

  //set body
  'body' => 'this is a test body, can also be set as an array with "value" and "format" as keys I believe',

  //use the entity definition to set the appropriate property for the bundle
  $entity_def->get('entity_keys')['bundle']=>$bundle
);

$new_post = \Drupal::entityManager()->getStorage($entity_type)->create($new_node);
$new_post->save();
2
votes

Figured it out. For anyone else with this issue, nodes are now treated as entities, and the entity module is now part of core. So my code ended up looking like this:

$new_page_values = array();
$new_page_values['type'] = 'my_content_type';
$new_page_values['title'] = $form_state['values']['page_title'];
$new_page_values['path'] = $new_page_path;

$new_page = entity_create('node', $new_page_values);
$new_page->save();
2
votes

Best way to create node in Drupal 8 via using core services

$node = \Drupal::entityTypeManager()->getStorage('node')->create([
  'type'       => 'content_type_machine_name',
  'field_text' => 'Foo',
  'title'      => 'Text Title',
]);
$node->save();