7

I have a content type with a field_maps whose type is Text (plain, long). I needed to change it to Text (plain).

So I've done this SQL statement:

ALTER TABLE node__field_maps MODIFY field_maps_value VARCHAR(200);

It seems that field_type has changed to VARCHAR(200), but there is still one more problem: On the content type and manage fields tabs, the field is still shown as Text (plain, long).

How do I change it to Text (plain)?

  • Do you have production data in the database? Because the easiest way is to delete the old field and install it as you like. – Eyal Jul 31 '16 at 12:24
  • 1
    @Hefi you can try my answer to a similar Q. You can always put your site in maintenance mode for a few secs/mins while you do it. Do a dry run on a test/dev server first. – No Sssweat Jul 31 '16 at 13:09
  • You should write an update hook to perform this task. Basically you will need to copy the data to a variable, delete the field install the new field and insert the data back. (All in the same update function) – Eyal Aug 1 '16 at 6:57
9

I have also get this kind of issue that change field type from one to another with existing data. So as @Eyal mentioned, we can write an update hook to

  1. export data from a field table to a variable
  2. remove fields of all bundles
  3. add new fields of all bundles
  4. restore data to field table

Here is the code example

use \Drupal\field\Entity\FieldStorageConfig;
use \Drupal\field\Entity\FieldConfig;

/**
 * Change node__field_maps from string_long to string type.
 */
function mymodule_update_8XXX() {
  $database = \Drupal::database();
  $table = 'node__field_maps';
  $entity_type = 'node';
  $field_name = 'field_maps';

  $field_storage = FieldStorageConfig::loadByName($entity_type, $field_name);

  if (is_null($field_storage)) {
    return;
  }

  $rows = NULL;

  if ($database->schema()->tableExists($table)) {
    // The table data to restore after the update is completed.
    $rows = $database->select($table, 'n')
      ->fields('n')
      ->execute()
      ->fetchAll();
  }

  $new_fields = array();

  // Use existing field config for new field.
  foreach ($field_storage->getBundles() as $bundle => $label) {
    $field = FieldConfig::loadByName($entity_type, $bundle, $field_name);
    $new_field = $field->toArray();
    $new_field['field_type'] = 'string';
    $new_field['settings'] = array();

    $new_fields[] = $new_field;
  }

  // Deleting field storage which will also delete bundles(fields).
  $new_field_storage = $field_storage->toArray();
  $new_field_storage['type'] = 'string';
  $new_field_storage['settings'] = array(
    'max_length' => 255,
    'is_ascii' => FALSE,
    'case_sensitive' => FALSE,
  );

  $field_storage->delete();

  // Purge field data now to allow new field and field_storage with same name
  // to be created. You may need to increase batch size.
  field_purge_batch(10);

  // Create new field storage.
  $new_field_storage = FieldStorageConfig::create($new_field_storage);
  $new_field_storage->save();

  // Create new fields.
  foreach ($new_fields as $new_field) {
    $new_field = FieldConfig::create($new_field);
    $new_field->save();
  }

  // Restore existing data in the same table.
  if (!is_null($rows)) {
    foreach ($rows as $row) {
      $database->insert($table)
        ->fields((array) $row)
        ->execute();
    }
  }

}

NOTE: Always backup DB and test code before running this code

Other thoughts In my case, we also have exported configures which means the field type and settings are also included in field_storage_config, field_config, entity_form_display, and entity_view_display config files. So we have to update config settings in those files as well. One easy way could be:

  • clone your website
  • delete the field and add a field with the same name again in field UI
  • export configures to use them in the repo
  • import configure after DB update and clear cache again

This is code is inspired by @drugan in the post https://www.drupal.org/node/2816859

  • 1
    Great code - thanks!! I got this to work for a similar field change. Be aware, the new field will be disabled in the form display.. I didn't think it worked at first but then realized it was just disabled. – wheelercreek Feb 12 '18 at 19:28
  • I have copy the content by doing copy table and rename field and table value . value now showing in the new fields and i have move content from plain text to number . Now i have set sorting according to number (integer) .its still showing according to plain text 10 than 2. whats the solution for this need your help? – Manmeet Khurana Jun 30 '18 at 8:02

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.