Hello,

I was hoping your module would have something useful for developers, but alas, so I wrote my own lineage loader:

/**
 * Get the lineage of a taxonomy term
 *
 * @param $term object The taxonomy term
 * @return object The taxonomy term with a loaded parent_term property
 */
function taxonomy_get_lineage($term) {
  $parents = taxonomy_get_parents($term->tid);
  
  // If we've reached the bottom of the tree, build the path
  if (!$parents) {
    $lineage = array();
    while ($term) {
      $parent     = $term;
      $clean_term = clone $term;
      unset($clean_term->child);
      $lineage[]  = $clean_term;
      $term       = isset($term->child) ? $term->child : FALSE;
    }
    $parent->lineage[] = $lineage;
    return FALSE;
  }
  
  // Otherwise set the child term
  foreach ($parents as $parent) {
    $parent->child = $term;
    taxonomy_get_lineage($parent);
  }
}

This adds a property, lineage, to the taxonomy term. The lineage property contains shallow (for better garbage collection) copies of all the terms, for all the paths through a multi-parented taxonomy tree.

For example, to print all of paths for a taxonomy item:

* vetted > Design / Design Arts > Architecture > Acoustics / Acoustic Design
* Categories > Arts / Entertainment > Design / Design Arts > Architecture > Acoustics / Acoustic Design
* vetted > Arts / Entertainment > Design / Design Arts > Architecture > Acoustics / Acoustic Design
* Categories > Engineering > Design / Design Arts > Architecture > Acoustics / Acoustic Design
* vetted > Engineering > Design / Design Arts > Architecture > Acoustics / Acoustic Design
* vetted > Architecture > Acoustics / Acoustic Design
* Categories > Construction > Architecture > Acoustics / Acoustic Design
* vetted > Construction > Architecture > Acoustics / Acoustic Design
* vetted > Acoustics / Acoustic Design

We would write:

  $term = taxonomy_get_term(777);
  taxonomy_get_lineage($term);
  
  foreach ($term->lineage as $parents) {
    $names = array();
    foreach ($parents as $parent) {
      $names[] = $parent->name;
    }
    drupal_set_message(implode(' > ', $names));
  }

Hope someone finds this useful.

Cheers,
Aidan

Comments

xjm’s picture

Status: Needs review » Postponed (maintainer needs more info)

I'm confused. This code doesn't seem to use any of lineage's API or database records at all.

xjm’s picture

Version: 6.x-1.x-dev » master

If lineage is enabled, you can get the lineage for a term with a query like:

$r = db_query("SELECT lineage FROM {term_lineage} WHERE tid = %d", $term->tid);
$lineage_string = db_result($r);

(This snippet assumes a normal hierarchy, no multiple parents.)

This provides a lineage string that can then be manipulated as you like (explode on \n and use lineage_strip_weight() or lineage_get_weight()).

It would be simple to add an API function for this (lineage_get_lineage()). It could accept a $term object as an argument (or a $tid), and return an array with the lineage data, with weight and term name for each line of the lineage. Caching recommended.

Lineage is mostly a views module, but I'd certainly consider a patch for an API function like this if folks would find it useful.

xjm’s picture

Version: master » 6.x-1.x-dev
Status: Postponed (maintainer needs more info) » Needs work
aidanlis’s picture

Status: Needs work » Needs review

You're right, I didn't use any of lineage's APIs because I needed support for multiple parents - you can see from the output that the tree I'm dealing with has multiple parents all over the place. If there's an easier way of doing this with your module I'd love to know how.

In terms of inclusion, if your module is primarily for views this function may find a home somewhere else - it doesn't seem an unreasonable inclusion for Drupal core IMO.

xjm’s picture

Status: Needs review » Active

Submitting an issue to the Lineage queue doesn't submit anything to Drupal core. (At this point any API changes would probably only be considered for 8.x.) Also, the "needs review" status is for issues with a working patch, which this doesn't have.

I would be interested in a patch for this, though, and in a patch to improve lineage's support for multiple parents (which would be a separate issue). The possibility is there; simply a matter of adding a foreach in a couple places.

aidanlis’s picture

The Drupal core comment was an aside - having spoken to chx the operation is too expensive for core, the hierarchies would need to be improved at a database level which is definitely an 8.x thing.

If you want to keep lineage as a views based module I'm happy to drop this function into a new module called Taxonomy Advanced API (or something), there's a few taxonomy helper functions going around which might have a home in such a module (http://drupal.org/node/769632 for example).

Otherwise, what else would you like changed? I don't see a point in making a patch for a single drop-in function.

Thanks,
Aidan

aidanlis’s picture

Just dumping some other functions which could go into a Taxonomy Advanced API module:
#255507: API clean-up: Help for taxonomy helper functions
#750654: taxonomy_enhancer module required?
#125231: Enhance autocomplete feature

(Sorry, I know these aren't related to your module, just keeping them here in case I go ahead and make the new module.)

aidanlis’s picture

< nicklewisatx> aidan_ how bout a taxonomy object that lets me quickly up and down through a hierarchy $term->parent()->parent();

xjm’s picture

Well, the advantage of using lineage's database records (as described in #2 above) is that you avoid the recursion in your script; there's only one query instead of n queries per parentage on the view. (Or, in other words, the recursion happens only when terms are changed rather than every time someone wants to look at the hierarchy.) That's why I think this would to be good to include with lineage, because lineage has already created that table.

#9 sounds good too; just a matter of returning an object instead of an array and adding that method.

You'll find that Drupal maintainers always want a patch for anything. :)

I'll take a look at this when I have some time this weekend and post a patch.