3

I've been doing my first Drupal 8 project, and a major pain point, when you have a site with 10 or more content types, is to copy a view mode to all the other content types after you set it up on one type, such as "article".

The question is, how do speed-up the process within Drupal 8 of copying a change to a view mode on multiple content types? It can be a real pain point for developers on larger sites.

6

I had an ah ah moment when I found this page: https://api.drupal.org/api/drupal/core!includes!entity.inc/function/entity_get_display/8.2.x

You can write little scripts to update a field across many content types. This can potentially save you hours on your Drupal 8 development! We have a site with nearly 20 content types and let's say you want all of them be able to display with your new view mode, "card". You've set it up on the article content type and now you need to copy it over.

I created this helper function as an example:

**
 * Utility function to copy a display mode from one entity bundle to another.
 *
 * @param $entity_type
 *   string Entity type to update.
 * @param $source
 *    string Source node bundle.
 * @param $target
 *    string Target node bundle.
 *  @param $view_mode
 *    string view mode to use.
 */
function my_module_copy_display_mode($entity_type, $source, $target, $view_mode) {

    $entity_view_display = \Drupal::entityTypeManager()
    ->getStorage('entity_view_display')
    ->load($entity_type . '.' . $source . '.' . $view_mode);

    if (empty($entity_view_display)) {
      return;
    }

    $items_to_copy = $entity_view_display->get('content');

    $new_entity_view_display = \Drupal::entityTypeManager()
    ->getStorage('entity_view_display')
    ->load($entity_type . '.' . $target . '.' . $view_mode);

    if (empty($new_entity_view_display)) {
      // If it can't load view mode on target type, create it.
      $values = array(
        'targetEntityType' => $entity_type,
        'bundle' => $target,
        'mode' => $view_mode,
        'status' => TRUE,
      );
      $new_entity_view_display = \Drupal::entityTypeManager()
        ->getStorage('entity_view_display')
        ->create($values);
    }

    $arr = $new_entity_view_display->toArray();

    foreach($arr['content'] as $field_name => $field_data) {
      $new_entity_view_display->removeComponent($field_name);
    }

    $definitions = \Drupal::entityManager()->getFieldDefinitions($entity_type, $target);

    foreach($items_to_copy as $key => $value) {
      // Check if they are in the entity field definition array.
      // This prevents adding fields that aren't on this content type.
      if (!empty($definitions[$key])) {
        $new_entity_view_display->setComponent($key, $value);
      }
    }

    $new_entity_view_display->save();
}

To use this, I wrote a secondary function with our site's content types:

/**
 * Copy a given view mode from article bundle to all other node types.
 *
 * @param $view_mode
 *   string View Mode to copy.
 */
function my_module_copy_view_mode_from_article_to_other_types($view_mode) {
  $source = 'article';

  $targets = [
    'car',
    'gallery',
    'video',
    'listicle',
    // etc.  put all the content types you want to copy to.
  ];

  foreach ($targets as $target) {
    my_module_copy_display_mode('node', $source, $target, $view_mode);
  }

}

Then, I just ran this second function from /devel/php, with a handful of view modes I wanted to make sure were consistent across all node bundles.

It's very fast, and what used to take half-an-hour of drudgery, dragging and dropping, is now very fast!

Update: Here's a drush version you can add to a custom module, it also allows you to just copy one field from a display mode to another display mode.

    <?php
/**
 * Implements hook_drush_command().
 */
function mymodule_drush_command() {
  $items = array();
  $items['copy_display_mode'] = [
    'description' => 'Copy display mode to another display mode. Example: "drush cdm node article clinical_trial three_up_item three_up_item"',
    'arguments' => [
      'entity_type' => 'Entity type to update',
      'source' => 'Bundle to copy from',
      'target' => 'Bundle to copy to',
      'source_view_mode' => 'View mode to copy from',
      'target_view_mode' => 'View mode to copy to',
      'field_to_copy' => 'Optionally, copy just one field',
    ],
    'callback' => 'mymodule_copy_display_mode',
    'aliases' => ['cdm'],
  ];
  return $items;
}

/**
 * Utility function to copy a display mode from one node bundle to another.
 *
 * @param $entity_type
 *   string Entity type to update.
 * @param $source
 *    string Source bundle.
 * @param $target
 *    string Target bundle.
 * @param $source_view_mode
 *    string view mode to copy.
 * @param $target_view_mode
 *    string view mode to copy to.
 */
function mymodule_copy_display_mode($entity_type = "", $source = "", $target = "", $source_view_mode = "", $target_view_mode = "", $field_to_copy = "") {

  if (empty($entity_type)) {
    drush_print('Missing entity_type. Type "drush help cdm" for arguments.');
    return;
  }

  if (empty($source)) {
    drush_print('Missing source. Type "drush help cdm" for arguments.');
    return;
  }

  if (empty($target)) {
    drush_print('Missing target. Type "drush help cdm" for arguments.');
    return;
  }

  if (empty($source_view_mode)) {
    drush_print('Missing sourced_view_mode. Type "drush help cdm" for arguments.');
    return;
  }

  if (empty($target_view_mode)) {
    drush_print('Missing target_view_mode. Type "drush help cdm" for arguments.');
    return;
  }

  $entity_view_display = \Drupal::entityTypeManager()
    ->getStorage('entity_view_display')
    ->load($entity_type . '.' . $source . '.' . $source_view_mode);

  if (empty($entity_view_display)) {
    return;
  }

  $items_to_copy = $entity_view_display->get('content');

  $new_entity_view_display = \Drupal::entityTypeManager()
    ->getStorage('entity_view_display')
    ->load($entity_type . '.' . $target . '.' . $target_view_mode);

  $updated = "updated";

  if (empty($new_entity_view_display)) {
    // If it can't load view mode on target type, create it.
    $values = array(
      'targetEntityType' => $entity_type,
      'bundle' => $target,
      'mode' => $target_view_mode,
      'status' => TRUE,
    );
    $new_entity_view_display = \Drupal::entityTypeManager()
        ->getStorage('entity_view_display')
        ->create($values);
    // Change verb for output to user.
    $updated = "created";
  }

  $arr = $new_entity_view_display->toArray();

  if ($field_to_copy == "") {
    foreach ($arr['content'] as $field_name => $field_data) {
      $new_entity_view_display->removeComponent($field_name);
    }

    $definitions = \Drupal::entityManager()->getFieldDefinitions($entity_type, $target);

    $output = [];
    foreach ($items_to_copy as $key => $value) {
      // Check if they are in the entity field definition array.
      // This prevents adding fields that aren't on this content type.
      if (!empty($definitions[$key])) {
        $new_entity_view_display->setComponent($key, $value);
        $output[] = ' -- ' . $key;
      }
    }

    $new_entity_view_display->save();
    drush_print("$entity_type.$target.$target_view_mode $updated from $entity_type.$source.$source_view_mode");
  }
  else {

    $definitions = \Drupal::entityManager()->getFieldDefinitions($entity_type, $target);

    if (!empty($definitions[$field_to_copy])) {
      $new_entity_view_display->setComponent($field_to_copy, $items_to_copy[$field_to_copy]);
      $output = [' -- ' . $field_to_copy];
    }

    $new_entity_view_display->save();

    drush_print("copied field $field_to_copy to $entity_type.$target.$target_view_mode from $entity_type.$source.$source_view_mode");
  }

  if (!empty($output)) {
    foreach ($output as $item) {
      drush_print($item);
    }
  }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.