I was working on an importer for a custom (hierarchical) taxonomy in WordPress recently and was baffled by some strange behaviour. My CSV test data looked a little like this:
Paints & Finishes, Emulsions Paints & Finishes, Varnish Paints & Finishes, Barn Paint Lettering, Small Lettering, Large Folding Canopies Energy Products, Juice
Which, I hoped, would result in a tree-like structure as follows:
- Paints & Finishes
- Barn Paint
- Folding Canopies
- Energy Products
So 4 root items and 6 children. So I was a bit miffed to see that, although both the terms and term_taxonomy tables were correctly populated and the parent:child relationships properly established, only the root items were displaying (when I logged into the dashboard and visited the WordPress-generated taxonomy list, that is). I also noticed that:
- If I ran the import a second time, although this quite correctly didn’t cause any further changes to the terms or terms_taxonomy tables, the missing child categories showed up
- Or, if I didn’t run the import a second time – but deleted/trashed all of the root categories, then the child categories magically materialized out of thin air … although having been orphaned by the previous delete operation they were now promoted to being root items
Clearly I was missing something. The answer of course is that traversing a table with ID and Parent ID columns to establish the hierarchy on every single request would be a fairly intensive operation. Instead, WordPress caches this data – within the options table – and it was this cache which had not been refreshed.
The import code I wrote made use of two different WordPress functions, wp_insert_term() and wp_update_term(), and the upshot was that, depending upon which was called and when, the cached term hierarchy would not always be refreshed.
So the solution was simple – clearing out the cached option and regenerating it with _get_term_hierarchy() (naughty, naughty – as this function is marked private but I did mange to justify this to myself) after all the terms to be imported had been updated or inserted.
So, in summary, a momentarily frustrating but all the same interesting look at the internal machinery of WordPress.
- The problem with daring to interfere directly with an options table based cache is, what if a cache other than the options table was in use? In this case the answer is that WordPress does not use its own caching API internally, at least not in this area: use of the options table for this particular cache is hard-coded.