Here's a quicky. Let's say you've created some exportable content (using CTools) which references a term ID and you have to go from your dev site to the production site. And your taxonomy is also being exported using UUID.
Somehow you have to tie them together because sure as eggs is eggs the term IDs created on the production site are not going to be the same as the local ones. That's why you used UUID in the first place. Right?
Here's what you do: in your local exportable you will have a column for the term ID so include a column for the term UUID as well.
In your add/edit form for the exportable you'll have to include some code to automatically add the selected term's UUID - I did it in the form validation. Basically you read the selected term ID, load the selected term which will have the UUID in it (because it's added to the base table). Set the term UUID value in $form_state['values']. Assuming you're using CTools Export UI the UUID will be saved automatically.
Also, in the module install, add "no export" => TRUE to the TID field, so that Export UI does not include it in the feature. (This code works for Features, it doesn't work for single imports, I'll leave that as an exercise for the reader - hint: you can specify an "import callback".)
That's the easy bit, when you export your content it will be saved with the term's UUID and not the term's ID. The difficult bit is how to link the UUID of exported content when Features loads it into the new site.
Except it's not hard at all. In your export specification, in the schema, you have the "default hook", well CTools Export UI very kindly calls an drupal_alter() on the default items after it's loaded them. So we can do this:
/**
* Implements hook_DEFAULT_HOOK_alter().
*
* This intercepts any defaults picked up from code and converts
* their UUID category into the local TID (which might be different
* on every site).
*
*/
function mymodule_my_default_hook_alter(&$items) {
$uuids = db_select('taxonomy_term_data', 't')
->fields('t', array('uuid', 'tid'))
->execute()->fetchAllKeyed();
foreach ($items as $item) {
if (empty($item->tid) && !empty($uuids[$item->uuid])) {
$item->tid= $uuids[$item->uuid];
}
}
}
The database call creates an array which maps all UUIDs to TIDs in one go. If your site uses a lot of taxonomy terms - perhaps you have user tagging - you might want to restrict this call to a specific vocabulary.
The exact item property names will depend on what you set up in your schema.
Sorted.
Showing posts with label taxonomy. Show all posts
Showing posts with label taxonomy. Show all posts
Thursday, 11 July 2013
Wednesday, 4 July 2012
Changing view_mode mid-stream
In my current contract I have to display a hierarchy of complex taxonomy terms - each one as a page with relevant data hanging off it. There are three levels to the taxonomy: Level 1 displays one set of data and links, Level 2 is never displayed on its own (which is something I'll have to take care of) and Level 3 has a different page structure again.
Different page layouts means Display Suite (http://drupal.org/project/ds) and that's great. It works fine when you want to configure a different layout for a node - as long as it's the same for every node type. Or entity bundle.
DS works fine for taxonomy terms in just the same way as for nodes. It is one of my favourite modules.
But I needed to be able to change the view_mode on the fly: to check what level the taxonomy term is and change the view_mode based on that. Which is when I ran into trouble - and it's not DS's fault. Though I never had to do it apparently this was not a problem in D6 but in D7 there is a bug which makes it tricky to change view_mode. You can read all about it here: http://drupal.org/node/1154382
This issue gives some hints as to the solution (hook_entity_prepare_view() is not it), but there is a link to this blog here. The solution described is for changing build mode for nodes based on the current theme (so you can change things if you're using a mobile theme).
My solution is the same except slightly more generic, instead of intercepting hook_node_...() hooks, I intercept hook_entity_...() hooks.
I'm just going to throw my code at you because I know you can work out what to do in your own situation.
/**
* Implements hook_entity_prepare_view().
*
* We have to play silly games to change the view_mode, first we intercept
* hook_entity_prepare_view() and establish what view_mode we want, and
* save it. But there's a bug which means this has no effect on the output
* so...
*/
function page_g2g_entity_prepare_view($entities, $entity_type, $langcode) {
if ($entity_type!='taxonomy_term') {
return;
}
foreach ($entities as $id => $entity) {
if ($entity->vocabulary_machine_name!='gtg_tags' || $entity->view_mode!='full') {
// wrong vocabulary or not a "full page"
continue;
}
// Change the display dependent on the number of parents
switch (count(taxonomy_get_parents_all($entity->tid))) {
case 1:
$entity->view_mode = 'g2g_level_1';
break;
case 2:
// Hm. Need to do something else here, maybe
// do a redirect to the parent term.
break;
case 3:
$entity->view_mode = 'g2g_level_3';
break;
}
}
}
/**
* Implements hook_entity_view_alter().
*
* ...we intercept before the full build is enacted. You can test and see that
* even though we changed the view_mode in the term itself, it hasn't transferred
* to the build theme. So having verified we want to do it with this entity
* we transfer it. And now it gets changed.
*/
function page_g2g_entity_view_alter(&$build) {
if (isset($build['#entity_type']) && $build['#entity_type']=='taxonomy_term') {
$build['#view_mode'] = $build['#term']->view_mode;
}
}
Arguably you don't need the first hook, you could do it all in the second call. But it's a matter of elegance and splitting actions into their appropriate locations.
Different page layouts means Display Suite (http://drupal.org/project/ds) and that's great. It works fine when you want to configure a different layout for a node - as long as it's the same for every node type. Or entity bundle.
DS works fine for taxonomy terms in just the same way as for nodes. It is one of my favourite modules.
But I needed to be able to change the view_mode on the fly: to check what level the taxonomy term is and change the view_mode based on that. Which is when I ran into trouble - and it's not DS's fault. Though I never had to do it apparently this was not a problem in D6 but in D7 there is a bug which makes it tricky to change view_mode. You can read all about it here: http://drupal.org/node/1154382
This issue gives some hints as to the solution (hook_entity_prepare_view() is not it), but there is a link to this blog here. The solution described is for changing build mode for nodes based on the current theme (so you can change things if you're using a mobile theme).
My solution is the same except slightly more generic, instead of intercepting hook_node_...() hooks, I intercept hook_entity_...() hooks.
I'm just going to throw my code at you because I know you can work out what to do in your own situation.
/**
* Implements hook_entity_prepare_view().
*
* We have to play silly games to change the view_mode, first we intercept
* hook_entity_prepare_view() and establish what view_mode we want, and
* save it. But there's a bug which means this has no effect on the output
* so...
*/
function page_g2g_entity_prepare_view($entities, $entity_type, $langcode) {
if ($entity_type!='taxonomy_term') {
return;
}
foreach ($entities as $id => $entity) {
if ($entity->vocabulary_machine_name!='gtg_tags' || $entity->view_mode!='full') {
// wrong vocabulary or not a "full page"
continue;
}
// Change the display dependent on the number of parents
switch (count(taxonomy_get_parents_all($entity->tid))) {
case 1:
$entity->view_mode = 'g2g_level_1';
break;
case 2:
// Hm. Need to do something else here, maybe
// do a redirect to the parent term.
break;
case 3:
$entity->view_mode = 'g2g_level_3';
break;
}
}
}
/**
* Implements hook_entity_view_alter().
*
* ...we intercept before the full build is enacted. You can test and see that
* even though we changed the view_mode in the term itself, it hasn't transferred
* to the build theme. So having verified we want to do it with this entity
* we transfer it. And now it gets changed.
*/
function page_g2g_entity_view_alter(&$build) {
if (isset($build['#entity_type']) && $build['#entity_type']=='taxonomy_term') {
$build['#view_mode'] = $build['#term']->view_mode;
}
}
Arguably you don't need the first hook, you could do it all in the second call. But it's a matter of elegance and splitting actions into their appropriate locations.
Sunday, 12 June 2011
Vocabulary by machine name, taxonomy_get_tree() and $user
(Amended on 17 Jul 2011 to replace reloading entire entities with using field_attach_load().)
Getting the ID of a vocabulary has long been a problem in Drupal but Drupal 7 goes a long way to resolving that:
$voc = taxonomy_vocabulary_machine_name_load('vocab_machine_name');
And you've got it.
However if you want to load a taxonomy_tree you still have to use the vocabulary ID so you run the line above first, and then:
$tree = taxonomy_get_tree($voc->vid, [parent], [depth], [internal value]);
The last two parameters on taxonomy_get_tree() have been swapped so if you want to specify the depth you don't have to do (..., -1, $depth) just (..., $depth). Which is handy.
Note that taxonomy_get_tree() does not return a full entity, which is unfortunate if you want any fields that have been attached to the terms. You have to fetch the fields separately but it's not hard:
$tree = taxonomy_get_tree($voc->vid);
foreach ($tree as $key => $term) {
$terms[$key] = $term->tid;
}
field_attach_load('taxonomy_term', $terms);
The same applies to the global $user variable. This is normally the user without attached fields, so if you need a field that has been attached...
global $user;
field_attach_load('user', array($user->uid => $user));
Hope that helps.
Getting the ID of a vocabulary has long been a problem in Drupal but Drupal 7 goes a long way to resolving that:
$voc = taxonomy_vocabulary_machine_name_load('vocab_machine_name');
And you've got it.
However if you want to load a taxonomy_tree you still have to use the vocabulary ID so you run the line above first, and then:
$tree = taxonomy_get_tree($voc->vid, [parent], [depth], [internal value]);
The last two parameters on taxonomy_get_tree() have been swapped so if you want to specify the depth you don't have to do (..., -1, $depth) just (..., $depth). Which is handy.
Note that taxonomy_get_tree() does not return a full entity, which is unfortunate if you want any fields that have been attached to the terms. You have to fetch the fields separately but it's not hard:
$tree = taxonomy_get_tree($voc->vid);
foreach ($tree as $key => $term) {
$terms[$key] = $term->tid;
}
field_attach_load('taxonomy_term', $terms);
The same applies to the global $user variable. This is normally the user without attached fields, so if you need a field that has been attached...
global $user;
field_attach_load('user', array($user->uid => $user));
Hope that helps.
Subscribe to:
Posts (Atom)