I have a large vocabulary, and admin views does not yet work for taxonomy. Taxonomy Manager does not do this as well.
Are there other options for bulk-deleting taxonomy terms?
I have a large vocabulary, and admin views does not yet work for taxonomy. Taxonomy Manager does not do this as well.
Are there other options for bulk-deleting taxonomy terms?
Taxonomy manager does have bulk delete functionality, just select all the terms in your vocabulary and click the 'Delete' button:
If you want to do it using code something like the following should help:
$vocabulary = taxonomy_vocabulary_machine_name_load('my_custom_vocabulary');
foreach (taxonomy_get_tree($vocabulary->vid) as $term) {
taxonomy_term_delete($term->tid);
}
A favorite method of bulk-deleting content by content type, taxonomy vocabulary, etc utilizes the http://drupal.org/project/devel module. For deleting all terms in a vocabulary:
Voila-- empty vocabulary, otherwise untouched.
Untested; use for inspiration and test:
<?php
$vid = 17;
$tree = taxonomy_get_tree($vid);
if (count($tree) == 0) {
print "Nothing to delete.\n";
}
else {
$tree = array_slice($tree, 0, 1000);
foreach ($tree as $term) {
print 'Deleting tid ' . $term->tid . "\n";
taxonomy_term_delete($term->tid);
}
}
Put this in its own file, and execute as
drush -u 1 scr nuke_vid_18.php
Keep running it until it doesn't show anything as deleted. The array_slice
is there to limit things so you don't run out of memory. You can potentially save some memory by querying directly, but taxonomy_get_tree()
isn't terribly inefficient as long as you aren't doing full term loads.
Backup your database with drush sql-dump
as a precaution before you do anything like this.
You can use the following command.
drush -v eval 'foreach(taxonomy_get_tree(123) as $term) { taxonomy_term_delete($term->tid); }'
If it doesn't work, make sure that you clear your cache (e.g. memcached).
A faster way is using the following dirty SQL query, where 123 is the ID of the vocabulary you should change.
drush sqlq "DELETE FROM taxonomy_term_data WHERE vid = 123"
You can get the vid from the vocabulary name with the following command.
drush sqlq "SELECT name, vid FROM taxonomy_vocabulary WHERE name = 'vocabulary_name'"
I've these modules: Drush and Devel For exclude all terms of taxonomy, use the generate-terms command:
drush generate-terms you_vocabulary_name 0 --kill
Change your_vocabulary_name to name of vocabulary you need delete terms
On Drupal 8 and 9 with Drush, just run :
drush entity:delete taxonomy_term --bundle=VOCABULARY_ID
Replace VOCABULARY_ID with the vocabulary machine name.
Admin views just provides preconfigured VBO views.
VBO itself works fine with terms (or any other entity type). Install VBO, create the view that you want, then use VBO to delete the terms.
You can also use the Taxonomy Multi-delete Terms module to delete taxonomy terms.
This module makes it possible to delete multiple terms at one time. You need to select terms and click on delete button. All selected terms will be deleted. You can also delete all terms at one time.
The module has been developed for Drupal 7 and Drupal 8. It's also covered by the security advisory policy.
To bulk delete all taxonomy terms within a vocabulary in Drupal 7, use taxonomy_term_delete()
and loop through all terms.
Consider the following example.
// Get metadata about the vocabulary from its machine name.
$vocab = taxonomy_vocabulary_machine_name_load('TAXONOMY_MACHINE_NAME');
// Get a hierarchical representation of all terms.
$terms = taxonomy_get_tree($vocab->vid);
// Loop through all terms in the taxonomy, deleting each one.
if (!empty($terms)) {
foreach ($terms as $term) {
taxonomy_term_delete($term->tid);
}
}
Even easier, if you have Drush and the Devel module installed, you can use the following command to bulk delete all terms in a taxonomy* from the comfort of your shell.
drush generate-terms TAXONOMY_MACHINE_NAME 0 --kill
This assumes you have the Devel Generate module enabled, which can be installed with drush en -y devel && drush en -y devel_generate
.
I’m using the jQuery Easy Confirm Dialog plugin for this. First download the library from here and put this in your themes js folder.
We can then add a “Delete All Terms” button with a little code in a custom module:
function hook_form_alter(&$form, &$form_state, $form_id) {
switch($form_id) {
case 'taxonomy_overview_terms':
if($form['#total_entries']) {
drupal_add_library('system', 'ui.dialog');
drupal_add_js(drupal_get_path('theme', 'YOUR_THEME_NAME').'/js/jquery.easy-confirm-dialog.js');
$js = 'jQuery(document).ready(function($){$(".confirm").easyconfirm({locale: { title: \'Delete all '.$form['#vocabulary']->name.' terms\', button: [\'No\',\'Yes\']}});});';
drupal_add_js($js, array('type'=>'inline'));
$form['actions']['delete_all'] = array(
'#markup' => '<a href="/admin/structure/taxonomy/'.$form['#vocabulary']->vid.'/delete-all" class="button confirm" title="Are you sure you want to delete all terms from the '.$form['#vocabulary']->name.' vocabulary?">Delete All Terms</a>',
'#weight' => 10,
'#attributes' => array('class' => array('button'))
);
}
break;
}
}
Now we need to define the path to our function to delete the terms:
function hook_menu() {
$items = array();
$items['admin/structure/taxonomy/%/delete-all'] = array(
'title' => 'Delete all taxonomy terms',
'type' => MENU_CALLBACK,
'page callback' => 'delete_all_taxonomy_terms',
'page arguments' => array(3),
'access arguments' => array('administer taxonomy'),
);
return $items;
}
And finally add the functionality to actually delete the terms:
function delete_all_taxonomy_terms($vid) {
$vocabulary = taxonomy_vocabulary_load($vid);
$query = new EntityFieldQuery();
$result = $query
->entityCondition('entity_type', 'taxonomy_term')
->propertyCondition('vid', $vid)
->execute();
foreach($result['taxonomy_term'] as $term) {
taxonomy_term_delete($term->tid);
}
drupal_set_message('All terms have been deleted from the '.$vocabulary->name.' vocabulary');
drupal_goto('admin/structure/taxonomy/'.$vocabulary->machine_name);
}
I would recommend using Admin Views with VBO to get a view to replace the default display of Taxonomy terms.
What you have to do is the following:
In addition to @mpdonadio code, I just added the snippet to load vid by the vocabulary's name. I hope it might help someone to save time.
$voca = "forums";
$vobj=taxonomy_vocabulary_machine_name_load("forums");
$vid = $vobj->vid;
$tree = taxonomy_get_tree($vid);
if (count($tree) == 0) {
print "Nothing to delete.\n";
}
else {
$tree = array_slice($tree, 0, 1000);
foreach ($tree as $term) {
print 'Deleting tid ' . $term->tid . "\n";
taxonomy_term_delete($term->tid);
}
}
Assuming Entity API is installed we can use entity_delete_multiple which should be faster than deleting one every time.
define("MY_VOCAB", "tags");
function _custom_zap_vocab() {
$vocab = taxonomy_vocabulary_machine_name_load(MY_VOCAB);
$tree = taxonomy_get_tree($vocab->vid);
$tids = array_map(function($term){
return $term->tid;
}, $tree);
entity_delete_multiple('taxonomy_term', $tids);
}
With Drupal 8 and Drush, just run a command like the following one.
drush php-eval 'foreach (Drupal::entityTypeManager()->getStorage("taxonomy_term")->loadByProperties(["vid" => ["department", "region"]]) as $c) {$c->delete();}'
In this example, I delete all terms in two vocabularies: department and region.
My answer is tangentially-related to the original question. Building on kenorb's answer, if you wish to clean ALL vocabularies at your site, you can run the following:
drush -v eval '$vocabularies = taxonomy_get_vocabularies(); foreach($vocabularies as $vocabulary) { foreach(taxonomy_get_tree($vocabulary->vid) as $term) { taxonomy_term_delete($term->tid);}}'
You can create a drush command named vocabulary-clean
. Create a module named drush_taxonomy
, inside the drush_taxonomy.drush.inc
file put this code:
<?php
/**
* @file
* Drush commands related to taxonomy.
*/
/**
* Implements hook_drush_command().
*/
function drush_taxonomy_drush_command() {
$items['vocabulary-clean'] = array(
'description' => dt("Delete all terms in a vocabulary."),
'aliases' => array('vc'),
'arguments' => array(
'name' => dt('The vocabulary names to clean.'),
),
'examples' => array(
'drush vocabulary-clean tags' => dt('Delete all the terms in tags vocabulary'),
'drush vocabulary-clean tags test' => dt('Delete all the terms in tags and test vocabularies'),
),
);
return $items;
}
/**
* Callback for the vocabulary clean command.
*/
function drush_drush_taxonomy_vocabulary_clean() {
$names = func_get_args();
if (!empty($names)) {
// Check for duplicate ids.
$test_names = array_unique($names);
if (count($test_names) != count($names)) {
drush_set_error('DRUSH_VOCABULARY_CLEAN_ERROR', dt('You have duplicate vocabulary names.'));
return;
}
//Searching the vocabularies in the site
$vocabulary_in_db = array_column(taxonomy_get_vocabularies(), 'machine_name');
$vocabulary_non_existent = array_diff($names, $vocabulary_in_db);
$vocabulary_existent = array_diff($names, $vocabulary_non_existent);
if(count($vocabulary_existent) == 0) {
drush_set_error('DRUSH_VOCABULARY_CLEAN_ERROR', dt("The desired vocabularies to clean doesn't exists."));
return;
}
if(count($vocabulary_non_existent)) {
drush_print(dt("Non-existent vocabularies:"));
drush_print(implode(' ', $vocabulary_non_existent));
}
foreach ($vocabulary_existent as $name) {
$vid = taxonomy_vocabulary_machine_name_load($name)->vid;
foreach(taxonomy_get_tree($vid) as $term) {
taxonomy_term_delete($term->tid);
}
}
drush_print(dt("Vocabularies cleaned:"));
drush_print(implode(' ', $vocabulary_existent));
}
else {
drush_set_error('DRUSH_VOCABULARY_CLEAN_ERROR', dt("You must enter at least one vocabulary name."));
}
}
Install the module, run drush cc drush
to clear the drush cache and use the command like this:
drush vc tags
or
drush vocabulary-clean tags
If you want add another alias to the command add elements to the aliases array like this:
'aliases' => array('vc', 'voc-clean', 'clean'),
And you can use this commands:
drush vc tags
drush voc-clean tags
drush clean tags
Always the output will be:
Vocabularies cleaned:
tags
Today, it is also easy to do this with Drupal Console. For example, to
delete all the taxonomy terms from the Tags vocabulary, it's sufficient to run drupal taxonomy:term:delete tags
.
As was said by @texas_bronius, if you have devel generate enabled, you can use that but taking it one step further, if you also have Drush installed, I would use drush generate-terms [vocabulary_machine_name] 0 --kill
.
Replace [vocabulary_machine_name] with the machine name of the vocabulary to delete. 0
is the number of taxonomy terms to add and --kill
is to remove the existing taxonomy terms.
Just to complete the answers, there is a module doing exactly this: the Taxonomy delete all terms module. I have used it and it works.
For sites with very large Taxonomy vocabularies, deleting vocabularies may become impossible due to the term deletion request timing out. When that happens before the deletion transaction is complete, the transaction is rolled back, causing no terms at all to be deleted.
The module isn't covered by by the security advisory policy, and it has only a development snapshot for Drupal 7. There aren't branches/releases for Drupal 8 or 9.
Today, within Drupal 8|9, taxonomy_bulk_actions contrib module can do that for you.
In Drupal 8+ you can use this:
* Delete terms of chosen vocabulary.
*
* @param string $vocabulary
* Machine name of the vocabulary.
*
* @command module_name:delete-terms-of
* @aliases delete-terms-of
*/
public function deleteChosenTerms(string $vocabulary) {
try {
$taxonomy_storage = $this->entityTypeManager->getStorage('taxonomy_term');
$terms = $taxonomy_storage->loadByProperties(['vid' => $vocabulary]);
if (!empty($terms)) {
foreach ($terms as $term) {
$term->delete();
}
}
}
catch (InvalidPluginDefinitionException | PluginNotFoundException | EntityStorageException $e) {
$this->loggerFactory->error($e->getMessage());
}
}
Then you can run drush
command e.g: drush delete-terms-of taxonomy_name