Not to be confused with #412518: Convert taxonomy_node_* related code to use field API + upgrade path which makes taxonomy vocabularies into a field. This issue is for attaching fields to taxonomy terms.

I think this could be a step-by-step process:

1. hook_fieldable() and the various field_attach() calls.
2. Convert term descriptions to a text field
3. If both this and vocabulary fields gets in, then look at converting synonyms and related terms into fields and fun stuff like that.
4. Possibly make vocabularies fieldable and do the same thing with description for those.

This issue will only deal with step #1.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

yched’s picture

Big +1 !

5. Figure out what's the output for those fields : where are they displayed by default ? at the top of taxo/term/tid pages like current 'description' ? Do we need to introduce a tpl file ? Are there other 'build modes' that make sense out of the box ?
See #409750: Overhaul and extend node build modes - basically, every fieldable entity has to wonder what are its display modes. Years of CCK has made this pretty clear for nodes, we have to invent this for other entities.

catch’s picture

Status: Active » Needs work
FileSize
2.38 KB

Alright here's something just to get the ball rolling, already hitting bits of the mess which is taxonomy module.

1. Where the hell does field_attach_view() go? taxonomy_term_page() is where we'd most likely want to display fields, at least initially, but that doesn't even load actual term objects yet, let along render anything in a nice way. Is it enough to get the basic loading and saving in and fix that in a followup, or do we need to do that here?

2. Do we want to use vocabulary ID for bundles (I do - add geo fields to a locations vocabulary but not to car models for example) - but is just vid enough for a bundle key or is that going to take some refactoring?

yched’s picture

Bundles should definitely be vocabularies IMO. Technically, numeric bundle ids shouldn't be an issue for the field API, except if several entity types later come naturally with numeric bundles too. Maybe we can use 'vocab_[vid]' as a string id - sort of relates to 'prevent bundle names clashes', which hasn't been sorted out yet - and for which it seems we haven't even created an issue yet ?.

A nasty side effect however, whether we use a 'vocab_' prefix or not, is that those numeric 'vids as bundles names' bubble up to template names.
- field.tpl.php has a field-[field_name]-[bundle-name].tpl.php variant
- if terms are fieldable, they probably need a term.tpl.php (equivalent to node.tpl.php), and thus a term-[bundle-name].tpl.php variant
Having code or filenames depend on serial ids rather than string machine name is bad practice for code transportability, since ids can change from site to site (was one of the issues with flexinode). So this sort of calls for machine name for vocabularies :-(.

Could be done in a separate issue, though. I think #412518: Convert taxonomy_node_* related code to use field API + upgrade path will raise the same need : taxonomy fields using numeric vids in their definition will be painful to export / import.

catch’s picture

Machine names for vocabularies is a small price to pay I think, and sounds like the least worst option.

term.tpl.php sounds good. Either way we have to do some serious refactoring of taxonomy_term_page() at some point.

Xano’s picture

Subscribing.

andypost’s picture

Subscribe...

skilip’s picture

Subscribe

catch’s picture

Status: Needs work » Needs review
FileSize
3.26 KB

Re-roll, completely untested. taxonomy_term_page() is slightly cleaned up since the last time I looked at it.

catch’s picture

FileSize
5.61 KB

This time with field_attach_form() call.

There might not be all that much left to do here - need to create a text field for the purposes of testing and see if any of it works.

Status: Needs review » Needs work

The last submitted patch failed testing.

catch’s picture

Assigned: Unassigned » catch
Status: Needs work » Needs review
Issue tags: +Fields in Core
FileSize
4.7 KB

Working patch, successfully attached a text field and displayed it.

There aren't tests for attaching fields to specific fieldable entities in core yet, so not sure if we need those, or how to write them if so. But please try at home.

catch’s picture

FileSize
12.55 KB
6.3 KB

and the screenshots.

catch’s picture

FileSize
6.26 KB

Spoke to webchick in irc and she reckoned we should try to get bundles in with this patch too.

So updated version which adds a 'machine_name' column to the taxonomy_vocabulary table, along with hook_update_N() and field on the vocabulary creation form.

Status: Needs review » Needs work

The last submitted patch failed testing.

yched’s picture

Status: Needs work » Needs review

No time to test just right now - but major yay !
Now is definitely a good time to push this forward. The sooner we get this in, the more time there is to digest the consequences (in followup patches) - for instance:
- making terms fieldable is a strong incentive to have the taxo listing pages themed through a template ? The current hook_taxonomy_load() probably begs for this too, BTW...
- how does a Field UI (even the current contrib one) fits in ?

About the patch itself: one of the possibly tricky bits in the form part is making sure the "add more" button works ok with unlimited-value fields. And actually, making the non-JS part work is a little more demanding on the form workflow. Existing node form workflow, albeit awful at places, was OK, but user form workflow is uglier still, and non-JS 'add more' currently doesn't work on user forms. See #367006: [meta] Field attach API integration for entity forms is ungrokable and field_add_more_submit()'s $form['#builder_function'] for the gory details.

andypost’s picture

Trying to test this, patch applied clean

Using devel module executing code below still have no effect

Looking in database - tables for field created but still no input form on term edit page

Suppose using taxonomy term as bundle is wrong this should be per vocabulary

$field = array(
  'field_name' => 'somefield',
  'type' => 'text',
  'cardinality' => 1, /* not necessary as it's the default.*/
);
field_create_field($field);
$instance = array(
  'field_name' => 'somefield',
  'bundle' => 'taxonomy term',
  'label' => t('Some field'),
  'description' => t('You can enter something here.'),
  'weight' => 0,
  'widget' => array(
    'type' => 'text_textfield',
    'label' => t('Some field'),
  ),
);
field_create_instance($instance);
yched’s picture

- Minor : taxonomy_form_vocabulary() - "...for internal user only"
- machine name: field_attach_(create|rename|delete)_bundle() functions need to be called where appropriate
(field_attach_create_bundle() should also be called in the update function, probably)

yched’s picture

Status: Needs review » Needs work

Fix status after #15 crosspost over #13.

yched’s picture

Other missing calls : field_attach_delete(), field_attach_form_validate(), field_attach_submit()

Wim Leers’s picture

Subscribing. (First time in months.) Interesting to say the least. :)

catch’s picture

Status: Needs work » Needs review
FileSize
18.9 KB

At least we know from all those exceptions that the field API and taxonomy module is well tested.

New patch, here's what it does:

1. Adds a machine_name column for taxonomy vocabularies
2. Uses that as bundle
3. loads the vocabulary machine name in taxonomy_term_load_mutiple() (via a join) - because field API needs this a property of the fieldable object.
4. Lots and lots of test cleanup because we need the actual vocabulary when creating terms now instead of just vid so we can pass machine_name around.

I'm not tied to machine_name at all, and it seems a bit of a shame that we have to create it and mess around with it just to get nicely named bundles.

On irc, sun suggested changing $vocabulary->name to $vocabulary->title and then machine_name -> name. That's an idea, but it breaks any code using vocabulary->name, and also taxonomy terms have names, not title.

sun also suggested $term->type (as a corollary to $node->type)- that'd be great if the concept of node types wasn't embedded into taxonomy.module already (taxonomy_get_vocabularies($type) etc.) - that's hopefully going to die when vocabularies as field gets in, but no point trying to kill it twice.

So we're left with either adding machine name - which I think is a small price to pay for per-vocabulary bundles, trying to do something like generate the bundle from a sanitized version of vocabulary->name (but that's likely to break if your vocabulary name is in non-roman characters), or I dunno, something else. I'm tempted to say we should put it in with machine name now (so we don't get stuck with numeric ids), then revisit as soon as vocabularies is fields is in and we've got a less crowded namespace.

Either way, all taxonomy tests pass with this - haven't re-tested the field/instance creation.

catch’s picture

FileSize
19.22 KB

Missed a spot.

webchick’s picture

Content types as of a few months ago have auto-machine-name-generating code, based on the human-readable name. Let's re-use that. If it causes problems with non-Latin characters, we're going to want to fix it in both places anyway.

catch’s picture

FileSize
21.47 KB

Spoke to Stella in irc and re-using it is going to be uglier than copying and pasting it due to all the different form ids, so I've done that. Works fine on my testing.

catch’s picture

FileSize
21.48 KB

Without ContentTypes in the js. doh.

yched’s picture

- We probably need some form validation to ensure a machine name is not reused ?

- minor:

+  function createTerm($vocabulary) {
     $term = new stdClass();
     $term->name = $this->randomName();
-    $term->vid = $vid;
+    $term->vid = $vocabulary->vid;
+    $term->machine_name = $vocabulary->machine_name;
     taxonomy_term_save($term);
     return $term;
   }

$term->machine_name is kind of misleading, it's the vocab machine name, not the term machine name

- Setting $term->machine_name is not required for taxonomy_term_save($term); to work, right ? If it's just to have createTerm() return a fully built $term, it might be best to set the property after the term_save() ? or return the result of a term_load() ?

Status: Needs review » Needs work

The last submitted patch failed testing.

Xano’s picture

I am in favour of using name for machine names and title for human-readable names. This should actually be done consistently in Drupal.

catch’s picture

yched: Validation - yeah probably.

$term->machine_name is kind of misleading, it's the vocab machine name, not the term machine name

Well yeah, but we face the same issue with anything else unless we call it something like $term->vocabulary_machine_name - which I nearly did, but seemed like unnecessary messing about to add the prefix for only that reason. This is the problem with node types not being first class objects whereas taxonomy vocabularies are, part of the reason I didn't want to tackle bundles in the initial patch.

Setting $term->machine_name is not required for taxonomy_term_save($term); to work, right ? If it's just to have createTerm() return a fully built $term, it might be best to set the property after the term_save() ? or return the result of a term_load() ?

taxonomy_term_save() calls field_attach_insert()/field_attach_update() which needs the bundle name in order to not explode. So yeah it is required. We could take the $vid in taxonomy_term_save(), load the vocabulary if machine_name isn't set, then assign it internally I guess - ideas welcome on the least annoying way to handle it.

Xano, maybe, but I'm absolutely not going to roll patch to do that in this issue, it'll mean this patch never ever gets in - $node->type to $node->name would make this a 200k patch. I'm also not convinced the change is worth it.

Xano’s picture

We can start in this issue by using title and name for the human-readable name and machine name respectively.

catch’s picture

But why do that when it's only going to affect taxonomy terms and vocabularies? Then it's not consistent with anything else in core, but requires a massive API change and an upgrade path.

catch’s picture

Status: Needs work » Needs review
FileSize
25.58 KB

Fixed the forum and blogapi test failures and an actual bug in vocabulary deletion.

catch’s picture

Another issue with title and name - for vocabularies - sure we could use title and name. But then for taxonomy terms, the 'name' is actually going to be loaded from the vocabulary->name - and terms won't have their own machine readable name, so might as well keep name. In other words a big minefield I don't want to get into if I can avoid it. The real semantic question here is "How do we deal with the fact that we don't want numeric bundles for terms, so need to load a machine readable name for the vocabulary into the term object?".

Current patch:

$vocabulary->name
$vocabulary->machine_name
$term->name
$term->machine_name = $vocabulary->machine_name

Slightly more semantic possibility, but not necessarily much nicer:

$vocabulary->name
$vocabulary->machine_name
$term->name
$term->vocabulary_machine_name

Let's do one of those, and look at unifying title/name/machine name in another issue.

Status: Needs review » Needs work

The last submitted patch failed testing.

yched’s picture

Status: Needs work » Needs review
FileSize
25.31 KB

re #33: I'd personally vote for the latter ($term->vocabulary_machine_name). Attached patch doesn't change this.

Updated patch:
- fixed taxonomy_load_vocabularies() -> taxonomy_get_vocabularies()
- fixed a couple 'taxonomy term' -> 'taxonomy_term' as $obj_type param in a few field_attach_*() calls
Also took care of the non-JS 'add more', as mentioned in #15:
- added multistep support to the term form, building on $form_state['term'] (the 'add more' button basically makes any form multistep),
- wrapped the "build $term from form values" part in a taxonomy_form_term_submit_builder() function, also called from the non-JS 'add more' handler.

And tested the feature to work just fine !

To test, create a vocab, give it the machine name 'test_vocab', and run the following code in a devel PHP block:

$field = array(
  'field_name' => 'term_field_multiple',
  'cardinality' => FIELD_CARDINALITY_UNLIMITED,
  'type' => 'text',
);
field_create_field($field);

$instance = array(
  'field_name' => 'term_field_multiple',
  'bundle' => 'test_vocab',
  'label' => 'Multiple',
);
field_create_instance($instance);
yched’s picture

Note that even with the cool vocab machine names, we still face the more general Field API issue of bundle names clashes - in short, trouble happens when users create a node type named 'user', or a vocab named 'page'.
This is discussed in #470242: Namespacing for bundle names and is an issue we already have with nodes, so I don't think it should hold this patch.

Status: Needs review » Needs work

The last submitted patch failed testing.

catch’s picture

Status: Needs work » Needs review
FileSize
26.47 KB

Re-rolled yched's patch to fix the last remaining test failures, and to use $term->vocabulary_machine_name instead of $term->machine_name for clarity.

Tested 6-7 upgrade path and no errors.

bjaspan’s picture

Subscribe. Note to self: Read the issue.

bjaspan’s picture

Review based on just reading the patch:

Adding a "Machine readable name" field to the vocabulary form whose description is "for internal use only" does not tell users anything about what it is for. If they really don't need to know what it is for, it should just be generated automatically and invisibly, based on the original voc name or something. I saw discussion of auto-generating machine names but do not see code for it. If we can't auto-generate them, or if that is a task for a separate issue, then we should at least improve the description for now.

Also, the restrictions on machine-readable names, if the form element is present at all, should be explained on the form itself, not as a
"gotcha" only when the form is validated.

So, perhaps: "The unique machine name for this vocabulary, used to select term theme templates. Can only contain lowercase letters, numbers, and underscores."

Why add a textfield vocabulary_machine_name element to the term form whose #access is always false?

It's not critical, but couldn't the update function use db_update()->expression() to do all vocabs at once instead of needing the loop?

Some test cases are converted from form submissions into API calls. I'm all in favor of API calls and testing them, but it does mean we are losing the test of the form unless the form is explicitly tested somewhere else (in which case, YAY for converting tests to API when they can be).

So long as the machine-name auto-generation/fixing the description comments are addressed by a followup issue, none of these are blockers. I'm not RTBC'ing to see what the comments on my review are, but I'm also not CNW'ing because I'm not sure it is warranted.

bjaspan’s picture

Oh, and I forgot to add: Nice work!

yched’s picture

Status: Needs review » Needs work

"couldn't the update function use db_update()->expression() to do all vocabs at once instead of needing the loop?"

I think we need the loop on vocabs to run field_attach_create_bundle() on each vocab - which is currently missing.
The function happens to do nothing with the default sql storage (which we can be sure will be the one in use when the update runs), so it has no serious impact, but technically, not calling it is wrong.
Or we need a comment to explicitly state we skip it.

So CNW at least for this.

catch’s picture

Status: Needs work » Needs review
FileSize
27.38 KB

@bjaspan - I added vocabulary.js to auto-generate the machine name same as content types per webchick, but didn't roll the last patch with -N, this one includes it. I'm happier having this exactly the same as content type names in terms of UI than removing it completely. Changed the help text though.

#access => FALSE - because I hate '#type' => 'value' - and if you don't have the form element in there, field_attach_form() will blow up in your face for not having a bundle name.

Tests - the UI is tested explicitly in the taxonomy tests for both vocabularies and terms, those tests date from when taxonomy_term_save() took a FAPI array and it was easier to use drupalPost() than the API calls, now it isn't, so better to clean up.

@yched: I actually added that in to the hook_update_N() but I think that was in a patch which never got posted :(.

Only changes in this one are the description on machine name, vocabulary.js actually being in the patch, and hook_update_N() calling field_attach_create_bundle(). Thanks for the reviews!

catch’s picture

FileSize
28.58 KB

Added tests for the vocabulary machine name validation (which also tests that it shows up in taxonomy_vocabulary_load() etc.) - given the dozens of test failures and exceptions which happen if you get a field_attach_*() call wrong I think we can say those are well tested elsewhere. Also update the Field API CHANGELOG.txt entry.

bjaspan’s picture

I do not see a diff for CHANGELOG.txt. Incidentally, CHANGELOG says of Field API:

* Provides a subset of the features of the Content Construction Kit (CCK) module.

I think "subset" is not necessarily accurate. :-)

catch’s picture

FileSize
28 KB

Hmm, fixed lack of changelog.txt diff. Subset's a bit wrong yeah, although only partially wrong until we've got a UI.

jredding’s picture

sorry all... subscribe :(

yched’s picture

Status: Needs review » Needs work

taxonomy_fieldable_info() is missing a 'bundles' entry, listing existing bundles - see http://api.drupal.org/api/function/hook_fieldable_info/7.

Aside from this, I don't think we have remaining issues keeping us from RTBC ? (can't set it myself, I took part in the patch...)

Side issue, should not hold this back: #488542: Tie Field UI pages to any fieldable entity

catch’s picture

Status: Needs work » Needs review
FileSize
29.31 KB

Added a taxonomy_vocabulary_machine_names() helper, with a test, and added this to taxonomy_fieldable_info(). Also found one stray line break. Should be pretty much ready now.

yched’s picture

Status: Needs review » Needs work

Sorry, the PHPdoc is actually not clear on that :-/. The format for 'bundles' should be

array(
  'machine_name' => 'Human name',
  ...
);
catch’s picture

Status: Needs work » Needs review
FileSize
29.34 KB

Ahh, didn't get that. Reworked it a bit.

yched’s picture

Thanks ! This is ready for me.

bjaspan’s picture

Status: Needs review » Reviewed & tested by the community
Dries’s picture

Awesome. I'll review this tomorrow morning.

Dries’s picture

1. What are some good use cases for this? In the issue description, we suggest that synonyms and related terms could be converted to fields but I'm wondering if there are better, more compelling examples. The use case I can think of is to associate an image with a term -- I believe Jeremy Andrews once started a module for that. Are there any other contributed modules that we could nuke? Any other creative ideas? Having a couple of really compelling ideas validates the need for this and avoids that we are over-engineering this just because we can -- the taxonomy system is freaking enough people out as it is. ;-)

2. Instead of flattening the namespace to avoid clashes (eg. $term->vocabulary_machine_name and $term->machine_name) we could consider using nested objects: $term->vocabulary->machine_name and $term->machine_name). I'm not demanding that we change this; just bringing it up for discussion. Feels like a better way to deal with this problem.

3. I'm wondering if andypost's issues in #16 have been addressed. I haven't try to reproduce his experiment.

4. Does this have any performance impact on node listing pages that have a lot of taxonomy terms? There are sites that are taxonomy heavy.

andypost’s picture

@Dries my experiment in #16 was proposed by catch, there's a help page http://drupal.org/node/474420
Suppose taxonomy fields should work as described there and it's a most quick way to test it!

catch’s picture

Dries:

#1. Here's some obvious candidates for nuking - I only got to page 10 of 34 on http://drupal.org/taxonomy/term/71

http://drupal.org/project/taxonomy_image
http://drupal.org/project/nat
http://drupal.org/project/category
http://drupal.org/project/taxonomy_enhancer
http://drupal.org/project/term_fields
http://drupal.org/project/taxonomy_vocab_relate
http://drupal.org/project/taxonomy_node

There's also obvious things like assigning geolocation to terms so you can show them in maps and geotag RSS feeds, which I think you can do from contrib at the moment, but not sure if it's part of location or a separate module.

2. If we do $term->vocabulary->machine_name we'd need to consider loading the full vocabulary object with every term load, at the moment it's just a join to get the machine name. I don't think that would have a massive performance impact with multiple load, but it'd add some weight. $term->machine_name - terms don't actually have machine names of their own, at least not yet - only a bundle name which has to come from the vocabulary. If it's OK I'd like to tackle this in a followup issue - this is the first fieldable object which has a 'bundle' other than nodes - and this patch highlights how that concept doesn't necessarily map well to our existing core APIs for other potentially fieldable objects.

3. I tried the same thing as andypost a few times and it always worked for me.

4. Taxonomy terms are multiple loaded on node listings, however the field cache doesn't currently have a way to take advantage of that - so it adds a cache_get() per term. There's a patch at #333171: Optimize the field cache (which has been RTBC for a while now) which takes that down to one query for the page, it'll also reduce queries for node listings without terms as well - since node_load_multiple() also means a cache_get per node for the field cache at the moment. So yes, but no (assuming that patch gets accepted).

scor’s picture

@Dries: I just started writing a patch to add a concept URI to taxonomy terms in line with the recent announcement of the new CommonTag format and part of the RDFa effort for Drupal 7. I'm not going into details here but in a nutshell, this would boost the linkage on the content on the web, and several web companies are involved in the consortium (including Yahoo! etc). Much like term_node, term_hierarchy, term_synonyms and term_relation, term_uri would be a good candidate for being a field.

catch’s picture

andypost asked in irc for example code for attaching a field to terms in a vocabulary. Tested this and it worked for me.

NB make sure the machine name for your 'Tags' vocabulary is 'tags' before or after running this code - the hook_update_N() plays it safe and tries to account for vocabulary names with non-roman characters etc.

$field = array(
  'field_name' => 'test',
  'type' => 'text',
  'cardinality' => 1, /* not necessary as it's the default.*/
);
field_create_field($field);

$instance = array(
  'field_name' => 'test',
  'bundle' => 'tags',
  'label' => t('Some text'),
  'weight' => 0,
  'widget' => array(
    'type' => 'text_textfield',
    'label' => t('Some text'),
  ),
);
field_create_instance($instance);
andypost’s picture

FileSize
15.73 KB

@catch Thanx a lot for example! screenshot attached
Only local images are allowed.

Using vocabulary->machine_name as bundle is more clear but why not 'vid_' . $term->vid?

Edited:
catch: andypost: lets you export field/bundle definitions between sites.
catch: andypost: also nicer for templates field-bundlename.tpl.php

yched’s picture

andypost's code in #16 didn't work because the $instance['bundle'] property ('taxonomy term') was wrong. It should be the machine name of the vocabulary.

re #60: see #3 - in short, numeric ids are evil when it comes to code portability between different sites, or between staged instances.
Similiar to the current node-[bundle (node type)].tpl.php template variants, we should have term-[bundle (vocab)].tpl.php (to be done in a followup patch), and having serial ids in template names is one road to hell. That's only one example.

Status: Reviewed & tested by the community » Needs work

The last submitted patch failed testing.

catch’s picture

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

CHANGELOG.txt conflict.

Dries’s picture

@catch: convincing list of example + we can worry about #57(2) later.

I'll commit this once the test bot came back with results.

Dries’s picture

Status: Reviewed & tested by the community » Fixed

Committed! Thanks.

yched’s picture

Two major field additions in a row. W00t !

Followup : #489834: Template for terms

catch’s picture

Status: Fixed » Reviewed & tested by the community

vocabulary.js didn't make it in.

catch’s picture

Status: Reviewed & tested by the community » Fixed

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

mlncn’s picture

Follow-up issue posted addressing goal 1: Convert taxonomy term subject and description to fields.

BenK’s picture

Keeping track of this thread...