[English] Drupal Tutorial: Auto-Tag with Token
Sometimes it happens that users who are posting some content on a community site forget to tag it, its annoying, right? Lets try to build small solution for this using Token module. Let me remind you what Token is for. Mostly its task is to provide API that gives an opportunity to use placeholders in big pieces of text, that will be replaced with token value during processing, for example %nid or [nid] will be replaced with node identifier.
So the plan is to specify list of tags that should be inserted automatically if user didn’t provide them or even add certain tags for special site needs, please note that tags would not be hard-coded, but preprocessed from the content that was inserted.
Okay, lets say Taxonomy and Token modules were enabled. Lets create new vocabulary called Tags and in settings mark it as Tag, ’story’ node type will be tagged.

Next step is to create simple settings form for administrator to define what tags should be inserted for new content. To help administrator, we can display him a list of all available tokens for nodes. For this we will use:
theme('token_help', $type);
in our case $type equals ‘node’, so the final code for helper administration form will be:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | /** * Menu callback for the token auto-tag settings form. */ function token_autotag_admin_settings() { $form['token_autotag']['token_autotag_pattern'] = array( '#type' => '<span class="misspell">textfield</span>', '#title' => t('Autotag pattern'), '#default_value' => variable_get('token_autotag_pattern', '[month], [language], token-autotag'), ); if (module_exists('token')) { $form['token_autotag']['token_help'] = array( '#title' => t('Replacement patterns'), '#type' => '<span class="misspell">fieldset</span>', '#collapsible' => TRUE, '#collapsed' => TRUE, '#description' => t('Prefer raw-text replacements for text to avoid problems with HTML entities!'), ); $form['token_autotag']['token_help']['help'] = array( '#value' => theme('token_help', 'node'), ); } return system_settings_form($form); } |

Default value for tagging was set to: current month, language of the post and ‘token-autotag’, later we will define more ‘clever’ tags, because at the moment we don’t know how to provide them ![]()
So we should check user input in Tags field and if it is empty - fill it with predefined pattern, for this we are going to implement hook_nodeapi() and
1 | token_replace($original, $type = 'global', $object = NULL, $leading = '[', $trailing = ']'); |
1 2 3 4 5 6 7 8 9 10 | /** * Implementation of hook_<span class="misspell">nodeapi</span>(). */ function token_autotag_nodeapi($node, $op) { if ($op == 'presave') { if (module_exists('token') && $node->taxonomy['tags'][1] == '') { $node->taxonomy['tags'][1] = token_replace(variable_get('token_autotag_pattern', '[month], [language], token-autotag'), 'node', $node); } } } |

It was easy. What’s next? Lets provide few new tokens that will be used for tagging content.
We will implement Token API hooks:
1 | hook_token_list($type = 'all'); |
This function is used to provide help and in-line documentation for all of the possible replacement tokens.
Note: $type indicates the context that token help is being generated for, so you should show ALL tokens at the same time if $type is ‘all’. As such, the help text should be keyed by the $type context your module will use when doing the actual replacements.
1 | hook_token_values($type, $object = NULL); |
This function should return a keyed array of placeholders, and their replacement values.
$type contains the current context — ‘node’, ‘user’, ‘global’, etc.
$object contains the specific node, user, etc. that should be used as the basis for the replacements.
For example, we are interested in :
1) what part of the day post was created
- 06:00 - 12:00 : ‘morning’;
- 12:00 - 20:00 : ‘day’;
- 20:00 - 24:00 : ‘evening’;
- 24:00 - 06:00 : ‘night’.
2) size of the post:
- less then 100 words : ‘note’;
- 100 - 1000 words : ‘article’;
- more then 1000 words : ‘narrative’.
1 2 3 4 5 6 7 8 9 10 | /** * Implementation of hook_token_list(). */ function token_autotag_token_list($type = 'all') { if ($type == 'node' || $type == 'all') { $tokens['node']['day-part'] = t("Part of the day, when post was created ('morning', 'day', 'everning', 'night')"); $tokens['node']['post-size-type'] = t("Node type based on size ('note', 'article', 'narrative')"); } return $tokens; } |
2 new tokens - [day-part] and [post-size-type] appeared in the placeholder tokens list, so we update configuration pattern

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | /** * Implementation of hook_token_values(). */ function token_autotag_token_values($type, $object = NULL) { $values = array(); switch ($type) { case 'node': $hour = (int)date('H', $date); $values['day-part'] = $hour < 6 ? 'night' : ($hour < 12 ? 'morning' : ($hour < 20 ? 'day' : ($hour < 24 ? 'everning' : 'night'))); // _token_autotag_get_post_words_amount - method that counts amount of numbers based on some logic $words_amount = _token_autotag_get_post_words_amount($node); $values['post-size-type'] = $words_amount < 100 ? 'note' : ($words_amount < 1000 ? 'article' : 'narrative'); break; } return $values; } |

That’s it! Now you can play with it and provide some new features like give a user opportunity to put placeholders into tag field, specify tag tokens which will mark all nodes even if user inputed few, etc.
If you need real relevant auto-tag utility you can take a look on Taxonomy Autotagger which can automatically tag a node with terms from a vocabulary that the node’s content type is associated with if the terms (or the terms’ synonyms) are found in the content of the node itself. And by the way, now you can build placeholder token that will call Taxonomy Autotagger methods to generate tags and put it in Tag field with your predefined tokens

< Voir le site
In addition, I would also suggest to take a look over Open Calais suite of modules that enable amazing features based on this Reuters’ ontology API. http://drupal.org/project/opencalais and http://www.opencalais.com/
Hi,
I have created a custom type in drupal. I have a lot of documents which are of the same type. These documents (Word docs) can be converted to .htm files. I want to extract certain data from the .htm files and replace them in the custom type in drupal.
The custom type will naturally have fixed place holders with default value as empty. Using hook_cron I can pick up the .htm files from a directory and parse through them to get the data. But I am confused as to how to set the token values. Could you share your views on this?
Hi Jason,
Why do you need tokens ? For what I understood, your needs are to extract some data from HTML files and save it into Drupal’s nodes. Usually tokens are used as kind of variables which are replaced by their calculated values…
Bonjopur, J’mapelle andre, j’etudiet francais dix ans avant, mais mon francais est horible….
anyway I live in Chicago and I’m doin a social network site with drupal taxonomy - I’m almost done but I really need just a little push to finish - specifically , I’m trying to implement this token auto-tagging, by copying the code to my template.php is there any reason that this is not working for me, am I not supposed to be using the template.php from my theme folder?
any help would be great, thanks,
drew wasserman
druzi-design.net
Hi, many thanks for this, it is perfect for my simple needs. Just one thing which I discovered is that when assigning to the ['tags'] array the key is in fact the vid (vocabulary id) to which you want to add the term. This had me baffled for a while as I had deleted my original vocabularies which meant the vid of my first vocabulary was 15 or so. Something like this fixed the issue (assuming you assign the content type to the vocab):
$vids = array_keys (taxonomy_get_vocabularies($node->type));
Then I could use the first key as my vid (a little crude if you have a complex taxonomy - but perfect for a simple one;) i.e.
$node->taxonomy['tags'][ $vids[0] ] = …
Drew: you need to create a module and add the above into a module - not do it in the template.
Many Thanks, Steve.