Drupal 7: Setting Default Value For A Field

I was recently working on a module that contained a content type as a feature. When the module was enabled the hook_install() hook set up a collection of taxonomy terms which were used within the content type as a field. Whilst testing this out I realised that although the terms were installed correctly the default value of the field changed depending on which system the module was installed on. The reason for this was that the term ID was being used to pull out the default term from the database, which is the normal behaviour in Drupal. The problem here was that if a term the ID of the term was different (because one had been added) then this had a knock-on effect of changing the default value of the field.

To get around this I needed a way of setting the default value of the field based on a given taxonomy term. After some research and reading of the Drupal source code I found a way to programmatically set the default value of a taxonomy field.

Before getting into that there is a little bit of setup to do beforehand. As I said before, the module I was working on contained a feature that held a content type and a few fields, one of which was a taxonomy reference. In order to set a default value on a taxonomy field on a content type I needed to ensure that all of the components are correctly assembled first. In the hook_install() hook of the module I added a call to features_revert() so that I could be sure that the rest of the actions I was about to complete would work correctly. The features_revert() function works like clicking the 'Revert Features' button in the features module administration section and will force the given arguments to be reverted. In order for this to work during the install hook the correct feature files also need to be included and so the start of the hook includes the features files involved with nodes, fields and taxonomies.

function my_module_install() {
  // Ensure the correct features files are included
  module_load_include('inc', 'my_module', 'my_module.features');
  module_load_include('inc', 'my_module', 'my_module.features.field');
  module_load_include('inc', 'my_module', 'my_module.features.taxonomy');

  // Ensure that the content type, fields and taxonomy vocabularies are actually there.
  features_revert(
    array(
      'my_module' => array(
        'taxonomy',
        'node',
        'field'
      )
    )
  );
}

As a side note it may have been better to run this code in a different hook (e.g., hook_enable() or hook_modules_enabled()) so that the features_revert() function isn't needed. I have found, however, that you can't rely on features being fully implemented in any of the installing and enabling hooks. Forcing just the components you need to use in a feature is a good way of ensuring that everything you need is ready to go.

The next step was to load the vocabulary and add the default terms to it. The following code adds six terms to the vocabulary called 'task_status', which is also included in the install hook.

// Set up 'Status' vocabulary terms.
$task_status_vocab = taxonomy_vocabulary_machine_name_load('task_status');
$statuses = array(
  'New',
  'Being Worked On',
  'Postponed',
  'Failed QA/Testing',
  'Cancelled',
  'Ready For QA/Testing'
);
foreach ($statuses as $status) {
  $term = new stdClass();
  $term->name = $status;
  $term->vid = $task_status_vocab->vid;
  taxonomy_term_save($term);
}

Now that everything is set up the default field value can be set. What we need to do first is to run a database query to pick out the correct term so that we can set the taxonomy field to the correct value.

// Get the tid for the default status
$term = db_select('taxonomy_term_data', 'td')
  ->fields('td', array('tid', 'name'))
  ->condition('name', 'New')
  ->condition('vid', $task_status_vocab->vid)
  ->execute()
  ->fetchObject();

Now we need to take the term ID we just found and set it to be the default for the field, which involves three steps. The first step is to get an instance of the field using the function field_read_instance() that we can modify. The second step is to then modify the field with the new default value of the taxonomy term ID (referred to as tid). The final step is to update the field instance with the new field information using the field_update_instance() function.

// Set the default taxonomy term for the taxonomy field.

// Get an instance of the field that we can modify
$instance = field_read_instance('node', 'field_task_status', 'task');

// Update the default value of the field
$instance['default_value'] = array(array('tid' => $term->tid));

// Save the field back to the database.
field_update_instance($instance);

The only problem here is that once the default value has been updated the Feature will report itself as being overridden (which it is). This is unavoidable, but it's not something that will cause many problems. The one main problem is that if you ever need to revert the fields components of the feature again in the future then you'll need a way of updating the field with the correct default value. Even without Features this is a good trick to know for any fields.

Comments

Great post. I would like to use this to set the default valued based on a global variable (that I defined using the Variable module). My client "editor" user is able to set this variable through the admin, and I would like to set the default value of certain taxonomy term reference fields based on that. My problem is when to do it. Do you have any idea which hook I could use?
Permalink

Add new comment

The content of this field is kept private and will not be shown publicly.
CAPTCHA
4 + 1 =
Solve this simple math problem and enter the result. E.g. for 1+3, enter 4.
This question is for testing whether or not you are a human visitor and to prevent automated spam submissions.