User login

Easily add content with update hooks: use default content module exports to create content that needs to be in sync with configuration

An approach for keeping content that is added as part of development synchronized with test and production environments is to use the Default Content module to export the content. It's built for the content to be exported to an installation profile's 'content' folder, and then the module, if enabled, automatically brings the content in when the site is installed. Presuming that reinstalling the site would be a drastic step for getting one block's content (aside: we do find it useful to use installation profiles with default content for automated testing and initial development), it's also possible to import the content one item at a time, such as in an update hook, with the below code in your example.install or example.profile:

Updated to support taxonomy terms import!

<?php
/**
 * Import a piece of content exported by default content module.
 */
function example_import_default_content($path_to_content_json) {
  list(
$entity_type_id, $filename) = explode('/', $path_to_content_json);
 
$p = drupal_get_path('profile', 'guts');
 
$encoded_content = file_get_contents($p . '/content/' . $path_to_content_json);
 
$serializer = \Drupal::service('serializer');
 
$content = $serializer->decode($encoded_content, 'hal_json');
  global
$base_url;
 
$url = $base_url . base_path();
 
$content['_links']['type']['href'] = str_replace('http://drupal.org/', $url, $content['_links']['type']['href']);
 
$contents = $serializer->encode($content, 'hal_json');
 
// The path for the taxonomy term class is different.
 
if ($entity_type_id == 'taxonomy_term') {
   
$class = 'Drupal\taxonomy\Entity\Term';
  } else {
   
$class = 'Drupal\\' . $entity_type_id . '\Entity\\' . str_replace(' ', '', ucwords(str_replace('_', ' ', $entity_type_id)));
  }
 
$entity = $serializer->deserialize($contents, $class, 'hal_json', array('request_method' => 'POST'));
 
$entity->enforceIsNew(TRUE);
 
$entity->save();
}
?>

Export a custom block with an ID of 8:

drush dcer block_content 8

And used in your example.install file:

<?php
/**
 * Add the footer block content.
 *
 * Implements hook_update_N().
 */
function example_update_8001() {
 
example_import_default_content('block_content/136efd63-021e-42ea-8202-8b97305cc07f.json');
}
?>

See also Drupal 8 default content notes.

Searched words: 
programmatically make nodes, taxonomy terms, menu items, other content

Comments

This makes default_content much more useful

Thanks for this post. It makes the default_content module much more useful for site building!

I think a more reliable, and consistent, way to get the class name is like this:

<?php
  $class = \Drupal::entityTypeManager()->getDefinition($entity_type_id)->getClass();
?>

I could not figure out how to get it to update an existing content entity. I tried $entity->enforceIsNew(FALSE);, and I tried ['request_method' => 'PATCH'] with no success. Any ideas?

Post new comment

The content of this field is kept private and will not be shown publicly.
  • You may post code using <code>...</code> (generic) or <?php ... ?> (highlighted PHP) tags.
  • You can use Markdown syntax to format and style the text. Also see Markdown Extra for tables, footnotes, and more.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <img> <blockquote> <small> <h2> <h3> <h4> <h5> <h6> <sub> <sup> <p> <br> <strike> <table> <tr> <td> <thead> <th> <tbody> <tt> <output>
  • Lines and paragraphs break automatically.

More information about formatting options

By submitting this form, you accept the Mollom privacy policy.