Prevent deletion of taxonomy term if associated with a node

Parent Feed: 

Why check if term is associated to a node prior to deletion?

In cases where taxonomy terms are used only for categorizing content on a Drupal powered web page, there should be no harm in deleting them. However sometimes taxonomy is used to store terms critical to the content they are referenced from and in this case steps should be taken to prevent an accidental deletion.

I have encountered such a case on a project I am working on which is soon to become a web platform for university students. When creating a faculty node, its name is being defined by choosing a term from the 'faculties' vocabulary. Deleting a term assigned to such a faculty node would lead to... well undesired effects.

Approach

When looking for the right hook you will find that there is no hook_taxonomy_pre_delete and using the existing hook_taxonomy_term_delete would be too late (the term would be deleted by then). (By the way, this problem persists across other entity types, like nodes - hoping to see some added hooks in D8.)

I will describe an easy way of preventing the deletion of a used taxonomy term, but be warned, this will only prevent the deletion of a term in the UI, it will not react to programmatically deleted terms.

Here is how this is going to look like:

Taxonomy term delete warning.

Some code:


  1. // In our custom module 'mymodule' let's go ahead and implement hook_form_alter() (what else!?) and switch on $form_id.

  2. function mymodule_form_alter(&$form, &$form_state, $form_id) {

  3. switch ($form_id) {

  4. // This is the general term form.

  5. case 'taxonomy_form_term':

  6. // Checking if we are on the delete confirmation form.

  7. if (isset($form['delete'])) {
  8. // Getting the term id.

  9. $tid = $form['#term']->tid;

  10. // Limiting the query to 30 to save resources when loading the nodes later on.

  11. $limit = 30;

  12. // Getting node ids referencing this term and setting a limit.

  13. $result = taxonomy_select_nodes($tid, FALSE, $limit);

  14. if (count($result) > 0) {
  15. $markup = t('This term is being used in nodes and cannot be deleted. Please remove this taxonomy term from the following nodes first:') . '<ul>';

  16. // Looping through the node ids, loading nodes to get their names and urls.

  17. foreach($result as $nid) {

  18. $node = node_load($nid); // This is quite resource hungry, so if dealing with loads of nodes, make sure you apply a limit in taxonomy_select_nodes().

  19. if (!$node)

  20. continue;

  21. $markup .= '<li>' . l($node->title, 'node/' . $node->nid, array('attributes' => array('target'=>'_blank'))) . '</li>';
  22. }

  23. // Appending some text with ellipsis at the end of list in case there might be more nodes referencing this term than the ones displayed.

  24. if (count($result) >= $limit)
  25. $markup .= '<li>' . t("... only the first @limit results are displayed.", array('@limit' => $limit)) . '</li>';
  26. $markup .= '</ul>';

  27. // Using the render array's markup key to display our warning message.

  28. $form['description']['#markup'] = $markup;

  29. // Removing the 'delete' button from the form.

  30. $form['actions']['submit']['#access'] = FALSE;

  31. // $form['actions']['submit']['#disabled'] = TRUE; // Disables the button instead of removing it.

  32. }

  33. }

  34. break;

  35. }

  36. }

Summary

TL;DR: We want to prevent people deleting taxonomy terms which are already associated to nodes. We use hook_form_alter on the form taxonomy_form_term and use the function taxonomy_select_nodes to check if a node uses the term in question, then we display links to the nodes and remove the 'delete' button.

Feel invited to comment!

Original Post: 

About Drupal Sun

Drupal Sun is an Evolving Web project. It allows you to:

  • Do full-text search on all the articles in Drupal Planet (thanks to Apache Solr)
  • Facet based on tags, author, or feed
  • Flip through articles quickly (with j/k or arrow keys) to find what you're interested in
  • View the entire article text inline, or in the context of the site where it was created

See the blog post at Evolving Web

Evolving Web