Attached is a patch which allows export of both individual taxonomy terms and (via features integration) all the terms on an exported vocabulary.

Some notes on how this works:

  • A new exportable is setup: taxonomy_term. This will export a single term. A $term->vocabulary member is set which is the machine readable name of $term->vid. This is used to set the correct $term->vid when restored.
  • The $pipe returned from taxonomy_vocabulary_features_export() will include all of that vocabularies terms (although, hierarchical terms aren't taken into account at all) which causes features to grab its terms via the taxonomy_term exportable.

As mentioned, it doesn't work for hierarchical terms and there are probably other things about terms that aren't being exported. But the most basic operation is there.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

dsnopek’s picture

More testing of synching to database revealed some issues. Here is an updated patch which fixes those issues.

jazzslider’s picture

I definitely like the idea. However, I'm not sure we should automatically include terms whenever a vocabulary is exported; sometimes all you want is the vocabulary itself. With that in mind, here are the rules I'd prefer:

1. When a vocabulary is exported, its terms are _not_ automatically exported; the user can still choose to export them if he/she wishes.
2. When a term is exported, its vocabulary _is_ automatically exported (since you need the vocabulary for the term).

What do you think?

Apart from that, the patch looks good …I haven't taken it for a test drive yet, but the code looks solid; I should be able to try it out shortly.

Thanks for your help with this!
Adam

dsnopek’s picture

Thanks for the feedback!

1. When a vocabulary is exported, its terms are _not_ automatically exported; the user can still choose to export them if he/she wishes.

I agree completely. However, how do we allow users to enable/disable such an option? I don't see anyway to pass options with the features system. All we get is:

features[taxonomy_vocabulary][] = "myvocabulary"

The only thing I can think of is providing also a "taxonomy_vocabulary_with_terms" or something similar. It would work, but would make our implementation a little uglier. What do you think?

2. When a term is exported, its vocabulary _is_ automatically exported (since you need the vocabulary for the term).

This is already in place in the patch.

Anyway, let me know if you experience any problems with testing.

Thank you,
David.

jazzslider’s picture

Hmm …provided that the hook_features_export_options() implementation is working correctly, the features UI should expose a list of taxonomy terms that can be manually selected. However, it does not appear to be doing so.

Been trying to track down the problem this morning in testing; it appears that _exportables_taxonomy_get_terms() isn't working as intended—on a site with several vocabulary terms, it's not returning anything.

I'll look into this further, but I thought I'd mention my findings so far.

Thanks!
Adam

jazzslider’s picture

OK, the attached patch resolves the problems I found; still need to test out whether the exported feature works correctly, but I think we're very close.

soglesby’s picture

For info:
There appears to be a problem with the helper implementations of hook_enable(), i.e. __enable(), appearing in both the ...features.taxonomy_term.inc and ...features.taxonomy_vocabulary.inc files.

Since both are included into ...features.inc you get a name clash.

Steven

dsnopek’s picture

For info:
There appears to be a problem with the helper implementations of hook_enable(), i.e. __enable(), appearing in both the ...features.taxonomy_term.inc and ...features.taxonomy_vocabulary.inc files.

Since both are included into ...features.inc you get a name clash.

I can think of basically two solutions to this problem:

  • exportables generates hook_enable() and hook_disable() with names modified to include the component name -- ie. mymodule_enable_taxonomy_vocabulary() -- and we require the user to write there own mymodule.install file to actually include and call them. This is less good because it makes exportables a sort-of 2nd class citizen within features. OR ...
  • Modify features to provide special support for hook_enable and hook_disable and do the mymodule.install generation. I started a patch for this in the features issue tracker: #651084: Patch for special treatment of install hooks -- required for taxonomy integration. It appears to work, but I haven't done very much testing yet.

What do others think?

Happy Hacking!
David.

M_Z’s picture

Is the #5 patch in current dev version of exportables? Thanks in advance.

M_Z’s picture

I answered my question #8 by myself. The patch is not in dev version of exportables.
I tried the patch and included vocabulary and 2 terms of that vocabulary into my feature.

Installing my feature on a fresh site created the vocabulary successfully, but to create both terms I had to visit admin/build/exportables/sync where I checked taxonomy_term and clicked the "Resync" button.

For my use case it isn't possible to check all terms individually when creating a feature.
Does someone know if there is a working taxonomy integration into Features module out there, which can manage a vocabulary and all its terms by one click when composing the feature?
Maybe I start my own patch to solve this issue (then I will use only one features.*.inc file for both - vocabulary and terms - and maybe the reason of my manually "Resync" for the terms is because of "There appears to be a problem with the helper implementations of hook_enable(), i.e. __enable(), appearing in both the ...features.taxonomy_term.inc and ...features.taxonomy_vocabulary.inc files." ?)

If #7 can be solved with one of the suggested options there could be 3 alternatives for taxonomy integration into features module (and maybe 3 different features.*.inc files):
- taxonomy_vocabulary (like in current dev version)
- taxonomy_term (added in patch #5)
- taxonomy_vocabulary_with_all_terms (must be developed)

dsnopek’s picture

My patch at #651084: Patch for special treatment of install hooks -- required for taxonomy integration was going no where and admittedly not great code. So, I've decided to abandon that approach all together.

Attached is a new patch, which is just like the last one from jazzslider, but doesn't try to generate hook_enable() and hook_disable(). These have to be written by the user and put in mymodule.install (assuming "mymodule" is the name of their feature):

/**
 * Implementation of hook_enable().
 */
function mymodule_enable() {
  drupal_load('module', 'exportables');

  exportables_sync('taxonomy_vocabulary', 'mymodule');
  exportables_sync('taxonomy_term', 'mymodule');
}

/**
 * Implementation of hook_disable().
 */
function mymodule_disable() {
  drupal_load('module', 'exportables');

  exportables_unsync('taxonomy_term', 'mymodule');
  exportables_unsync('taxonomy_vocabulary', 'mymodule');
}
Installing my feature on a fresh site created the vocabulary successfully, but to create both terms I had to visit admin/build/exportables/sync where I checked taxonomy_term and clicked the "Resync" button.

I believe this was an order thing, ie. it was trying to create the terms before creating the vocabulary. The terms would fail, but the vocabulary would succeed. On the second try, now the vocabulary is there, so terms would succeed too. This shouldn't be a problem with the custom written hook_enable() which puts them in the correct order.

Does someone know if there is a working taxonomy integration into Features module out there, which can manage a vocabulary and all its terms by one click when composing the feature?
Maybe I start my own patch to solve this issue ...

- taxonomy_vocabulary_with_all_terms (must be developed)

Its actually really easy to get it to pull all the terms too, my original-original patch did that. If your willing to just patch the code for your application, its only a matter of getting taxonomy_vocabulary_features_export() to return the terms names in the $pipe. You can see my first patch for guidance.

However, the more difficult is giving the user the option (with terms or without terms) and doing it without duplicating tons of code (ie. the "taxonomy_vocabulary_with_all_terms") feature. I'm thinking it could work by returning a $pipe with dependencies on both "taxonomy_vocabulary" and all the "taxonomy_term" names. But I haven't had a chance to try it yet.

M_Z’s picture

@dsnopek:
I understand the problem with hook_enable and hook_disable, but maybe we can find a better solution than your suggested 'manual way' (in #10).

Are there good reasons, that you split vocabularies and terms in 2 feature.*.inc files?
I think that we can get same behaviour with only one feature.*.inc file for both and an additional array key 'vocabulary' or 'term' inside the definition.

Then there is only one hook_enable and hook_disable implementation for all items which are covered by exportables module.
This hook implementation will always call both sync commands (in the right order):

  exportables_sync('taxonomy_vocabulary', 'mymodule');
  exportables_sync('taxonomy_term', 'mymodule');

I don't know if exportables_sync checks if there are array elements to synchronize. But also if it doesn't check it yet, it would be easy to implement.

I think that putting vocabularies and terms in one file is a big step towards your '$pipe' solution.

What do you think about it?
I offer some support in solving this problem, because I don't want to create my own solution, when there are already good approaches in the community (and I think that Exportables module is the most promising approach for a clean Features integration for taxonomy at the moment).

Greets,
Martin

dsnopek’s picture

@M_Z:

I understand the problem with hook_enable and hook_disable, but maybe we can find a better solution than your suggested 'manual way' (in #10).

Are there good reasons, that you split vocabularies and terms in 2 feature.*.inc files?
I think that we can get same behaviour with only one feature.*.inc file for both and an additional array key 'vocabulary' or 'term' inside the definition.

Then there is only one hook_enable and hook_disable implementation for all items which are covered by exportables module.
This hook implementation will always call both sync commands (in the right order).

IMHO we can't have exportables automatically generating hook_enable() and hook_disable() unless its a somehow extendable system (which my former features patch was sort-of, atleast for other features). What if the user has something else they want to do in those hooks? How would they prevent exportables from conflicting with their own? Even if we decide that exportables will only write one set of enable/disable hooks, what if someone wants to use another 3rd party module which wants to provide its own enable/disable hooks?

Unless we can answer all those questions, I think the manual approach is the best way.

We could make things easier on users and create functions like:

// sync everything covered by exportables for 'mymodule' in the correct order
exportables_sync_module('mymodule');

// un-sync everything covered by exportables for 'mymodule' in the correct order
exportables_unsync_module('mymodule');

So then users don't have to care about what they put in those hooks. This would make documentation and support easier too, especially if someday exportables supported more types than just taxonomy vocabulary and terms, the existing user hook would continue to work...

M_Z’s picture

@dsnopek:

Thank you for your reply.

I understand you and I did some brainstorming with me :-) if there could be another solution.
Here is my suggestion:

1. We try to auto-generate a simple 'sub-module' CUSTOMFEATURENAME_exportables containing of a .info file and a .module or .install file where we place CUSTOMFEATURENAME_exportables_enable and ..._disable hook implementations containing only your suggested fundtions exportables_sync_module('mymodule') respectively exportables_unsync_module('mymodule') (see #12).
This sub-module will be placed inside the exported feature directory beside all the other .inc files.

2. We add a dependency for this sub-module into our (main) feature.

The sub-module prevents us from 'blocking' a custom hook_enable or hook_disable implementation in the (main) feature. And the sub-module will be installed (and enabled) on the fly, when the (main) feature will be activated (because of the module dependency).

What do you think about it?

jonskulski’s picture

subscribing.

@M_Z Creative solution but I don't think that entirely solves the problem and it introduces quite a bit of overhead, imo. The problem still exists what if there are other exportables that need to play around in hook_enable(). The requirement of an extensible system to collection actions is still there.

It's not very different than just having a custom exportables_enable (that is then called from the real hook_enable)

Unfortunately I don't have a great solution suggestion.

jonskulski’s picture

I'd also like to point out that this approach doesn't seem to support anything but a base case of adding a vocabulary and terms. For example, if I want to have a feature with a view that filters by a term id.

Views stores it's filters like this

 $handler->override_option('filters', array(
  'tid' => array(
    'operator' => 'or',
    'value' => array(
      '0' => '3282',
    ),
    'group' => '0',
    'exposed' => FALSE,
    'expose' => array(
      'operator' => FALSE,
      'label' => '',
    ),
    'type' => 'textfield',
    'limit' => TRUE,
    'vid' => '26',
    'id' => 'tid',
    'table' => 'term_node',
    'field' => 'tid',
    'hierarchy' => 0,
    'relationship' => 'none',
    'reduce_duplicates' => 0,
  ),
));

You'll notice hard term IDs and vocabulary IDs in there.

I suppose the view default function could be changed so that we use the _exportables_fix_.. functions to turn the machine name into a tid. This would require either manual editing or some sort of text replacement script. Neither of these options are very good, in my opinion. Open for suggestions/placation.

For this immediate project we are reserving some term and vocabulary IDs and just doing it that way.

jonskulski’s picture

Status: Needs review » Needs work

Setting to needs work

hefox’s picture

Subscribe, reminding myself to update with what I did when time.

got one of the originally patch somewhat working eventually, but not in patches yet.

hefox’s picture

Attached is a patch 2 with some modifications based on modifications done against the first patch. Haven't tested this patch, and may have missed some.

Some of the issues was null being returned when empty should have, and upsetting of term tid before the term save completely owned the update, though perhaps what needs to be done instead is a separate update function. hmm.

On handling of other exported items, other than by making custom filters or altering the actual output of exported views to include calls to get term/vocabulary information, I don't see it as being possible without interaction on the feature creator to add in calls to get the desired machine name. Hmm..

Summit’s picture

Subschribing, greetings, Martijn

hefox’s picture

First is my current working taxonomy term only related patch, adds parent term support.

In the end, I personally don't mind writting my own hook_enables and would prefer that it doesn't do it for me as I end up moving em to the install folder anyway, so I suspect documentation would be acceptable at first, but getting the patch in for some basic support would be really really grand. However, in some respect the enable/disable issue is an overall exportable issue, not terms themselves?

Note though, I'm mostly using exportables for the hooks, and not exporting via features. :>

Actually, perhaps logic can be added that if vocabulary machine name doesn't exist, try and find vocabulary and synch it, but seems messy.

As for views, I use content_taxonomy fields so that views isn't generally an issue, content taxonomy is. I use #693024: Add alter hooks for the "faux" exportables which gives me hook_content_default_fields_alter and update my fields vids to the new one :). hook_views_default_views_alter is already in views, which allows me to do something similar also, so my features work whatever the vocabulary ids are.


/**
 * Implementation of hook_content_default_fields_alter().
 */
function mymodule_content_default_fields_alter(&$fields, $module) {
  _exportables_fix_content_taxonomy($fields,
    array(
      'field_some_field' => 'vocabulary_machine_name',
    )
  );
}

function _exportables_fix_content_taxonomy(&$fields, $replacements) {
  foreach ($replacements as $field => $machine) {
    $replacements[$field] =  exportables_machine_load_id('taxonomy_vocabulary', $machine);
    if (empty($replacements[$field])) {
      unset($replacements[$field]);
    }
  }
  foreach($fields as $key => $field) {
    if (!empty($field['field_name']) && !empty($replacements[$field['field_name']])) {
      $fields[$key]['vid'] = $replacements[$field['field_name']] ;
    }
  }
}
function mymodule_views_default_views_alter(&$views) {
  $views['viewname']->display['default']->display_options['filters']['tid']['vid'] = exportables_machine_load_id('taxonomy_vocabulary', 'vocabulary_machine_name');
}
hefox’s picture

Status: Needs work » Needs review

Opened topic specific to enable/disabling exportables #834888: Enableing modules with exportable hooks/ drupal_write_record, marking this needs review.

rfay’s picture

subscribe

hefox’s picture

Version: 6.x-1.x-dev » 6.x-2.x-dev
Status: Needs review » Needs work

Since exportabeles 1.x conflicts with stable features, and exportables 2.x is quite different... changing status.

acouch’s picture

@hefox or @dagmar, is there any point to updating this to 2.x since Features now supports CTools Export API and the module maintainer says "Taxonomy export, and all the UI to sync exportables is not yet in this release, and probably will be delegated in other module." ?

Would that better be handled here: http://drupal.org/node/755986 ?

hefox’s picture

Likely, but figured module maintainer should likely close it in this case.