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();
}
  • you got some advance? – Adrian Cid Almaguer Aug 20 '17 at 14:34
  • do yo need to clean the vocabulary or delete some ids? – Adrian Cid Almaguer Aug 21 '17 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. – Adrian Cid Almaguer Aug 21 '17 at 13:09
  • yay, sorry i wasnt aware you were trying to use D8. Please see @AdrianCidAlmaguer post. – tenken Aug 21 '17 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. – Adrian Cid Almaguer Aug 21 '17 at 15:20
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).

  • 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 '17 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 '17 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 '17 at 16:12
  • @tenken Still not working, error still the same. I add my code in my first post – Snabow Aug 21 '17 at 12:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.