To migrate content into Drupal taxonomy terms, use the MigrateDestinationTerm class:

$term_options = MigrateDestinationTerm::options($language, $text_format);
$this->destination = new MigrateDestinationTerm('tags', $term_options);
$this->addFieldMapping('name', 'source_name');
...

The first argument is the bundle (vocabulary machine_name) you wish to migrate source content into.

Fields

tid - The Drupal term ID. Usually this will be unmapped - the tid will be automatically assigned when the term is created, and the map table will record the source key that generated this ID. You would map the tid when the system-of-record is DESTINATION (i.e., the purpose of your migration is updating existing terms rather than importing new terms). Note also, tids cannot be created on an initial migration. Drupal does not allow for specifying term ids upon creation. If this is tried then no error will be thrown, instead Migrate will say that everything updated just fine. However, no data will be inserted and you may need to manually truncate the migrate_map_[machine name] table. See http://drupal.org/node/1516244 for explanation.

name - The name of the term. If a term of the name (and in the same place in a hierarchical vocabulary) already exists, then the incoming term is mapped to the existing term.

description - The term description.

parent - The Drupal term ID of the term's parent, typically mapped using sourceMigration($this->machineName). Mutually exclusive with parent_name.

parent_name - The name of the term's parent. Mutually exclusive with parent.

format - The text format (e.g., 'Filtered HTML') associated with the description.

weight - The weight of the term (i.e., its default ordering in listings of terms).

Options

Language

The language option will be applied as the default language for any term fields which are language-dependent. If unspecified, it will default to LANGUAGE_NONE.

Text format

The text format (e.g., 'filtered_html') will be applied as the default text format for any term fields which take a format. If unspecified, the default for the field will be applied.

Allowed duplicated terms

By default this setting is set to false. If you import two (or more) terms with the same name, migrate will treat them as one term. From migrate point of view you will get one create and one update for same term.

If set to true, migrate will create two terms even if they have the same name. From migrate point of view you will get two creates.

For Migrate 2.6 add to MigrateDestinationTerm this option:
'allow_duplicate_terms' => TRUE

Advanced usage

The vocabulary passed to the MigrateDestinationTerm constructor can be overridden on a per-term basis by mapping vocabulary_machine_name:

  $this->addFieldMapping('vocabulary_machine_name', 'category_name');

See also Advanced field mapping for Migrate wizard UI help.

Comments

stevecowie’s picture

It's probably obvious but the override per term field mapping gets done in the constructor and assuming you've got the category_name as a vocabulary name from a previous version of Drupal as part of your source query, the category has to exist in the destination database. I guess it would be possible to call an extra method to check for the existence of the vocabulary and generate it if it didn't already exist. Also it wants the category's machine name as explained in this issue: http://drupal.org/node/1463356

dropfen’s picture

If anyone needs duplicate Terms (by name) he/she can add 'allow_duplicate_terms' to the term_options.

like this:

$term_options['allow_duplicate_terms'] = TRUE;
$this->destination = new MigrateDestinationTerm('tags', $term_options);

Otherwise your existing Terms will be replaced by the Term Name.
Thx.

chrisolof’s picture

One issue you may face when migrating in a hierarchical term tree is how to map the term parent when the parent term may or may not be imported yet.

One way to do this is to create two migrations: one for the terms themselves, and one for the hierarchical (parent-child) data.

To do this you map everything but the term parent in the first migration. Be sure to use the "allow_duplicate_terms" option in your destination in case you have multiple terms in different spots (depths) with the same name:

    $destination_options = array(
      'allow_duplicate_terms' => TRUE,
    );
    $this->destination = new MigrateDestinationTerm('categories', $destination_options);

Then, in your second migration, you'll be updating the existing terms by adding just their parent term ID. To tell migrate to only update this field on the existing terms we imported in the first migration, you'll need to set the system of record to the Drupal side of things (so you don't wipe out other fields/properties on the term) and map the tid using the first migration as the sourceMigration:

    $this->systemOfRecord = Migration::DESTINATION;
    $this->addFieldMapping('tid', 'source_term_id_here')
      ->sourceMigration('FirstMigrationNameHere');
    $this->addFieldMapping('parent', 'source_parent_column_name_here')
      ->sourceMigration('FirstMigrationNameHere')
      ->defaultValue(0);

It's also a good idea to make the second migration dependent on the first - since you need terms in there before you can arrange them in a hierarchy. See migrate_example.migrate.inc inside of the migrate module's migrate_example module for an example of how to set dependencies up for a migration.