No save button on vocabulary page?

I recently got a call from the content managers of a website I support, complaining that they couldn't reorder vocabulary terms any more. Specifically, the Save button was gone! Took me a while, but here is why, and how to solve it (if you just want the solution, scroll to the bottom)

I initially dismissed it a being some stray permission issue, since the specific site was using taxonomy access control to determine who could do what in the site. So I logged in as user 1, and casually strolled to the vocabulary page... where not buttons where present. 

I checked the page code, and found that the buttons were not present in the HTML at all - that ruled out any browser-side theming issues.

I pulled out my trusty custom hook module, and printed the form render array out... no buttons. This warrants deeper inspection, since it would appear that the taxonomy module is behind this!

So I started gutting the taxonomy module, adding debug code to find out what was going on. Which lead me to understand that the culprit was this check in

if ($vocabulary->hierarchy < 2 && count($tree) > 1) {

That line is the condition for outputting the form buttons. I'm sure that Drupal 6 devs are smirking now! This basically checks that there are items in the specific vocabulary, and the hierarchy type. 

In Drupal 6, hierarchy type was something you chose when creating the taxonomy - not so in Drupal 7. This particular part of code has to do with multi-parenting of terms ( ie terms that have more than one parent); The hierarchy type of the vocabulary is updated after a term is saved/updated and includes more than one parent. The bummer is, it doesn't get updated back when you remove the extra parent.

"But I don't use multiple parents" I hear you cry in the back. Well, the culprit behind THAT, was the hierarchical select module, and its Dropbox feature. For those unfamiliar with the feature, it allows selecting items from a hierarchical list and adding them one by one to a box. 

What happens is simple, but annoying to find - when you create a term, you have a parent selection form item, under "Relations", which is blank by default. This gets overriden by Hierarchical select, if you have it enabled for the vocabulary, and inherits the widget settings of  the vocabulary (hence, the dropbox). Initially, this dropbox contains the '<root>' element. If you try to add a parent to it via the dropbox (thus saving yourself from dragging the term in its proper place after it being created), the dropbox contains two values: root and your selected category. If your users just add the new category and save, you just won the lottery.

You now have a term that has the root level AND the proper place as parents, bumping your hierarchy type for the whole vocabulary. 

TL;DR - Ok, now how to solve this thing?

Unfortunately I haven' t found an elegant way around it - just make sure your users understand and not do it. For fixing a "broken" vocabulary (broken since you cannot reorder items, it is otherwise working as expected), you need to resort to a database query:

UPDATE taxonomy_vocabulary SET hierarchy=1 WHERE vid=5

you should obviously replace the vid number (in this example, 5) with the one you're interested in. For reference, the values for hierarchy are

  • 0 - flat list
  • 1 - hierarchy tree
  • 2 - multi-parent hierarchy 

If you find the above helpful, let me know, or about any other related findings you may have!