Deleting a field explicitly renames that field's tables and removes it from the Field UI. Deleting a content type, however, leaves sites with orphaned fields. These orphan fields can't be deleted from the UI, can't be reused in Field UI, and no new fields with the same machine-names can be created.

Comments

joe.murray’s picture

Option 1: When deleting a content type, check whether fields it uses are not used by other content types. If not, add message about deleting field(s) unused elsewhere in system in content type deletion confirmation message. If user agrees to delete content type, also delete fields. Pro: keeps system clean, allows user to set new content type and add existing field before deleting old content type and fields.

Option 2: Allow 'orphaned' fields to be included in new content types. Pro: it can be time consuming to set up a field, and this approach allows that effort not be lost. Likely best if combined with Option 3.

Option 3: Allow 'orphaned' fields to be deleted.

I tend towards Option 1.

damien tournoud’s picture

There are actually at least three issues here:

  • we delete the field instance but not the field itself if it doesn't have any instance left
  • the Field UI is using field_info_instances() so it doesn't see fields that have no instances
  • (supposing we fix the above) there is nothing to prevent you from re-creating a field or an instance that is being deleted
xmacinfo’s picture

Before changing the way content types detects and use fields, I guess we should upgrade the field list report (admin/reports/fields) to:

  1. Identify orphan fields: display “Orphaned field” in the Used In column.
  2. Add a Delete operation link: we could add an Operations column.

As a first step, that would at least let us identify quickly and possibly delete any orphaned field.

This would not solve all issues, though.

yched’s picture

The UI is oriented towards masking the separate concepts of fields and instances. You get fields, and they can be used in several places.
This has a couple drawbacks, but keeps the concepts simple to grasp and avoids duplicating CRUD notions on two different levels. I'd rather keep it that way.

The UI on purpose doesn't handle 'fields without instances'. Internally, once the last instance of a field is deleted, the field itself is deleted (field_ui_field_delete_form_submit()).

Content type deletion doesn't run through field UI, though, but through code - field_attach_delete_bundle().

IIRC hardcoding field deletion in field_delete_instance() was considered and turned down as too harsh. Right now it's up to the code calling field_delete_instance() to decide - in this case, field_attach_delete_bundle(). I guess we could provide some helper code to ease that task; possibly even an optional param for field_delete_instance(), possibly even defaulting to 'yes, delete field if orphaned'.

I'm not sure this qualifies as critical, BTW.

xmacinfo’s picture

This is critical since you can't create a new field using the same name as an orphaned field.

klausi’s picture

Priority: Critical » Normal

This is annoying and a little WTF, but does not break overall functionality, neither of the field system nor of Drupal itself.

gstokes’s picture

Same problem here I have filed name I wish to reuse but cant as its still held in Database. I made a mistake in the choosing the type of filed and wish to remove it. This seems like pretty obvious piece of functionality.

yched’s picture

@gstokes: let's not mix several things. This issue is about fields sticking around when a content type is disabled.
When a single field is deleted, it should currently be possible to create a new field with the same name straight on. If this doesn't work, please open a separate issue with a detailed description and steps to reproduce.

yched’s picture

Marked #944972: Filed name (exists but cannot be selected) as duplicate.

We need to fix this.
IIRC, my last thought on the subject was to add a $delete_field_too_if_last_instance param for field_delete_instance() - defaulting to TRUE.

nomonstersinme’s picture

Priority: Normal » Major

I would mark this critical but I don't want to step on any toes. This is a HUGE issue IMO because most people will not understand what they did wrong and spend hours trying to figure this out. Yes, you can create a new field with a new name but thats really not a good solution.

Additionally upon deleting a content type and not its fields I get php eval errors:

Notice: Undefined variable: field_type in eval() (line 2 of .../modules/php/php.module(75) : eval()'d code).
Notice: Undefined variable: node in eval() (line 2 of .../modules/php/php.module(75) : eval()'d code).
Notice: Trying to get property of non-object in eval() (line 2 of .../modules/php/php.module(75) : eval()'d code)

Everyone has done so much great work on D7 It would really be a shame if this didn't get fixed before a full release... :/

yched’s picture

Status: Active » Closed (duplicate)
knalstaaf’s picture

Nomonstersinme (#10): I think that issue may be php-module related: "Undefined variable: node in eval()" and "Trying to get property of non-object in eval()" error.

torinwalker’s picture

Can you guys suggest a temporary workaround? e.g. delete rows from some field_table, then drop the tables corresponding to the field_data_field_ and field_revision_field_, and any other relevant schema data? Just like the previous comments made, I've had some frustration setting up fields exactly the way I want - I'll create a field, then decide I want to change it's label or name only to find out it cannot be modified or changed. This is especially frustrating for the field values - if, as the warning suggests, once the data is created it cannot be changed, why present an editing field? I tried editing the data four or five times before I came to the realization that perhaps I wasn't doing anything wrong to edit the data, but that the data simply cannot be edited.... but that's another issue.

Right now, I want to re-use a field name without littering the database with previous instances of the field name (e.g. field_length_type, field_length_type2, field_length_type_3rd_times_a_charm, etc.), and the only way I can see doing this is to purge all relevant data from the database.

Thanks for any help.

Torin...

torinwalker’s picture

I figured it out. Thanks anyway.

Torin...

pixelsweatshop’s picture

Torin, can you share your workaround.

Can on just drop the orphaned table (and it's revision counterpart), or is the field registered somewhere else as well?

spyckedelic’s picture

I am still encountering this problem. No fix yet?

eidoscom’s picture

I has the same problem and solved. Here is my workaround:

I did it accessing directly to the database. You have to delete 2 tables, delete one insert and truncate one table for each orphan field in drupal 7.

  1. If my field names "myfield", you have to search 'field_data_field_myfield' and 'field_revision_field_myfield' tables and drop it.
  2. Then search for a insert in 'field_config' table where 'field_name' column is "myfield" and delete it
  3. All that you must do now is TRUNCATE the 'cache_field' table

This worked for me, hope this may help you ;)

eidoscom’s picture

For a core fields like "body" or "comments" you must search for an instance records on the database inside the 'field_config_instance' table. There you can find records referencing the custom fields too.

anavrin’s picture

Guys , this should be solved a long time ago ... At least just to prevent to allow deleting the content types if there are fields:
1. used in other content types (i belive that's the real reason why the fields are not deleted automatycally when we delete content type)
2. used only in the content type that we are trying to delete - with comunicate -> you have to first delete all custom fields in this conent type manually...

That would change the situation from bug to need improvement...(and I believe it's not a big task for author of the module responsible for this functionality ...)

regards,
Marcin

xmacinfo’s picture

If you feel that is issue as not been fixed in #915906: Deleting node type with only instance of a field leaves the field in a strange zombie state, please change the status to “active”.

IreOke’s picture

Ty so much, #17 works perfect for me, you saved my life!!!

svedova’s picture

Issue summary: View changes

Well I am using this code in a hook_cron:

function hook_cron() {
    // Delete orphan field data.
    $result = db_query("SELECT field_name FROM {field_config}");
    
    for ($i = 0; $i < $result->rowCount(); $i++)
    {
        $record = $result->fetchObject();
        $field  = $record->field_name;
    
        $res = db_query("DELETE f FROM {field_data_$field} f " .
                        "LEFT JOIN {node} n ON f.entity_id = n.nid " . 
                        "WHERE n.nid IS NULL AND entity_type = :type", array(':type' => 'node'));
        
        $rev = db_query("DELETE f FROM {field_revision_$field} f " .
                        "LEFT JOIN {node} n ON f.entity_id = n.nid " . 
                        "WHERE n.nid IS NULL AND entity_type = :type", array(':type' => 'node'));
        
        // print "Deleted {$res->rowCount()} rows from $field<br>";
    }
}

This works for me.

jpsalter’s picture

This cleaned out a lot of cruft for us

function delete_orphaned_tables() {

  $db_fields = array();
  $results = db_query("SHOW TABLES like 'field_data_%'");
  foreach($results as $result) {
    $table_name = current((array) $result);
    $db_fields[] = str_replace('field_data_','', $table_name);
  }
  
  $drupal_fields = array();
  $results = db_query('SELECT field_name FROM field_config');
  foreach($results as $result) {
    $drupal_fields[] = $result->field_name;
  }
  
  $orphans = array_diff($db_fields, $drupal_fields);
  
  foreach($orphans as $orphan) {
    $query = 'DROP TABLE IF EXISTS field_data_'. $orphan .', field_revision_'. $orphan;
    drupal_set_message($query);
    db_query($query); // Comment out this line out to test
  }
  
  db_query('TRUNCATE cache_field');
}

joelpittet’s picture

D8 version in case people are looking for comment #22:

function hook_cron() {
  // Clean up orphan fields.
  $entity_type_id = 'node';
  $database = \Drupal::database();
  $entity_manager = \Drupal::entityTypeManager();
  $table_mapping = $entity_manager->getStorage($entity_type_id)
    ->getTableMapping();

  $table_names = $table_mapping->getDedicatedTableNames();
  foreach ($table_names as $table_name) {
    $query = $database->select($table_name, 'f');
    $query->fields('f', ['entity_id']);
    $query->leftJoin('node', 'n', 'n.nid = f.entity_id');
    $query->isNull('n.nid');
    $orphan_ids = $query->execute()->fetchCol();
    if ($orphan_ids) {
      $database->delete($table_name)
        ->condition('entity_id', $orphan_ids, 'IN')
        ->execute();
    }
  }
}
Michael G’s picture

Module Rooms and all related modules, can't be deactivated or uninstalled because of an orphaned field.

rooms_booking_unit_options

Any suggestions?...