You are here

field_ui.inc in Display Suite 8.2

Same filename and directory in other branches
  1. 8.4 includes/field_ui.inc
  2. 8.3 includes/field_ui.inc

Field UI functions for Display Suite.

File

includes/field_ui.inc
View source
<?php

/**
 * @file
 * Field UI functions for Display Suite.
 */
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Drupal\Core\Entity\Entity\EntityViewDisplay;
use Drupal\Core\Form\FormState;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element;
use Drupal\Core\Url;
use Drupal\ds\Ds;
use Drupal\ds\Plugin\DsField\DsFieldInterface;
use Drupal\field\FieldConfigInterface;
use Drupal\field_ui\FieldUI;
use Drupal\layout_plugin\Layout;

/**
 * Adds the Display Suite fields and layouts to the form.
 */
function ds_field_ui_fields_layouts(&$form, FormStateInterface $form_state) {
  global $base_root, $base_path;

  // Get the entity_type, bundle and view mode.
  $entity_type = $form['#entity_type'];
  $bundle = $form['#bundle'];

  /* @var \Drupal\Core\Entity\EntityFormInterface $entity_form */
  $entity_form = $form_state
    ->getFormObject();

  /* @var \Drupal\Core\Entity\Display\EntityDisplayInterface $entity_display */
  $entity_display = $entity_form
    ->getEntity();
  $view_mode = $entity_display
    ->getMode();

  // Create vertical tabs.
  ds_field_ui_create_vertical_tabs($form);

  // Add layout fieldset.
  _ds_field_ui_table_layouts($entity_type, $bundle, $view_mode, $form, $form_state);

  // Add/alter fields on the table, but only if a layout is selected.
  if (!empty($form['#ds_layout'])) {
    _ds_field_ui_fields($entity_type, $bundle, $view_mode, $form, $form_state);

    // Also alter core fields.
    _ds_field_ui_core_fields($form, $form_state);
  }

  // Special validate function for field group.
  if ($form_state
    ->has('no_field_group')) {
    array_unshift($form['#validate'], '_ds_field_group_field_ui_fix_notices');
  }

  // Attach js.
  $form['#attached']['library'][] = 'ds/admin';

  // Add process function to add the regions.
  $form['#process'][] = 'ds_field_ui_regions';

  // Add a destination so we can get back if layout has been changed.
  $form['ds_source'] = array(
    '#type' => 'hidden',
    '#value' => $base_root . $base_path,
  );
  $form['ds_destination'] = array(
    '#type' => 'hidden',
    '#value' => drupal_get_destination(),
  );
  $form['ds_entity_type'] = array(
    '#type' => 'hidden',
    '#value' => $entity_type,
  );
  $form['ds_bundle'] = array(
    '#type' => 'hidden',
    '#value' => $bundle,
  );
  $form['ds_view_mode'] = array(
    '#type' => 'hidden',
    '#value' => $view_mode,
  );
}

/**
 * Create vertical tabs.
 */
function ds_field_ui_create_vertical_tabs(&$form) {

  // Add additional settings vertical tab.
  if (!isset($form['additional_settings'])) {
    $form['additional_settings'] = array(
      '#type' => 'vertical_tabs',
      '#theme_wrappers' => array(
        'vertical_tabs',
      ),
      '#prefix' => '<div>',
      '#suffix' => '</div>',
      '#tree' => TRUE,
    );
  }

  // @todo needs core permission
  $view_mode_admin_access = \Drupal::currentUser()
    ->hasPermission('admin_view_modes');
  if (isset($form['modes'])) {
    $form['modes']['#group'] = 'additional_settings';
    $form['modes']['#weight'] = -10;
    if ($view_mode_admin_access) {
      $url = Url::fromRoute('field_ui.display_mode');
      $form['modes']['view_modes_custom']['#description'] = \Drupal::l(t('Manage display modes'), $url);
    }
  }
}

/**
 * Add Regions to 'Manage fields' or 'Manage display' screen.
 *
 * @param array $form
 *   The form to add layout fieldset and extra Display Suite fields.
 * @param FormStateInterface $form_state
 *   The current form state.
 *
 * @return array
 *   The altered form
 */
function ds_field_ui_regions(array $form, FormStateInterface $form_state) {

  // Get the entity_type, bundle and view mode.
  $entity_type = $form['#entity_type'];
  $bundle = $form['#bundle'];

  /* @var EntityFormInterface $entity_form */
  $entity_form = $form_state
    ->getFormObject();

  /* @var \Drupal\Core\Entity\Display\EntityDisplayInterface $entity_display */
  $entity_display = $entity_form
    ->getEntity();
  $view_mode = $entity_display
    ->getMode();

  // Ignore field_group options.
  if ($form_state
    ->has('no_field_group')) {
    unset($form['fields']['_add_new_group']);
    $form['field_group']['#access'] = FALSE;
  }

  // Check layout.
  $layout = isset($form['#ds_layout']) ? $form['#ds_layout'] : FALSE;

  // Build an array which keys are the field names and
  // values are the region they are rendered in.
  $field_regions = array();

  // Change UI to add Region column if we have a layout.
  if ($layout) {
    foreach ($layout['regions'] as $region_name => $field_names) {
      foreach ($field_names as $field_name) {
        $field_regions[$field_name] = $region_name;
      }
    }
    $table =& $form['fields'];
    $table['#header'] = array(
      t('Label'),
      t('Weight'),
      t('Parent'),
      t('Region'),
      t('Name'),
      t('Field'),
      t('Widget'),
      array(
        'data' => t('Operations'),
        'colspan' => 2,
      ),
    );
    $table['#regions'] = array();
    $region_options = array();
    foreach ($layout['region_names'] as $region_key => $region_info) {
      $region_options[$region_key] = $region_info['label'];
      $table['#regions'][$region_key] = array(
        'title' => $region_info['label'],
        'message' => t('No fields are displayed in this region'),
      );
    }

    // Let other modules alter the regions.
    $context = array(
      'entity_type' => $entity_type,
      'bundle' => $bundle,
      'view_mode' => $view_mode,
    );
    $region_info = array(
      'region_options' => &$region_options,
      'table_regions' => &$table['#regions'],
    );
    \Drupal::moduleHandler()
      ->alter('ds_layout_region', $context, $region_info);
    $region_options['hidden'] = t('Disabled');
    $table['#regions']['hidden'] = array(
      'title' => t('Disabled'),
      'message' => t('No fields are hidden.'),
    );
    $region = array(
      '#type' => 'select',
      '#options' => $region_options,
      '#default_value' => 'hidden',
      '#attributes' => array(
        'class' => array(
          'ds-field-region',
        ),
      ),
    );

    // Update existing rows by changing rowHandler and adding regions.
    foreach (Element::children($table) as $name) {
      $row =& $table[$name];
      $row['#js_settings'] = array(
        'rowHandler' => 'ds',
      );
      $row['#region_callback'] = 'ds_field_ui_row_region';

      // Remove hidden format.
      if (isset($row['plugin']['type']['#options']['hidden'])) {
        unset($row['plugin']['type']['#options']['hidden']);
      }

      // Add label class.
      if (isset($row['label'])) {
        if ($form_state
          ->has('plugin_settings')) {
          $plugin_settings = $form_state
            ->get('plugin_settings');
          if (isset($plugin_settings[$name]['ft']['settings']) && !empty($plugin_settings[$name]['ft']['settings']['lb'])) {
            $row['human_name']['#plain_text'] = $plugin_settings[$name]['ft']['settings']['lb'] . ' ' . t('(Original: @orig)', array(
              '@orig' => $row['human_name']['#plain_text'],
            ));
          }
        }
      }

      // Add region.
      $split = 7;
      $second = array_splice($row, $split);
      $row['region'] = $region;
      $row['region']['#default_value'] = isset($field_regions[$name]) && isset($region_options[$field_regions[$name]]) ? $field_regions[$name] : 'hidden';
      $row = array_merge($row, $second);
    }
  }
  return $form;
}

/**
 * Returns the region to which a row in the Field UI screen belongs.
 *
 * @param array $row
 *   The current row that is being rendered in the Field UI screen.
 *
 * @return string
 *   The region.
 */
function ds_field_ui_row_region(array $row) {
  return isset($row['region']['#value']) ? $row['region']['#value'] : 'hidden';
}

/**
 * Validate the layout settings on the Field UI.
 */
function ds_field_ui_layouts_validate($form, FormStateInterface $form_state) {

  // Determine layout variables.
  $layout = $form_state
    ->getValue('layout');
  $old_layout = $form_state
    ->getValue('old_layout');
  $new_layout = $layout != $old_layout || empty($old_layout);

  // Only validate the layout settings if the layout hasn't changed.
  if (!$new_layout && !empty($layout)) {

    /* @var \Drupal\layout_plugin\Plugin\Layout\LayoutInterface $layout_plugin */
    $layout_plugin = Layout::layoutPluginManager()
      ->createInstance($form_state
      ->getValue('layout'), []);
    $layout_form = isset($form['layout_configuration']) ? $form['layout_configuration'] : [];
    foreach (Element::children($form) as $name) {
      if (!empty($form[$name]['#ds_layout_configuration'])) {
        $layout_form[$name] = $form[$name];
      }
    }
    $layout_form_state = (new FormState())
      ->setValues($form_state
      ->getValue('layout_configuration', []));
    $layout_plugin
      ->validateConfigurationForm($layout_form, $layout_form_state);
  }

  // Move the view modes so Field UI can handle them.
  if ($form_state
    ->hasValue('modes')) {
    $modes = $form_state
      ->getValue('modes');
    if (isset($modes['display_modes_custom'])) {
      $form_state
        ->setValue('display_modes_custom', $modes['display_modes_custom']);
    }
  }
}

/**
 * Save the layout settings from the 'Manage display' screen.
 */
function ds_field_ui_layouts_save($form, FormStateInterface $form_state) {
  $save_display = FALSE;

  // Get default values.
  $entity_type = $form['#entity_type'];

  /* @var \Drupal\Core\Entity\EntityFormInterface $entity_form */
  $entity_form = $form_state
    ->getFormObject();

  // Get the entity display.

  /* @var \Drupal\Core\Entity\Display\EntityDisplayInterface $display */
  $display = $entity_form
    ->getEntity();

  // Get view mode.
  $view_mode = $display
    ->getMode();

  // Determine layout variables.
  $layout = $form_state
    ->getValue('layout');
  $disable_css = $form_state
    ->getValue('disable_css');
  $entity_classes = $form_state
    ->getValue('entity_classes');
  if (empty($entity_classes)) {
    $entity_classes = 'all_classes';
  }
  $old_layout = $form_state
    ->getValue('old_layout');
  $new_layout = $layout != $old_layout || empty($old_layout);
  $key = array_search('ds_field_ui_change_layout_submit', $form['actions']['submit']['#submit']);
  if ($key && !empty($old_layout)) {
    return;
  }
  $ds_layouts = Ds::getLayouts();

  // Save layout and add regions if necessary.
  $record = array();
  $record['layout'] = array(
    'id' => $layout,
    'path' => !empty($layout) ? $ds_layouts[$layout]['path'] : '',
    'library' => isset($ds_layouts[$layout]['library']) ? $ds_layouts[$layout]['library'] : FALSE,
    'disable_css' => $disable_css ? TRUE : FALSE,
    'entity_classes' => $entity_classes,
  );
  $record['regions'] = array();

  // Remove old layout if necessary.
  if ($new_layout && !empty($old_layout) || empty($layout)) {
    $display
      ->unsetThirdPartySetting('ds', 'layout');
    $display
      ->unsetThirdPartySetting('ds', 'regions');
    $display
      ->save();
  }
  if ($new_layout && !empty($layout)) {
    $save_display = TRUE;

    // Move current visible fields into a default region, so
    // we keep their current settings.
    $layouts = Ds::getLayouts();
    $sl = $layouts[$layout];
    $first_region = key($sl['regions']);
    $record['layout']['settings']['classes'] = array();
    $record['layout']['settings']['wrappers'] = array();

    // Set default region values.
    foreach ($sl['regions'] as $region_name => $content) {
      $record['layout']['settings']['wrappers'][$region_name] = 'div';
    }
    $record['layout']['settings']['outer_wrapper'] = 'div';
    $record['layout']['settings']['attributes'] = '';
    $record['layout']['settings']['link_attribute'] = FALSE;
    $record['layout']['settings']['link_custom'] = '';
    $fields = _ds_sort_fields($form_state
      ->getValue('fields'), 'weight');
    foreach ($fields as $field_key => $field) {

      // Ignore new fieldgroup, new field or existing field.
      if (in_array($field_key, array(
        '_add_new_field',
        '_add_existing_field',
        '_add_new_group',
      ))) {
        continue;
      }

      // Can either be form or display.
      if (isset($field['type']) && $field['type'] != 'hidden') {
        $record['regions'][$first_region][] = $field_key;
      }
    }

    // In case this is the full node view mode and if the comment module
    // is enabled for this content type, add it as well.
    if ($entity_type == 'node' && $view_mode == 'full' && \Drupal::moduleHandler()
      ->moduleExists('comment')) {
      $record['regions'][$first_region][] = 'comments';
    }
  }
  elseif (!empty($layout)) {
    $save_display = TRUE;
    $fields = _ds_sort_fields($form_state
      ->getValue('fields'), 'weight');
    foreach ($fields as $key => $field) {

      // Make sure to hide hidden fields.
      if ($field['region'] == 'hidden') {
        $form_state
          ->setValue([
          'fields',
          $key,
          'type',
        ], 'hidden');
        continue;
      }
      if (!isset($record['regions'][$field['region']])) {
        $record['regions'][$field['region']] = array();
      }
      $record['regions'][$field['region']][] = $key;
    }

    /* @var \Drupal\layout_plugin\Plugin\Layout\LayoutInterface $layout_plugin */
    $layout_plugin = Layout::layoutPluginManager()
      ->createInstance($layout, []);
    $layout_form = isset($form['layout_configuration']) ? $form['layout_configuration'] : [];
    foreach (Element::children($form) as $name) {
      if (!empty($form[$name]['#ds_layout_configuration'])) {
        $layout_form[$name] = $form[$name];
      }
    }
    $layout_form_state = (new FormState())
      ->setValues($form_state
      ->getValue('layout_configuration', []));
    $layout_plugin
      ->submitConfigurationForm($layout_form, $layout_form_state);

    // Get the layout settings from the layout_plugin.
    $record['layout']['settings'] = $layout_plugin
      ->getConfiguration();

    // Let other modules alter the layout settings.
    \Drupal::moduleHandler()
      ->alter('ds_layout_settings', $record, $form_state);
  }

  // Save the configuration.
  if ($save_display) {

    // Let other modules alter the layout settings.
    \Drupal::moduleHandler()
      ->alter('ds_layout_settings', $record, $form_state);
    foreach (array_keys($record) as $key) {
      $display
        ->setThirdPartySetting('ds', $key, $record[$key]);
    }
    $display
      ->save();
  }
}

/**
 * Form validation handler for _ds_field_ui_fields().
 */
function ds_field_ui_fields_validate($form, FormStateInterface $form_state) {
  $fields = $form_state
    ->getValue('fields');
  foreach (Element::children($form['fields']) as $key) {
    if (isset($fields[$key]['settings_edit_form']['settings'])) {
      $settings = $fields[$key]['settings_edit_form']['settings'];
      if (!empty($settings)) {
        $plugin_settings = $form_state
          ->get('plugin_settings');
        $plugin_settings[$key] = $settings;
        $form_state
          ->set('plugin_settings', $plugin_settings);
      }
    }
    if (isset($fields[$key]['settings_edit_form']['third_party_settings']['ds'])) {
      $settings = $fields[$key]['settings_edit_form']['third_party_settings']['ds'];
      if (!empty($settings)) {
        $plugin_settings = $form_state
          ->get('plugin_settings');
        $plugin_settings[$key] = $settings;
        $form_state
          ->set('plugin_settings', $plugin_settings);
      }
    }
  }
}

/**
 * Save the field settings from the 'Manage display' screen.
 */
function ds_field_ui_fields_save($form, FormStateInterface $form_state) {
  if (empty($form['#ds_fields'])) {
    return;
  }

  // Get the entity display.

  /* @var \Drupal\Core\Entity\EntityFormInterface $entity_form */
  $entity_form = $form_state
    ->getFormObject();

  /* @var \Drupal\Core\Entity\Display\EntityDisplayInterface $display */
  $display = $entity_form
    ->getEntity();
  $field_settings = array();

  // Fetch values from form_state.
  $all_field_values = $form_state
    ->getValue('fields');
  $all_plugin_settings = $form_state
    ->get('plugin_settings');

  // Save settings for each Display Suite field.
  $ds_fields = $form['#ds_fields'];
  foreach ($ds_fields as $field) {
    $field_values = $all_field_values[$field];

    // In case the region is hidden, do not save.
    if (isset($field_values['region']) && $field_values['region'] == 'hidden') {
      continue;
    }

    // Build settings.
    $settings = array();
    $settings['plugin_id'] = $field;
    $settings['weight'] = $field_values['weight'];
    $settings['label'] = $field_values['label'];
    $settings['formatter'] = $field_values['plugin']['type'];

    // Any formatter settings.
    if (isset($all_plugin_settings[$field]['settings'])) {
      $settings['settings'] = $all_plugin_settings[$field]['settings'];
    }
    elseif (isset($all_plugin_settings[$field])) {

      // When the settings for that fields aren't changed the structure is
      // different.
      // @todo figure out how we can fix this.
      $settings['settings'] = $all_plugin_settings[$field];
    }
    $field_settings[$field] = $settings;

    // Always unset the field template settings from the regular settings array.
    // @todo needs serious review.
    unset($field_settings[$field]['settings']['ft']);

    // Add field template plugin settings if provided.
    $values = isset($all_plugin_settings[$field]['ft']) ? $all_plugin_settings[$field]['ft'] : array();
    if (!empty($values)) {
      $field_settings[$field]['ft'] = $values;
      $default_field_function = \Drupal::config('ds.settings')
        ->get('ft-default');
      $function = isset($values['id']) ? $values['id'] : $default_field_function;
      $field_settings[$field]['ft']['id'] = $function;

      // It's important for schema validation to never save empty arrays.
      if (empty($field_settings[$field]['ft']['settings'])) {
        unset($field_settings[$field]['ft']['settings']);
      }
    }

    // Last but not least unset the settings if they are empty after moving the
    // field template settings.
    if (empty($field_settings[$field]['settings'])) {
      unset($field_settings[$field]['settings']);
    }
  }

  // Save the record.
  $display
    ->unsetThirdPartySetting('ds', 'fields');
  if (!empty($field_settings)) {
    $display
      ->setThirdPartySetting('ds', 'fields', $field_settings);
  }
  $display
    ->save();

  // Clear the ds_fields cache.
  Cache::invalidateTags(array(
    'ds_fields_info',
  ));
}

/**
 * Clone a fields layout.
 */
function ds_field_ui_layout_clone($form, FormStateInterface $form_state) {
  $clone = $form_state
    ->getValue('clone');
  list(, , $cv) = explode('.', $clone);
  $entity_type = $form['#entity_type'];
  $bundle = $form['#bundle'];

  /* @var \Drupal\Core\Entity\EntityFormInterface $entity_form */
  $entity_form = $form_state
    ->getFormObject();

  // Get the entity display.

  /* @var \Drupal\Core\Entity\Display\EntityDisplayInterface $old_display */
  $old_display = $entity_form
    ->getEntity();
  $view_mode = $old_display
    ->getMode();
  $old_display
    ->delete();

  /* @var \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display */
  $display = EntityViewDisplay::load($entity_type . '.' . $bundle . '.' . $cv);
  $clone_display = $display
    ->createCopy($view_mode);
  $clone_display
    ->save();

  // Show message.
  drupal_set_message(t('The layout has been cloned.'));
}

/**
 * Creates a summary for the field format configuration summary.
 *
 * @param DsFieldInterface $plugin_instance
 *   An instance of the plugin.
 * @param array $settings
 *   The passed settings.
 * @param FormStateInterface $form_state
 *   The form state of the summary.
 *
 * @return array
 *   The summary.
 */
function ds_field_settings_summary(DsFieldInterface $plugin_instance, array $settings, FormStateInterface $form_state) {

  // Create the form.
  $summary = $plugin_instance
    ->settingsSummary($settings);

  // Add field template summary.
  ds_field_formatter_settings_summary_alter($summary, array(
    'field_definition' => $plugin_instance,
    'form_state' => $form_state,
  ));
  if (empty($summary)) {
    return array();
  }
  return array(
    '#type' => 'inline_template',
    '#template' => '<div class="field-plugin-summary">{{ summary|safe_join("<br />") }}</div>',
    '#context' => array(
      'summary' => $summary,
    ),
    '#cell_attributes' => array(
      'class' => array(
        'field-plugin-summary-cell',
      ),
    ),
  );
}

/**
 * Creates a form for Display Suite fields.
 *
 * @param DsFieldInterface $plugin_instance
 *   An instance of the plugin.
 * @param FormStateInterface $form_state
 *   The form state of the form.
 *
 * @return mixed
 *   The altered form.
 */
function ds_field_settings_form(DsFieldInterface $plugin_instance, FormStateInterface $form_state) {

  // Create the form.
  $form = $plugin_instance
    ->settingsForm(array(), $form_state);

  // Add field template settings to every field if enabled.
  if (\Drupal::config('ds.settings')
    ->get('field_template')) {
    $context = array(
      'instance' => array(
        'entity_type' => $plugin_instance
          ->getEntityTypeId(),
        'bundle' => $plugin_instance
          ->bundle(),
        'field_name' => $plugin_instance
          ->getName(),
      ),
      'view_mode' => $plugin_instance
        ->viewMode(),
    );
    ds_field_template_settings_form($form, $form_state, $context);
  }
  return $form;
}

/**
 * Add fake field group value in.
 *
 * @param array $form
 *   The actual form.
 * @param FormStateInterface $form_state
 *   The form state of the form.
 */
function _ds_field_group_field_ui_fix_notices(array $form, FormStateInterface $form_state) {
  $field_group = array(
    'group_name' => '',
    'label' => '',
  );
  $fields = $form_state
    ->getValue('fields');
  $fields['_add_new_group'] = $field_group;
  $form_state
    ->setValue('fields', $fields);
}

/**
 * Add the layouts fieldset on the Field UI screen.
 *
 * @param string $entity_type
 *   The name of the entity type.
 * @param string $bundle
 *   The name of the bundle.
 * @param string $view_mode
 *   The name of the view_mode.
 * @param array $form
 *   A collection of form properties.
 * @param FormStateInterface $form_state
 *   The form_state.
 */
function _ds_field_ui_table_layouts($entity_type, $bundle, $view_mode, array &$form, FormStateInterface $form_state) {
  $ds_layouts = Ds::getLayouts();
  $layout_options = array(
    '' => t('- None -'),
  );
  $optgroup = '';
  foreach ($ds_layouts as $key => $layout_definition) {
    $optgroup = t('Other');

    // Create new layout option group.
    if (!empty($layout_definition['category'])) {
      $optgroup = (string) $layout_definition['category'];
    }
    if (!isset($layout_options[$optgroup])) {
      $layout_options[$optgroup] = array();
    }

    // Stack the layout.
    $layout_options[$optgroup][$key] = $layout_definition['label'];
  }

  // If there is only one $optgroup, move it to the root.
  if (count($layout_options) == 2) {
    $options = $layout_options[$optgroup];
    $layout_options = array_merge(array(
      '' => t('- None -'),
    ), $options);
  }

  // Add layouts form.
  $form['ds_layouts'] = array(
    '#type' => 'details',
    '#title' => t('Layout for @bundle in @view_mode', array(
      '@bundle' => str_replace('_', ' ', $bundle),
      '@view_mode' => str_replace('_', ' ', $view_mode),
    )),
    '#collapsible' => TRUE,
    '#group' => 'additional_settings',
    '#collapsed' => FALSE,
    '#weight' => -100,
  );

  // @todo cleanup
  $layout = array();

  /* @var \Drupal\Core\Entity\EntityFormInterface $entity_form */
  $entity_form = $form_state
    ->getFormObject();

  /* @var \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display */
  $display = $entity_form
    ->getEntity();
  if ($display
    ->getThirdPartySetting('ds', 'layout')) {
    $layout_configuration = $display
      ->getThirdPartySetting('ds', 'layout');
    $layout = $ds_layouts[$layout_configuration['id']];
    $layout['layout'] = $layout_configuration['id'];
    $layout['disable_css'] = $layout_configuration['disable_css'];
    $layout['entity_classes'] = $layout_configuration['entity_classes'];
    $layout['settings'] = $layout_configuration['settings'] ?: [];
    $layout['regions'] = $display
      ->getThirdPartySetting('ds', 'regions');
    $layout['fields'] = $display
      ->getThirdPartySetting('ds', 'fields');
  }
  if (!empty($layout) && isset($layout['layout']) && isset($ds_layouts[$layout['layout']])) {
    $layout['region_names'] = $ds_layouts[$layout['layout']]['regions'];
    $form['#ds_layout'] = $layout;
  }

  // Load the layout preview form.
  $layout['layout_options'] = $layout_options;
  _ds_field_ui_table_layouts_preview($form, $form_state, $ds_layouts, $layout, $display);
  if (!empty($layout) && !empty($layout['settings'])) {

    /* @var \Drupal\layout_plugin\Plugin\Layout\LayoutInterface $layout_plugin */
    $layout_plugin = Layout::layoutPluginManager()
      ->createInstance($layout['layout'], $layout['settings'] ?: []);
    $layout_configuration_form = $layout_plugin
      ->buildConfigurationForm([], $form_state);

    // Merge 'details' elements in 'additional_settings' group into the main
    // form.
    foreach (Element::children($layout_configuration_form) as $name) {
      $element = $layout_configuration_form[$name];
      if ($element['#type'] == 'details' && $element['#group'] == 'additional_settings') {
        $form[$name] = $layout_configuration_form[$name];
        unset($layout_configuration_form[$name]);
        $form[$name]['#ds_layout_configuration'] = TRUE;
        $form[$name]['#parents'] = [
          'layout_configuration',
          $name,
        ];
        $form[$name]['#tree'] = TRUE;
        if ($layout['layout'] === 'ds_reset') {
          $form[$name]['#access'] = FALSE;
        }
      }
    }

    // If anything is left, then we put it on it's own vertial tab.
    if (!Element::isEmpty($layout_configuration_form)) {
      $form['layout_configuration'] = array_merge($layout_configuration_form, [
        '#group' => 'additional_settings',
        '#type' => 'details',
        '#title' => t('Layout settings'),
        '#tree' => TRUE,
      ]);
    }
  }
  else {

    // See if we can clone from another view mode.
    $options = array();
    $entity_displays = \Drupal::configFactory()
      ->listAll('core.entity_view_display.' . $entity_type . '.' . $bundle);
    foreach ($entity_displays as $name) {
      $row = \Drupal::config($name)
        ->get();
      if ($row['mode'] == $view_mode) {
        continue;
      }
      if ($row['targetEntityType'] == $entity_type && $row['bundle'] == $bundle) {
        $options[$row['id']] = Unicode::ucfirst(str_replace('_', ' ', $row['targetEntityType'])) . ' > ' . Unicode::ucfirst(str_replace('_', ' ', $row['bundle'])) . ' > ' . Unicode::ucfirst(str_replace('_', ' ', $row['mode']));
      }
    }
    if (!empty($options)) {

      // Clone from another layout.
      $form['ds_clone'] = array(
        '#type' => 'details',
        '#group' => 'additional_settings',
        '#title' => t('Clone layout'),
        '#collapsible' => TRUE,
        '#collapsed' => TRUE,
      );
      $form['ds_clone']['clone'] = array(
        '#title' => t('Select an existing layout to clone.'),
        '#type' => 'select',
        '#options' => $options,
        '#weight' => 20,
      );
      $form['ds_clone']['clone_submit'] = array(
        '#type' => 'submit',
        '#value' => t('Clone layout'),
        '#submit' => array(
          'ds_field_ui_layout_clone',
        ),
        '#weight' => 21,
      );
    }
  }
  $form['ds_layouts']['old_layout'] = array(
    '#type' => 'value',
    '#value' => isset($layout['layout']) ? $layout['layout'] : 0,
  );

  // Add validate and submit handlers. Layout needs be first so
  // we can reset the type key for Field API fields.
  $form['#validate'][] = 'ds_field_ui_layouts_validate';
  array_unshift($form['actions']['submit']['#submit'], 'ds_field_ui_fields_save');
  array_unshift($form['actions']['submit']['#submit'], 'ds_field_ui_layouts_save');
}

/**
 * Add the layout previews to the Field UI screen.
 *
 * @param array $form
 *   A collection of form properties.
 * @param FormStateInterface $form_state
 *   The state of the form.
 * @param array $ds_layouts
 *   Collection of all the layouts.
 * @param array $layout
 *   Current selected layout.
 * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display
 *   The entity display object.
 */
function _ds_field_ui_table_layouts_preview(array &$form, FormStateInterface $form_state, array $ds_layouts, array $layout, EntityViewDisplayInterface $display) {
  $layout_string = '';
  $form['ds_layouts']['layout'] = array(
    '#type' => 'select',
    '#title' => t('Select a layout'),
    '#options' => $layout['layout_options'],
    '#default_value' => isset($layout['layout']) ? $layout['layout'] : '',
    '#weight' => -1,
    '#ajax' => array(
      'callback' => 'ds_field_ui_table_layouts_preview_callback',
      'wrapper' => 'ds_layout_wrapper',
    ),
  );
  if (!isset($layout['layout'])) {
    $form['ds_layouts']['layout']['#description'] = t("A layout must be selected to enable Display Suite functionality.");
  }
  $form['ds_layouts']['preview'] = array(
    '#type' => 'container',
    '#prefix' => '<div id="ds_layout_wrapper">',
    '#suffix' => '</div>',
    '#weight' => -3,
  );
  if (isset($layout['layout']) || $form_state
    ->hasValue('layout')) {
    $layout_string = $form_state
      ->hasValue('layout') ? $form_state
      ->getValue('layout') : $layout['layout'];
  }
  if (!empty($layout_string)) {
    $chosen_layout = $ds_layouts[$layout_string];
    $selected = '<strong>' . $chosen_layout['label'] . '</strong>';
    $selected .= '<br/>' . t('The default template can be found in %path', array(
      '%path' => $chosen_layout['template_path'],
    ));
    $suggestions_array = array();
    $suggestions_array[0] = $layout_string . '--' . $display
      ->getTargetEntityTypeId();
    $suggestions_array[2] = $layout_string . '--' . $display
      ->getTargetEntityTypeId() . '-' . $display
      ->getTargetBundle();
    $suggestions_array[4] = $layout_string . '--' . $display
      ->getTargetEntityTypeId() . '--{id}';
    if ($display
      ->getMode() != 'default') {
      $suggestions_array[1] = $layout_string . '--' . $display
        ->getTargetEntityTypeId() . '-' . $display
        ->getMode();
      $suggestions_array[3] = $layout_string . '--' . $display
        ->getTargetEntityTypeId() . '-' . $display
        ->getTargetBundle() . '-' . $display
        ->getMode();
    }
    ksort($suggestions_array);

    // Append correct extension.
    foreach ($suggestions_array as $key => $value) {
      $suggestion_replace = strtr($suggestions_array[$key], '_', '-');
      $suggestions_array[$key] = $suggestion_replace . '.html.twig';
    }
    if ($form_state
      ->hasValue('layout') || !empty($layout) && isset($layout['regions'])) {
      $fallback_image = drupal_get_path('module', 'ds') . '/images/preview.png';
      $current_layout = $form_state
        ->hasValue('layout') && (!isset($layout->layout) || $form_state
        ->getValue('layout') != $layout->layout) ? t('Current layout (after save)') : t('Current layout');
      $image = isset($chosen_layout['icon']) && !empty($chosen_layout['icon']) ? $chosen_layout['icon'] : $fallback_image;
      $form['ds_layouts']['preview']['title'] = array(
        '#markup' => '<div class="ds-layout-preview-title">' . $current_layout . '</div>',
      );
      $form['ds_layouts']['preview']['image'] = array(
        '#markup' => '<div class="ds-layout-preview-image"><img src="' . base_path() . $image . '"/></div>',
      );
      $form['ds_layouts']['preview']['info'] = array(
        '#type' => 'container',
        '#attributes' => array(
          'class' => array(
            'ds-layout-preview-suggestion',
          ),
        ),
      );
      $form['ds_layouts']['preview']['info']['suggestions'] = array(
        '#markup' => '<p>' . $selected . '</p><p>' . t('Template suggestions') . ':' . '</p>',
      );
      $form['ds_layouts']['preview']['info']['suggestions_list'] = array(
        '#theme' => 'item_list',
        '#items' => $suggestions_array,
      );
      if (!empty($chosen_layout['css'])) {
        $disable_css = FALSE;
        if (isset($layout['disable_css'])) {
          $disable_css = $layout['disable_css'];
        }
        if ($form_state
          ->hasValue('disable_css') && $disable_css !== $form_state
          ->getValue('disable_css')) {
          $disable_css = $form_state
            ->getValue('disable_css');
        }
        $form['ds_layouts']['preview']['info']['settings']['disable_css'] = array(
          '#type' => 'checkbox',
          '#title' => t('Disable layout CSS styles'),
          '#default_value' => $disable_css,
        );
      }
      $entity_classes = 'all_classes';
      if (isset($layout['entity_classes'])) {
        $entity_classes = $layout['entity_classes'];
      }
      if ($form_state
        ->hasValue('entity_classes') && $entity_classes !== $form_state
        ->getValue('entity_classes')) {
        $entity_classes = $form_state
          ->getValue('entity_classes');
      }

      // Default classes.
      $form['ds_layouts']['preview']['info']['settings']['entity_classes'] = array(
        '#type' => 'select',
        '#title' => t('Entity classes'),
        '#options' => array(
          'all_classes' => t('Entity, bundle and view mode'),
          'no_classes' => t('No classes'),
          'old_view_mode' => t('View mode (deprecated)'),
        ),
        '#default_value' => $entity_classes,
      );
      $form['ds_layouts']['preview']['clear'] = array(
        '#markup' => '<div class="ds-after-suggestion"></div>',
      );
    }
    if (!isset($layout['layout']) || $layout_string != $layout['layout']) {

      // Get admin path.
      $route = FieldUI::getOverviewRouteInfo($display
        ->getTargetEntityTypeId(), $display
        ->getTargetBundle());
      $route_parameters = $route
        ->getRouteParameters();
      $route_parameters['view_mode_name'] = $display
        ->getMode();
      $options = $route
        ->getOptions();
      $route_name = 'entity.entity_view_display.' . $display
        ->getTargetEntityTypeId() . '.view_mode';
      $admin_path = \Drupal::service('url_generator')
        ->generateFromRoute($route_name, $route_parameters, $options);
      $destination_url = '';

      // If regions aren't set we don't have to move fields.
      if (isset($layout['regions'])) {
        $route_name = 'ds.change_layout';
        $route_parameters = array(
          'entity_type' => $display
            ->getTargetEntityTypeId(),
          'bundle' => $display
            ->getTargetBundle(),
          'display_mode' => $display
            ->getMode(),
          'new_layout' => $layout_string,
        );
        $options = array();
        $destination_url = $admin_path;
      }
      $form['layout_changed_url'] = array(
        '#type' => 'value',
        '#value' => array(
          'route_name' => $route_name,
          'route_parameters' => $route_parameters,
          'destination_url' => $destination_url,
          'options' => $options,
        ),
      );
      array_unshift($form['actions']['submit']['#submit'], 'ds_field_ui_change_layout_submit');
    }
  }
}

/**
 * Ajax callback for _ds_field_ui_table_layouts_preview().
 */
function ds_field_ui_table_layouts_preview_callback($form, FormStateInterface $form_state) {
  return $form['ds_layouts']['preview'];
}

/**
 * Form submission handler for _ds_field_ui_table_layouts_preview().
 */
function ds_field_ui_change_layout_submit($form, FormStateInterface $form_state) {

  // Remove original destination.
  \Drupal::request()->query
    ->remove('destination');
  $destination = $form_state
    ->getValue('layout_changed_url');
  $redirectUrl = new Url($destination['route_name'], $destination['route_parameters'], $destination['options']);
  if (!empty($destination['destination_url'])) {
    $redirectUrl
      ->setOption('query', array(
      'destination' => $destination['destination_url'],
    ));
  }
  $form_state
    ->setRedirectUrl($redirectUrl);
}

/**
 * Add the fields to the Field UI form.
 *
 * @param string $entity_type
 *   The name of the entity type.
 * @param string $bundle
 *   The name of the bundle.
 * @param string $view_mode
 *   The name of the view_mode.
 * @param array $form
 *   A collection of form properties.
 * @param FormStateInterface $form_state
 *   A collection of form_state properties.
 */
function _ds_field_ui_fields($entity_type, $bundle, $view_mode, array &$form, FormStateInterface $form_state) {

  // Do not add the fields if there is no layout.
  if (!isset($form['#ds_layout'])) {
    return;
  }

  // Get the fields and put them on the form.
  $fields = Ds::getFields($entity_type);

  // Get field settings.
  $field_settings = $form['#ds_layout']['fields'];
  $form['#field_settings'] = $field_settings;
  $table =& $form['fields'];
  $form['#ds_fields'] = array();
  $field_label_options = array(
    'above' => t('Above'),
    'inline' => t('Inline'),
    'hidden' => t('- Hidden -'),
  );
  \Drupal::moduleHandler()
    ->alter('ds_label_options', $field_label_options);

  /* @var \Drupal\Core\Entity\EntityFormInterface $entity_form */
  $entity_form = $form_state
    ->getFormObject();

  /* @var \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display */
  $display = $entity_form
    ->getEntity();
  $parent_options = array();
  if (function_exists('field_group_field_ui_form_params')) {
    $field_group_params = field_group_field_ui_form_params($form, $display);
    foreach ($field_group_params->groups as $name => $group) {
      $parent_options[$name] = $group->label;
    }
    $parent_options['_add_new_group'] = t('Add new group');
  }
  foreach ($fields as $key => $field) {
    $configuration = array(
      'field' => $field,
      'field_name' => $key,
      'entity_type' => $entity_type,
      'bundle' => $bundle,
      'view_mode' => $view_mode,
    );

    // Check if we can display this field here.

    /* @var $plugin_instance DsFieldInterface */
    $plugin_instance = \Drupal::service('plugin.manager.ds')
      ->createInstance($field['plugin_id'], $configuration);
    if (!$plugin_instance
      ->isAllowed()) {
      continue;
    }

    // Don't filter out fields when $displays is empty.
    if (!empty($displays)) {
      $continue = TRUE;
      foreach ($displays as $limitation) {
        list($limit_bundle, $limit_view_mode) = explode('|', $limitation);
        if ($limit_bundle == '*' || $limit_bundle == $bundle) {
          if ($limit_view_mode == '*' || $limit_view_mode == $view_mode) {
            $continue = FALSE;
          }
        }
      }
      if ($continue) {
        continue;
      }
    }
    $form['#ds_fields'][] = $key;

    // Fetch saved plugin settings.
    $form_state_plugin_settings = $form_state
      ->get('plugin_settings');

    // Check on formatter settings.
    $plugin_settings = array();
    if (isset($form_state_plugin_settings[$key])) {
      $plugin_settings = $form_state_plugin_settings[$key];
    }
    elseif (isset($field_settings[$key]['settings']) || isset($field_settings[$key]['ft']) || isset($field_settings[$key]['ds_limit'])) {
      if (isset($field_settings[$key]['settings'])) {
        $plugin_settings = $field_settings[$key]['settings'];
      }
      if (isset($field_settings[$key]['ft'])) {
        $plugin_settings['ft'] = $field_settings[$key]['ft'];
      }
      if (isset($field_settings[$key]['ds_limit'])) {
        $plugin_settings['ds_limit'] = $field_settings[$key]['ds_limit'];
      }
      $form_state_plugin_settings[$key] = $plugin_settings;
    }
    $plugin_instance
      ->setConfiguration($plugin_settings);

    // Save fetched plugin settings.
    $form_state
      ->set('plugin_settings', $form_state_plugin_settings);
    $hidden = array(
      'hidden' => t('- Hidden -'),
    );

    // Get the formatters from the field instance.
    $formatters = $plugin_instance
      ->formatters();

    // This should be temporary. Don't want to copy stuff from the object to
    // the field each ajax refresh.
    if (!empty($formatters)) {
      $formatters = $hidden + $formatters;
    }
    else {
      $formatters = $hidden + array(
        'default' => t('Default'),
      );
    }
    $table[$key] = array(
      '#row_type' => 'field',
      '#js_settings' => array(
        'field',
      ),
      '#region_callback' => 'field_ui_display_overview_row_region',
      '#attributes' => array(
        'class' => array(
          'draggable',
          'tabledrag-leaf',
        ),
      ),
      'human_name' => array(
        '#plain_text' => $field['title'],
      ),
      'weight' => array(
        '#type' => 'textfield',
        '#default_value' => isset($field_settings[$key]['weight']) ? $field_settings[$key]['weight'] : 0,
        '#size' => 3,
        '#attributes' => array(
          'class' => array(
            'field-weight',
          ),
        ),
      ),
      'parent_wrapper' => array(
        'parent' => array(
          '#type' => 'select',
          '#empty_value' => '',
          '#options' => $parent_options,
          '#default_value' => isset($field_group_params->parents[$key]) ? $field_group_params->parents[$key] : '',
          '#attributes' => array(
            'class' => array(
              'field-parent',
            ),
          ),
          '#parents' => array(
            'fields',
            $key,
            'parent',
          ),
        ),
        'hidden_name' => array(
          '#type' => 'hidden',
          '#default_value' => $key,
          '#attributes' => array(
            'class' => array(
              'field-name',
            ),
          ),
        ),
      ),
      'label' => array(
        '#type' => 'select',
        '#options' => $field_label_options,
        '#default_value' => isset($field_settings[$key]['label']) ? $field_settings[$key]['label'] : 'hidden',
      ),
      'plugin' => array(
        'type' => array(
          '#type' => 'select',
          '#options' => $formatters,
          '#default_value' => isset($field_settings[$key]['formatter']) ? $field_settings[$key]['formatter'] : 'hidden',
          '#attributes' => array(
            'class' => array(
              'field-plugin-type',
            ),
          ),
        ),
      ),
      'settings_summary' => array(),
      'settings_edit' => array(),
    );
    if ($form_state
      ->get('plugin_settings_edit') == $key) {
      $table[$key]['settings_summary']['#attributes']['colspan'] = 2;
      $settings_form = ds_field_settings_form($plugin_instance, $form_state);
      ds_field_row_form_format_construct($table, $key, $settings_form, $form_state);
    }
    else {

      // After saving, the settings are updated here as well. First we create
      // the element for the table cell.
      $summary = ds_field_settings_summary($plugin_instance, $plugin_settings, $form_state);
      if (!empty($summary)) {
        $table[$key]['settings_summary'] = $summary;
        ds_field_row_form_format_summary_construct($table, $key, $form_state);
      }
    }
  }
}

/**
 * Alter the core field on the the Field UI form.
 *
 * @param array $form
 *   A collection of form properties.
 * @param FormStateInterface $form_state
 *   A collection of form_state properties.
 */
function _ds_field_ui_core_fields(array &$form, FormStateInterface $form_state) {
  $entity_type = $form['#entity_type'];
  $bundle = $form['#bundle'];

  /* @var \Drupal\Core\Entity\EntityFormInterface $entity_form */
  $entity_form = $form_state
    ->getFormObject();

  /* @var EntityViewDisplay $entity_display */
  $entity_display = $entity_form
    ->getEntity();

  // Gather type information.
  $instances = \Drupal::service('entity_field.manager')
    ->getFieldDefinitions($entity_type, $bundle);
  $table =& $form['fields'];

  // Get all persisted values for fields and plugin settings.
  $form_state_plugin_settings = $form_state
    ->get('plugin_settings');

  // Field rows.
  foreach ($instances as $key => $instance) {
    if ($instance instanceof FieldConfigInterface) {
      $settings = $entity_display
        ->getComponent($key);
      if (empty($settings)) {
        continue;
      }
      if (isset($form_state_plugin_settings[$key])) {
        $settings = array_merge($settings, $form_state_plugin_settings[$key]);
      }

      // Import field settings and merge with Field API settings.
      if (!isset($form_state_plugin_settings[$key])) {
        $form_state_plugin_settings[$key] = isset($settings['third_party_settings']['ds']) ? $settings['third_party_settings']['ds'] : array();
      }
      if ($form_state
        ->get('plugin_settings_edit') == $key) {
        $table[$key]['plugin']['settings_edit_form']['actions']['save_settings']['#validate'] = array(
          'ds_field_ui_fields_validate',
        );
        $table[$key]['plugin']['settings_edit_form']['actions']['cancel_settings']['#validate'] = array(
          'ds_field_ui_fields_validate',
        );
      }
      else {
        if (!empty($table[$key]['settings_summary'])) {
          ds_field_row_form_format_summary_construct($table, $key, $form_state);
        }
      }
    }
  }

  // Set updated plugin settings.
  $form_state
    ->set('plugin_settings', $form_state_plugin_settings);
}

/**
 * Helper function for building the formatter settings.
 */
function ds_field_row_form_format_construct(&$table, $key, $settings_form, FormStateInterface $form_state) {
  $build_info = $form_state
    ->getBuildInfo();
  $base_button = array(
    '#submit' => array(
      array(
        $build_info['callback_object'],
        'multistepSubmit',
      ),
    ),
    '#validate' => array(
      'ds_field_ui_fields_validate',
    ),
    '#ajax' => array(
      'callback' => array(
        $build_info['callback_object'],
        'multistepAjax',
      ),
      'wrapper' => 'field-display-overview-wrapper',
      'effect' => 'fade',
    ),
    '#field_name' => $key,
  );
  $table[$key]['plugin']['settings_edit'] = array(
    '#type' => 'container',
    '#attributes' => array(
      'class' => array(
        'field-plugin-settings-edit-form',
      ),
    ),
    '#parents' => array(
      'fields',
      $key,
      'settings_edit_form',
    ),
    '#weight' => -5,
    // Create a settings form where hooks can pick in.
    'settings' => $settings_form,
    'actions' => array(
      '#type' => 'actions',
      'save_settings' => $base_button + array(
        '#type' => 'submit',
        '#name' => $key . '_plugin_settings_update',
        '#value' => t('Update'),
        '#op' => 'update',
      ),
      'cancel_settings' => $base_button + array(
        '#type' => 'submit',
        '#name' => $key . '_plugin_settings_cancel',
        '#value' => t('Cancel'),
        '#op' => 'cancel',
        // Do not check errors for the 'Cancel' button.
        '#limit_validation_errors' => array(),
      ),
    ),
  );
  $table[$key]['#attributes']['class'][] = 'field-plugin-settings-editing';
  $table[$key]['plugin']['type']['#attributes']['class'] = array(
    'visually-hidden',
  );
}

/**
 * Helper function for formatter summary settings.
 */
function ds_field_row_form_format_summary_construct(&$table, $key, FormStateInterface $form_state) {
  $build_info = $form_state
    ->getBuildInfo();
  $base_button = array(
    '#submit' => array(
      array(
        $build_info['callback_object'],
        'multistepSubmit',
      ),
    ),
    '#ajax' => array(
      'callback' => array(
        $build_info['callback_object'],
        'multistepAjax',
      ),
      'wrapper' => 'field-display-overview-wrapper',
      'effect' => 'fade',
    ),
    '#field_name' => $key,
  );

  // Add the configure button.
  $table[$key]['settings_edit'] = $base_button + array(
    '#type' => 'image_button',
    '#name' => $key . '_plugin_settings_edit',
    '#src' => 'core/misc/icons/787878/cog.svg',
    '#attributes' => array(
      'class' => array(
        'field-plugin-settings-edit',
      ),
      'alt' => t('Edit'),
    ),
    '#op' => 'edit',
    // Do not check errors for the 'Edit' button, but make sure we get
    // the value of the 'plugin type' select.
    '#limit_validation_errors' => array(
      array(
        'fields',
        $key,
        'type',
      ),
    ),
    '#prefix' => '<div class="field-plugin-settings-edit-wrapper">',
    '#suffix' => '</div>',
  );
}

/**
 * Utility function to sort a multidimensional array by a value in a sub-array.
 *
 * @param array $a
 *   The array to sort.
 * @param string $subkey
 *   The subkey to sort by.
 *
 * @return array
 *   The sorted array.
 */
function _ds_sort_fields(array $a, $subkey) {
  $c = array();
  foreach ($a as $k => $v) {
    if (isset($v[$subkey])) {
      $b[$k] = $v[$subkey];
    }
  }
  asort($b);
  foreach ($b as $key => $val) {
    $c[$key] = $a[$key];
  }
  return $c;
}

Functions

Namesort descending Description
ds_field_row_form_format_construct Helper function for building the formatter settings.
ds_field_row_form_format_summary_construct Helper function for formatter summary settings.
ds_field_settings_form Creates a form for Display Suite fields.
ds_field_settings_summary Creates a summary for the field format configuration summary.
ds_field_ui_change_layout_submit Form submission handler for _ds_field_ui_table_layouts_preview().
ds_field_ui_create_vertical_tabs Create vertical tabs.
ds_field_ui_fields_layouts Adds the Display Suite fields and layouts to the form.
ds_field_ui_fields_save Save the field settings from the 'Manage display' screen.
ds_field_ui_fields_validate Form validation handler for _ds_field_ui_fields().
ds_field_ui_layouts_save Save the layout settings from the 'Manage display' screen.
ds_field_ui_layouts_validate Validate the layout settings on the Field UI.
ds_field_ui_layout_clone Clone a fields layout.
ds_field_ui_regions Add Regions to 'Manage fields' or 'Manage display' screen.
ds_field_ui_row_region Returns the region to which a row in the Field UI screen belongs.
ds_field_ui_table_layouts_preview_callback Ajax callback for _ds_field_ui_table_layouts_preview().
_ds_field_group_field_ui_fix_notices Add fake field group value in.
_ds_field_ui_core_fields Alter the core field on the the Field UI form.
_ds_field_ui_fields Add the fields to the Field UI form.
_ds_field_ui_table_layouts Add the layouts fieldset on the Field UI screen.
_ds_field_ui_table_layouts_preview Add the layout previews to the Field UI screen.
_ds_sort_fields Utility function to sort a multidimensional array by a value in a sub-array.