2

I'm looking for a way to delete about 1300 taxonomy terms (of 5250 in total) and their association with nodes. I firstly thought to delete the content of these tables:

  • taxonomy_index
  • taxonomy_term_data
  • taxonomy_ter_field_data
  • taxonomy_term_hierarchy
  • node__field_tags
  • node_revision__field_tag

Is this sufficient?
Is there a better way to do it, without Drush, which I cannot install?

EDIT :

I'm trying to do it programmaticaly, but I have an error

Error: Call to undefined function field_attach_delete() in delete_taxonomy_terms() (line 42 of /var/www/html/d8/delete_tags.php).

Trying to add call to module_load_include() but still get the same error. I put the file at the root of my Drupal installation (../mydrupal/delete_tags.php).

<?php
error_reporting(E_ALL);
date_default_timezone_set('Europe/Paris');

define('DRUPAL_DIR', $_SERVER["DOCUMENT_ROOT"]); //__DIR__ ); //.'/../drupal');

use Drupal\Core\DrupalKernel;
use Symfony\Component\HttpFoundation\Request;

$autoloader = require_once 'autoload.php';
$kernel = new DrupalKernel('prod', $autoloader);
$request = Request::createFromGlobals();
$response = $kernel->handle($request);
$response->send();
$kernel->terminate($request, $response);

/**
 * Deletes taxonomy terms.
 *
 * @param array $tids
 *   Array of taxonomy term IDs.
 */

$tids = [830];

delete_taxonomy_terms($tids);

function delete_taxonomy_terms($tids) {

module_load_include("inc", "field", "field.attach");

  db_delete('taxonomy_term_data')
    ->condition('tid', $tids, 'IN')
    ->execute();
  db_delete('taxonomy_term_hierarchy')
    ->condition('tid', $tids, 'IN')
    ->execute();

  $terms = taxonomy_term_load_multiple($tids);

  foreach ($terms as $term) {
    field_attach_delete('taxonomy_term', $term);
    module_invoke_all('taxonomy_term_delete', $term);
    module_invoke_all('entity_delete', $term, 'taxonomy_term');
  }

  // Reset static cache after all terms deleted.
  taxonomy_terms_static_reset();
}
9
  • you got some advance? Aug 20, 2017 at 14:34
  • do yo need to clean the vocabulary or delete some ids? Aug 21, 2017 at 13:04
  • you're trying to execute Drupal 7 code in Drupal 8. field_attach_delete() is a Drupal 7 function and you want Drupal 8. See my answer, I tested the code and it works. Aug 21, 2017 at 13:09
  • yay, sorry i wasnt aware you were trying to use D8. Please see @AdrianCidAlmaguer post.
    – tenken
    Aug 21, 2017 at 15:16
  • @tenken in my fist post I write Drupal 7 code too, and after I see that is for Drupal 8, so I edit the answer. Aug 21, 2017 at 15:20

3 Answers 3

3

Before you clean the vocabulary you need to change the taxonomy reference field, to do this you can use this code:

$nids = \Drupal::entityQuery('node')->condition('type','YOUR_CONTENT_TYPE')->execute();
$nodes =  \Drupal\node\Entity\Node::loadMultiple($nids);

foreach($nodes as $node) {
  // Change your term here
  $node->field_YOUR_TAXONOMY_REFERENCE_FIELD->value = '';
 $node->save();
}

To clean the vocabulary use this modification of a drush command that you can see in https://github.com/adrian-cid/drush_commands/blob/master/drush_taxonomy.drush.inc

You need to pass an array of vocabularies names to clean.

I use the dpm() function (you need to install Devel) to show the messages, but you can change it if you want.

function taxonomy_vocabulary_clean(array $names) {
  if (!empty($names)) {
    // Check for duplicate ids.
    $test_names = array_unique($names);
    if (count($test_names) != count($names)) {
      dpm('You have duplicate vocabulary names.');
      return;
    }
    //Searching the vocabularies in the site
    $vocabulary_in_db = array_keys(Drupal\taxonomy\Entity\Vocabulary::loadMultiple());
    $vocabulary_non_existent = array_diff($names, $vocabulary_in_db);
    $vocabulary_existent = array_diff($names, $vocabulary_non_existent);

    if (count($vocabulary_existent) == 0) {
      dpm("The desired vocabulary to clean doesn't exists.");
      return;
    }
    if (count($vocabulary_non_existent)) {
      dpm('Non-existent vocabulary:');
      dpm(implode(' ', $vocabulary_non_existent));
    }

    foreach ($vocabulary_existent as $name) {
      $tids = \Drupal::entityQuery('taxonomy_term')
        ->condition('vid', $name)
        ->execute();

      $controller = \Drupal::entityTypeManager()->getStorage('taxonomy_term');
      $entities = $controller->loadMultiple($tids);
      $controller->delete($entities);
    }
    dpm('Vocabulary cleaned:');
    dpm(implode(' ', $vocabulary_existent));
  }
  else {
    dpm('You must enter at least one vocabulary name.');
  }
}

Using the function:

taxonomy_vocabulary_clean(['tags', 'my_vocabulary_machine_name']);

The Drupal 7 code:

function taxonomy_vocabulary_clean(array $names) {
  if (!empty($names)) {
    // Check for duplicate ids.
    $test_names = array_unique($names);
    if (count($test_names) != count($names)) {
      dpm('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) {
      dpm("The desired vocabulary to clean doesn't exists.");
      return;
    }
    if(count($vocabulary_non_existent)) {
      dpm('Non-existent vocabulary:');
      dpm(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);
      }
    }
    dpm('Vocabulary cleaned:');
    dpm(implode(' ', $vocabulary_existent));
  }
  else {
    dpm('You must enter at least one vocabulary name.');
  }
}
1

You can write a custom function let's say on some form submit and do something like this:

/**
 * Deletes taxonomy terms.
 *
 * @param array $tids
 *   Array of taxonomy term IDs.
 */
function delete_taxonomy_terms($tids) {
 // Required to use field_attach_delete. - @tenken
 module_load_include("inc", "field", "field.attach");

  db_delete('taxonomy_term_data')
    ->condition('tid', $tids, 'IN')
    ->execute();
  db_delete('taxonomy_term_hierarchy')
    ->condition('tid', $tids, 'IN')
    ->execute();

  $terms = taxonomy_term_load_multiple($tids);

  foreach ($terms as $term) {
    field_attach_delete('taxonomy_term', $term);
    module_invoke_all('taxonomy_term_delete', $term);
    module_invoke_all('entity_delete', $term, 'taxonomy_term');
  }

  // Reset static cache after all terms deleted.
  taxonomy_terms_static_reset();
}

of course it's better to write batch function but if it's one time operation you can try to do it simple (be aware that operation may be interrupted depends on your max_execution_time value).

4
  • 1
    As an additional suggestion a simple php script on the server calling this function should suffice so long as drupal 8 is bootstrapped at the top of the file. The cleanest example (untested) I can find to bootstrap D8 is from this tutorial allabouttodd.com/story/… then simply execute the script with php, no drush needed.
    – tenken
    Aug 17, 2017 at 19:56
  • Try to use your solution, combine with @tenken, but I get an error : Error: Call to undefined function field_attach_delete() in delete_taxonomy_terms()
    – Snabow
    Aug 18, 2017 at 9:10
  • You need add a line like module_load_include("inc", "field", "field.attach"); at the top of the function delete_taxonomy_terms because that function is apart of this modules included files. api.drupal.org/api/drupal/modules!field!field.attach.inc/…
    – tenken
    Aug 18, 2017 at 16:12
  • @tenken Still not working, error still the same. I add my code in my first post
    – Snabow
    Aug 21, 2017 at 12:38
0

If you have taxonomy manager module installed, you can mass delete by running this javascript line in the console, which triggers a click on all the items

jQuery(".fancytree-checkbox").each(function() { jQuery(this).trigger("click")} )

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.