Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
I'm trying to migrate taxonomy terms from d6 to d7 while keeping the tids form the d6 site (for path alias purposes)
Some tids of the d6 site already exist on the d7 site. Those get overwritten as expected, but no new terms are created:
I had 17 terms in the database before the migration. The migration tells me it migrated 60 terms, but there are still only 17 terms in the database, meaning it has only overwritten existing terms and not added new ones?
Here's the code:
public function __construct() {
parent::__construct();
$this->description = t('Migrate taxonomy terms');
$this->dependencies = array('TCCReizenUrl');
$query = db_select(TTC_MIGRATION_SOURCE_TABLE . '.term_data', 'td');
$query->fields('td', array('tid', 'vid', 'name', 'description', 'weight'));
$query->condition('vid', 2);
$query->join(TTC_MIGRATION_SOURCE_TABLE . '.term_hierarchy', 'th', 'th.tid = td.tid');
$query->addField('th', 'parent');
// Order by parent so no term can be created when the parent doesn't exist yet.
$query->orderBy('th.parent');
$this->source = new MigrateSourceSQL($query);
$this->destination = new MigrateDestinationTerm('reizen');
$this->map = new MigrateSQLMap($this->machineName,
array(
'tid' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'description' => 'Drupal 6 term ID',
'alias' => 'td',
)
),
MigrateDestinationTerm::getKeySchema()
);
$this->addSimpleMappings(array('tid', 'name', 'description', 'parent', 'weight'));
$this->addFieldMapping('format')->issueGroup(t('Do Not Migrate'));
$this->addFieldMapping('parent_name')->issueGroup(t('Do Not Migrate'));
$this->addFieldMapping('path')
->issueGroup(t('Do Not Migrate'))
->description(t('Since we mapped the entire url alias table, and tid\'s are mapped as well, we do not need to map aliases again'));
$this->addFieldMapping(NULL, 'vid');
}
public function preImport() {
parent::preImport();
if (!taxonomy_vocabulary_load_multiple(array(), array('machine_name' => 'reizen'))) {
// Create a vocabulary named "Reizen".
$description = "";
$help = "";
$vocabulary = (object) array(
'name' => 'Reizen',
'description' => $description,
'machine_name' => 'reizen',
'help' => $help,
'hierarchy'=> 2,
);
taxonomy_vocabulary_save($vocabulary);
}
}
Comments
Comment #1
Jelle_SEven when I add
to the constructor and delete all existing taxonomy terms before trying to import it still tries to update the terms:
Processed 60 (0 created, 60 updated, 0 failed, 0 ignored) in 10.3 sec (349/min) - done with 'TTCReizenTerm'
Comment #2
mikeryanThat's not going to work - Drupal (specifically taxonomy_term_save()) does not support creating terms with specified tids. I would highly recommend that rather than try to preserve the tids, you use Redirect, or some approach like that, to redirect your old URLs to the new one.
If you really must preserve tids, then you'll need to extend MigrateDestinationTerm, overriding import() to call your own rewritten version of taxonomy_term_save() that will allow writing terms with specific tids (look at how node_save() and user_save() use is_new to support this functionality).
Comment #3
kevinquillen CreditAttribution: kevinquillen commentedSo, is there no way to import terms in (not preserve IDs) to setup a vocabulary structure from an old system?
Comment #4
mikeryanYou can import a term hierarchy from another system, you just can't preserve the tids.
Comment #5
kevinquillen CreditAttribution: kevinquillen commentedGotcha. I wound up creating a CSV export from the old DB, and imported it with a mySQL admin to preserve keys. Repeated that for the hierarchy table.
Comment #6
apotek CreditAttribution: apotek commentedSince drupal puts terms from several vocabularies into the same term_data table, if you migrate a term with term id 123 from system A to system B, and system B already has an other vocabulary with term id 123, you'll clobber System B's other vocabulary.
What we've done to try to preserve identity of terms across distributed systems (though it won't help in your use case with URLs), is to use the UUID module so we can migrate a term into the correct vocabulary and placement in the hierarchy of that vocabulary without clobbering any other instance of an identically-named term.
Comment #7
Jelle_SI solved this by using the preImport function to insert dummy data with the term ids into the table (using the select query from the source table). Then when the migration is run it will update the data with the right data according to the term ids. A bit of a workaround but it works...
Comment #8
mikeryanThe upshot is, if you want to preserve term IDs, that's something you need to hack in yourself according to the specifics of your needs, it's not something Migrate will do for you.
Comment #10
nlisgo CreditAttribution: nlisgo commentedJust wanted to add my code that I am using to create stub terms if they don't exist already for that specific term id. The use case is valid for me because this is a new D7 site build so I know there are no terms with those tid's currently and the client wishes to preserve the tids for one vocabulary. Hope this is helpful for someone:
Comment #11
scor CreditAttribution: scor commentedI found that in some cases the table taxonomy_term_hierarchy needs to be populated as well. This is what I used (bearing in mind that I was importing terms into an empty site, so I could claim any tid):
I was running this in an implemention of hook_taxonomy_term_presave(), but this snippet should work too as part of a Migration class.
Comment #12
olafkarsten CreditAttribution: olafkarsten commented#10 works. Thanks for sharing this.
Comment #13
criznach CreditAttribution: criznach commentedKeeping the same term IDs can be useful if you're moving views around with features, because views taxonomy filters aren't aware of Migrate's mapping.
#10 worked for me, but I had to clear cache_entity_taxonomy_term after the migration, or I saw "Stub term: 123". Adding the following to my term migration class did the trick.
Comment #14
joelpittet#10 worked for me as well but I had to change
$this->termsQuery
which doesn't seem to exist anymore with$this->query()
And I'm using migrate_d2d as a base with DrupalTerm6Migration. Thanks @nlisgoComment #15
Summit CreditAttribution: Summit commentedHi, Will this also work with Migrate D-D somehow?
I need the same TID's because of other dependencies.
greetings, Martijn
Comment #16
apotek CreditAttribution: apotek commentedI'm looking over this long-standing thread again, and feel like maybe it might helpful to reiterate some things.
1. A tid is not primarily an id for a term. It is the row id of a database table. If you're lucky and only dealing with one database, by chance, the tid can also function as the term's unique id. But in a heterogenous environment, you can't. Which is why migrate doesn't support it natively. Doing so would cross concepts. A database row id can be used as an id *only* within the database that data is stored in. Outside of that, there is no guarantee of uniqueness or consistency. The taxonomy module never thought about moving terms between different databases. So the tid should never be used as a canonical or public facing piece of data.
2. If despite this, you want to preserve tids, you can hack around to accomplish this, and many good suggestions have been made here in the thread. But if you have more than one vocabulary from more than one database, you will probably have clashing tids.
3. If you are moving to D7, you have the option of implementing uuids as fields on the term entities, which is the what I would recommend at this point.
4. Bottom line is that if you can find any way to not have to preserve tids (either by using redirects, or uuids, etc etc), do it. Tids are not real unique identifiers for terms.
There is a sandbox project by spajennios creating the concept of a taxonomy server and taxonomy client module which, relying on uuids, can move terms between servers in transparent way. It's a really cool model.
https://www.drupal.org/project/2185537/git-instructions
https://www.drupal.org/project/2183673/git-instructions
Comment #17
simeAnother approach to #10
Comment #18
simeI think it's fine that there is no native support for maintaining terms, however solutions to this sort of stuff are so important - because if you're migrating a small Drupal site for a low budget, preserving IDs simply saves time and money. So many modules use IDs in configuration.
Comment #19
Anthony Robertson CreditAttribution: Anthony Robertson commentedThanks sime!
The solution you propose above (#17) was very helpful in my situation.
If you're using drush, it is worth noting that drush will report these as 'updates' rather than 'creates' because the tid is added to the table first.
Comment #20
wrg20 CreditAttribution: wrg20 commentedI got it to work using the proposed solution #10 and #14 but I had to do some modifications. I would appreciate any comments on this. This is my first attempt at modifying the migrate code and I needed to retain the tids.
I replaced the createStub function in the taxonomy.inc file within the migrate_d2d module with #10 then replaced the following line of code per comment #14. I also need to port this into my custom module.
After that, I had to add the following to my DrupalTerm7Migration class within my custom migrate_d2d module.
Comment #21
tommy.thomas CreditAttribution: tommy.thomas as a volunteer commentedI tried #10 + in the base DrupalTermMigration class (migrate_d2d/taxonomy.inc):
Changed
$this->addSimpleMappings(array(''name', 'description', 'weight'));
To
$this->addSimpleMappings(array('tid','name', 'description', 'weight'));
Mapping the tid in addSimpleMappings(). That seems to have worked.
Comment #22
hellolindsay CreditAttribution: hellolindsay commentedInspired by #7, I used the prepare() function to create stub terms like this:
After adding this, my terms imported properly and tids where preserved.