Problem/Motivation

The taxonomy module provides the taxonomy_get_tree() function that returns the terms' tree for a given vocabulary. It is used in the backend taxonomy administration page (admin/structure/taxonomy/[machine_name]), in the generation of Term reference field selectors (both in the backend create/edit forms and in the front-end, like for example Commerce add to cart forms) and is also used by plenty of contrib modules (taxonomy menu, views, etc...).

The problem with this function is that it directly calls the database to get the terms hierarchy, and then, only if the $load_entities parameter is set to TRUE, it loads each term's entity. This makes it impossible to use the hook_entity_load() hook when taxonomy_get_tree() is called, thus making modules relaying on it to alter the term entities on load not work properly. This is incoherent with the taxonomy_term_load_multiple(), that is used everywhere in the taxonomy module, and that always loads the term entities and even has its own hook (hook_taxonomy_term_load).

The most important module affected by this I've found is Title, which used together with Entity Translation has become the de-facto standard for proper content internationalization.

Proposed resolution

The proposed resolution is making the $load_entities parameter default to TRUE. This simple change makes all the taxonomy trees immediatelly work with any modules relying on the entity_load hook to alter term's properties (for instance, it shows them translated in the backend and in the term reference fields selector widget when using Title + ET). Yes, it adds a bit of overheat by loading each term's entity, but it's minimal because of the entity controller static cache and the taxonomy_get_tree() function's own cache and I think the alternatives to this are worse.

One alternative is to modify all the calls to taxonomy_get_tree() to set the $load_entities parameter to TRUE. This would have to be done everywhere it is called in core (including taxonomy, field, forum, node, etc... modules) and in all the contrib modules that want to use and/or render the term's name or any other field (99.99% I'd say). When you can just set the parameter to TRUE as default, that doesn't make a lot of sense. Similar to this, would be to "manually" use entity_load() at the same places.

The other alternative is to use hook_query_term_access_alter() to alter the query and modify the information you want. This seems like a really bad idea to me and would lead to conflicts between diferent modules altering the query.

Thinking if this change could break any existing code, I can't see how. Any code showing terms wants to allow for entity_load hooks to run so the behaviour is consistent everywhere. Any code not showing terms (for example using only the term IDs or weights) won't be affected, apart from the minimal overheat.

So basically, what I propose is changing:
function taxonomy_get_tree($vid, $parent = 0, $max_depth = NULL, $load_entities = FALSE) {
to:
function taxonomy_get_tree($vid, $parent = 0, $max_depth = NULL, $load_entities = TRUE) {
in core's taxonomy/taxonomy.module.

Just this simple modification would fix a fair amount of long-standing and complicated-to-solve-because-core-doesnt-care-about-i18n issues, for example:

Also, any module using taxonomy_get_tree() without setting the param to TRUE (very probable if you don't test in an internationalized installation) will automatically get support for Entity Translation + Title.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

colan’s picture

This makes sense to me. I'm not sure if it's justified (i.e. maybe caching isn't enabled), but someone's complaining about the performance implications of doing this over at Get translated taxonomy terms with Entity Translation.

Maybe there's a way we can make it faster, and have it be correct? Not sure if the Core maintainers would be happy just going with the latter to fix things in Contrib (if it slows Core).

aleksijohansson’s picture

Patch attached with the proposed change implemented.

Status: Needs review » Needs work

The last submitted patch, 2: taxonomy_get_tree_load_entities_by_default-2418629-2.patch, failed testing.

dbt102’s picture

Status: Needs work » Reviewed & tested by the community
FileSize
125.01 KB

Thanks for the great description on this issue. It is exactly the problem I was having on a fresh install of Commerce Kickstart and translating Product Categories into Arabic.

The patch installed cleanly, and enabled translations in dropdown (as shown in attached file).

David_Rothstein’s picture

Status: Reviewed & tested by the community » Needs review

Well, as comment #1 above says (as well as the API docs of taxonomy_get_tree() itself) this seems like it could really hurt performance and memory usage in some cases...

So I think it needs more discussion, especially since it's an API change.

I would tend to prefer we keep the API function as is and consider modifying the calling code where safe/necessary instead.

Or in the worst case, we could consider adding a new hook (that runs after the tree is loaded with partial terms) that would let the above-mentioned contrib modules react to the tree being loaded similar to how they would normally react via hook_entity_load()?

gonssal’s picture

Seeing there has been no interest in this, which I find weird considering how much Entity Translation is used, I think the are basically two options:

  • Implement as a new hook (drupal_alter('taxonomy_get_tree_load_entities')?) that runs before the $load_entities value check so you can change it.
  • Forget about it and go for Drupal 8 if you want good and manageable i18n.

If any decision maker that can get this into core considers it's worth it, I'll send a patch with the hook.