16

How does one remove a field from a node programmatically? I have a migration in hook_update_N that moves the contents from a a field into a custom table. After that migration, I want to remove the field in that same function.

Are there any field API's that cater removing fields?

Edit, Solution: Because the answers lack actual code, here is what I did to move fields from the $users into my own records and subsequently remove the field from the database;

function my_module_update_7005(&$sandbox) {
  $slice = 100;
  //Fetch users from database;
  if (!isset($sandbox['progress'])) {
    $sandbox['progress'] = 0;
    $sandbox['current_uid'] = 0;
    // We'll -1 to disregard the uid 0...
    $sandbox['max'] = db_query('SELECT COUNT(DISTINCT uid) FROM {users}')->fetchField() - 1;
  }
  if (empty($users)) {
    $sandbox["current_uid"] += $slice;
  }
  $users = db_select('users', 'u')
    ->fields('u', array('uid', 'name'))
    ->condition('uid', $sandbox['current_uid'], '>')
    ->range(0, $slice)
    ->orderBy('uid', 'ASC')
    ->execute();
  //Loop trough users;
  foreach ($users as $user) {
    $foo = new Foo();
    // Warning: drupal's fields return mixed values; e.g. NULL versus an int.
    $foo->debits = (int) $user->user()->field_credits["und"][0]["value"];
    $foo->save();

    $sandbox['progress']++;
    $sandbox['current_uid'] = $user->uid;
  }

  $sandbox['#finished'] = empty($sandbox['max']) ? 1 : ($sandbox['progress'] / $sandbox['max']);

  // Remove the field.
  field_delete_field("field_credits"); //note that the name for Foo is field_foo
  field_purge_batch($sandbox['max']+1);//Drupal seems to have an offbyone problem.
}

3 Answers 3

29

field_delete_field($field_name) will mark the $field_name for deletion on next cron run.

You could use field_purge_batch to do the deletion, if you don't want to do it on cron run.

EDIT: field_delete_field() should be used when you need to delete the field from other bundles as well. If you only wish to delete the field from a particular bundle you should use field_delete_instance() as mentioned by @Clive.

5
  • 4
    Careful, that will also remove the field from any other bundles it might be attached to :) Good to know about field_purge_batch though
    – Clive
    Commented Oct 9, 2012 at 12:34
  • @Clive: right, it will delete the field form all bundles. Thank you for correcting :) I've edited the answer.
    – AjitS
    Commented Oct 9, 2012 at 12:52
  • I did want to remove the field entirely, i.e. from all bundles. But the warning is good. Thanks.
    – berkes
    Commented Oct 9, 2012 at 13:53
  • 1
    field_delete_instance() is the way to go. Commented Sep 25, 2015 at 18:34
  • field_purge_batch() will actually only delete as many field items as the batch size that is passed to it. This may help when the field has only a few items, so that to completely get rid of the field instance, you don't need to wait for cron to clean it out. If you have a lot of values in the field, don't be tempted to increase the batch size too high (the "batch" in the name doesn't mean it will do any batching itself, it just means it does a single batch of as many items as you ask it to); you might end up running into PHP memory or time limits.
    – Eelke Blok
    Commented Aug 3, 2016 at 8:50
24

To remove a field from a particular bundle you can use field_delete_instance()

Marks a field instance and its data for deletion.

Example:

function my_module_update_7001() {
  if ($instance = field_info_instance('node', 'field_name', 'page'))  {
    field_delete_instance($instance, TRUE);
    field_purge_batch(1);
  }
}

To remove a field from the system completely, you can use field_delete_field()

Marks a field and its instances and data for deletion.

Example:

function my_module_update_7001() {
  field_delete_field('field_name');
  field_purge_batch(1);
}

The fields/instances are only marked for deletion, the data will actually be purged during subsequent cron runs. To purged it manually execute:

field_purge_batch(1);
6
  • 1
    While calling field_delete_field() and field_purge_batch() works, it keeps records in field_config_instance and field_config. Why is that?
    – berkes
    Commented Oct 9, 2012 at 13:46
  • I don't quite get why calling field_purge_batch with a value of 1 will get rid of all field data. If I understand the code correctly, it gets the field data for $batchsize entities and leaves it at that (i.e. no recursively calling the function, or anything); it would seem it is up to the caller to check if all data is gone and if not, keep calling the function. But maybe I'm fundamentally misunderstanding something.
    – Eelke Blok
    Commented Aug 3, 2016 at 7:48
  • Actually, this comment in field_ui.admin.inc goes a long way in explaining this: // Fields are purged on cron. However field module prevents disabling modules // when field types they provided are used in a field until it is fully // purged. In the case that a field has minimal or no content, a single call // to field_purge_batch() will remove it from the system. Call this with a // low batch limit to avoid administrators having to wait for cron runs when // removing instances that meet this criteria.
    – Eelke Blok
    Commented Aug 3, 2016 at 8:19
  • @Clive, I trust you're advice pretty much implicitly, but I can't get over how weird it looks to me to have a declaration in an if condition. Is that on purpose? I'm referring to $instance = field_info_instance('node', 'field_name', 'page'). Shouldn't it instead be $instance = field_info_instance('node', 'field_contact', 'job'); and then drop the if statement?
    – cdmo
    Commented Oct 11, 2017 at 19:13
  • 1
    @cdmo it's called "assignment in condition", and yeah it does have problems. But Drupal core uses it liberally, even in the latest version, so it has precedent at least. To be honest this was 5 years ago and I'm a bit wiser now, I either don't use it, or if for whatever reason I'm going to, I wrap the assignment (eg if ( ($foo = $bar) ) { so the intention is obvious and the potential for error is limited. The if statement itself is necessary because field_delete_instance doesn't check for null
    – Clive
    Commented Oct 11, 2017 at 19:19
5

To answer @berkes question:

field_delete_field() does mark the field for deletion, causing it to get purged on the next cron run. However it does leave data on field_config_instance regarding the dropped field. Running cron or field_purge_batch() will not remove this data from field_config_instance table, even if the deleted column is set to 1 for the field.

For me using field_delete_instance() followed by a field_purge_batch() for each purged field worked - instantly removing both the field from the database (without requiring cron), as well as purging the field_config_instance table of any field data (for the deleted field).

Here is the solution:

/**
 * Implements hook_uninstall().
 */
function hook_uninstall() {
  // Delete all fields for all xyz entity bundles.

  // Retrieve all bundles for an entity.
  $bundles = field_info_bundles('XYZ'); // The name of your entity type, for example, 'node'.
  foreach ($bundles as $bundle => $properties) {

    // Retrieve all the fields for a given bundle.
    $instances = field_info_instances('XYZ', $bundle);
    foreach ($instances as $instance) {
      field_delete_instance($instance, TRUE);
      field_purge_batch(1);
    }
  }
}

Do note the TRUE on field_delete_instance(), as it indicates that the Field API should perform cleanup operations.

1
  • How to use this code? I want to delete title field from a content type
    – Umair
    Commented Jan 11, 2017 at 2:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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