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.
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