I want to migrate a text field to taxonomy reference field( the Tags one).

I've 1200 nodes having a field "Organization name". Those creating the content are making mistakes like misspelled company names. I'm using the company name in the views to find all related nodes.

This will help those entering can simply choose the company names or if someone has entered IBM for International Business Machines then I can merge those terms when using taxonomy reference field.

Should I go and create a vocabulary, add all existing values as terms in vocabulary then programmatically assign the text field values to the taxonomy reference field? Then delete the text field and change references in the views etc.

4 Answers 4


I would:

  • Go thorough all values, grouping them by their Levenshtein distance from each other.
  • For all set of similar names, I would choose canonical one, and put them in taxonomy as a term.
  • Using Computed Field or VBO I would choose the Levenshtein closest term for each node.

Details of implementation would need a bit of polishing, but that's my general approach. Apparently you can use Views Bulk Operations both to create taxonomy terms and to set field's value on node.


niccottrell on Drupal.org provided another solution:

Below donor is a source field, receptor is a taxonomy field. Loop over your nodes, possibly using Batch API, and for each invoke code like this:

$vid = 25; // vocab ID
$edit = array('vid' => $vid, 'name' => $object->field_donor[$object->language][0]['value']);
$terms = taxonomy_get_term_by_name($edit['name']);
if (!empty($terms)) {
  // term already exists
  $first_item = array_shift($terms);
  $tid = $first_item->tid;
else {
  // add term and get the tid
  $status = taxonomy_term_save($edit);
  $tid = $edit['tid'];
$object->field_receptor[$object->language][0]['tid'] = $tid;
  • Wow two answers from you!
    – AgA
    Jun 19, 2013 at 12:17
  • @AgA Two different points of view, two different approaches. This one is fast and to the bone, second one is about automating it as much as possible and using tools. I think these two deserve separate evaluation.
    – Mołot
    Jun 19, 2013 at 12:20

The code that which I wrote in migration_brand_type.inc file. This is a file which would create a mapping table for for the text field on the legacy database and Taxonomy on Our Drupal Database.

class MigrationBrandType extends Migration {
  public function __construct() {

    $this->description = t('Migrate languages from the source database to taxonomy terms');

    $this->map = new MigrateSQLMap($this->machineName,
        'productbrand' => array('type' => 'varchar', // Name of the field which you wish to migrate
        'length' => 255,
        'description' => 'Taxonomy Migration of brand',
    $query = Database::getConnection('default', 'legacy') // Legacy was the name of the database of mine.
      ->select('names', 'names') // Names was the name of the column from the legacy database from which I was fetching text values.
      ->fields('names', array('productbrand'))
      ->condition('productbrand', 'NULL', '!=');

    // Create a MigrateSource object, which manages retrieving  the input data.   
      $this->source = new MigrateSourceSQL($query, array(), NULL, array('map_joinable' => FALSE));

    // Set up our destination - terms in the migrate_example_beer_styles vocabulary
    $this->destination = new MigrateDestinationTerm('brands'); // Name of the vocabulary in which I was saying the text values.
    $this->addFieldMapping('name', 'productbrand');


While creating the field mapping for creating the relationship we do something like:

    $this->addFieldMapping('field_brand_type', 'productbrand')
     ->arguments(array('source_type' => 'tid'));

First, we migrate all the Text to the respective vocabulary and thwn we start the migration of content.


Using the example/suggestion @Molot posted, I created a batch process and packaged it as a module. Thought I would share.

First, create your taxonomy terms and add your entity reference field to your content type, then create and enable your batch module. Be sure to update the **FIELDS** below.

 * Implements hook_menu().

// Lets add a menu link to initiate the batch process
function convert_field_to_taxonomy_menu() {
    $items = array();
    $items['admin/batch'] = array(
        'title' => 'Convert to Tax Batch',
        'description' => 'Run batch operations.',
        'page callback' => 'drupal_get_form',
        'page arguments' => array('convert_field_to_taxonomy_form'),
        'access arguments' => array('administer site configuration'),
        'type' => MENU_NORMAL_ITEM,
    return $items;
// And a button to click
function convert_field_to_taxonomy_form() {
    $form = array();
    $form['submit'] = array('#type' => 'submit', '#value' => t('Click here to Start'));
    return $form;

function convert_field_to_taxonomy_form_submit($form, $form_state) {

function convert_field_to_taxonomy_setup_batch() {
    drupal_set_message('Updating Nodes');
    // load all the nodes from content type
    $nodes = node_load_multiple(array(), array('type' => "**CONTENT_TYPE**"));
    $node_count = count($nodes);

    // build the list of operation functions and function arguments
    foreach($nodes as $nid => $node) {
        // $operations[] = array(<function name>, <array of arguments to pass to function>);
        $operations[] = array('convert_field_to_taxonomy_method', array($node));

    //put all that information into our batch array
    $batch = array(
        'operations' => $operations,
        'title' => t('Convert to Tax Batch'),
        'init_message' => t('Initializing...'),
        'error_message' => t('An error occurred'),
        'progress_message' => t('Operation @current out of @total.'),
        'finished' => 'convert_field_to_taxonomy_finished_method'
    return $batch;

function convert_field_to_taxonomy_method($node, &$context) {
    $context['results'][] = $node->nid.
    ' : '.check_plain($node->title);
    // Optional message displayed under the progressbar.
    $context['message'] = t('Processing snapshot "@title"', array('@title' => $node->title));

    $vid = 38; // vocab ID
    $edit = array('vid' => $vid, 'name' => $node->**SOURCE_FIELD**['und'][0]['value']);
    $terms = taxonomy_get_term_by_name($edit['name']);
    if (!empty($terms)) {
        // term already exists
        $first_item = array_shift($terms);
        $tid = $first_item->tid;
    } else {
        // add term and get the tid
        $status = taxonomy_term_save($edit);
        $tid = $edit['tid'];

    $node->**TARGET_FIELD**['und'][0]['target_id'] = $tid;
    $path = drupal_lookup_path("alias", "node/".$node->nid);
    drupal_set_message("<a href='/$path'>".$node->title.
        "</a> updated.");

function convert_field_to_taxonomy_finished_method($success, $results, $operations) {
    if ($success) {
        // Here we could do something meaningful with the results.
        // We just display the number of data we processed...
        drupal_set_message(t('@count terms processed.', array('@count' => count($results))));
    } else {
        // An error occurred.
        // $operations contains the operations that remained unprocessed.
        $error_operation = reset($operations);
        drupal_set_message(t('An error occurred while processing @operation with arguments : @args', array('@operation' => $error_operation[0], '@args' => print_r($error_operation[0], TRUE))));

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.