annotate modules/taxonomy/taxonomy.module @ 2:85b5b336180c

Added tag 6.0 for changeset c1f4ac30525a
author Franck Deroche <webmaster@defr.org>
date Tue, 23 Dec 2008 14:28:28 +0100
parents c1f4ac30525a
children 2427550111ae
rev   line source
webmaster@1 1 <?php
webmaster@1 2 // $Id: taxonomy.module,v 1.414 2008/01/27 17:55:15 goba Exp $
webmaster@1 3
webmaster@1 4 /**
webmaster@1 5 * @file
webmaster@1 6 * Enables the organization of content into categories.
webmaster@1 7 */
webmaster@1 8
webmaster@1 9 /**
webmaster@1 10 * Implementation of hook_perm().
webmaster@1 11 */
webmaster@1 12 function taxonomy_perm() {
webmaster@1 13 return array('administer taxonomy');
webmaster@1 14 }
webmaster@1 15
webmaster@1 16 /**
webmaster@1 17 * Implementation of hook_theme()
webmaster@1 18 */
webmaster@1 19 function taxonomy_theme() {
webmaster@1 20 return array(
webmaster@1 21 'taxonomy_term_select' => array(
webmaster@1 22 'arguments' => array('element' => NULL),
webmaster@1 23 ),
webmaster@1 24 'taxonomy_term_page' => array(
webmaster@1 25 'arguments' => array('tids' => array(), 'result' => NULL),
webmaster@1 26 ),
webmaster@1 27 'taxonomy_overview_vocabularies' => array(
webmaster@1 28 'arguments' => array('form' => array()),
webmaster@1 29 ),
webmaster@1 30 'taxonomy_overview_terms' => array(
webmaster@1 31 'arguments' => array('form' => array()),
webmaster@1 32 ),
webmaster@1 33 );
webmaster@1 34 }
webmaster@1 35
webmaster@1 36 /**
webmaster@1 37 * Implementation of hook_link().
webmaster@1 38 *
webmaster@1 39 * This hook is extended with $type = 'taxonomy terms' to allow themes to
webmaster@1 40 * print lists of terms associated with a node. Themes can print taxonomy
webmaster@1 41 * links with:
webmaster@1 42 *
webmaster@1 43 * if (module_exists('taxonomy')) {
webmaster@1 44 * $terms = taxonomy_link('taxonomy terms', $node);
webmaster@1 45 * print theme('links', $terms);
webmaster@1 46 * }
webmaster@1 47 */
webmaster@1 48 function taxonomy_link($type, $node = NULL) {
webmaster@1 49 if ($type == 'taxonomy terms' && $node != NULL) {
webmaster@1 50 $links = array();
webmaster@1 51 // If previewing, the terms must be converted to objects first.
webmaster@1 52 if ($node->build_mode == NODE_BUILD_PREVIEW) {
webmaster@1 53 $node->taxonomy = taxonomy_preview_terms($node);
webmaster@1 54 }
webmaster@1 55 if (!empty($node->taxonomy)) {
webmaster@1 56 foreach ($node->taxonomy as $term) {
webmaster@1 57 // During preview the free tagging terms are in an array unlike the
webmaster@1 58 // other terms which are objects. So we have to check if a $term
webmaster@1 59 // is an object or not.
webmaster@1 60 if (is_object($term)) {
webmaster@1 61 $links['taxonomy_term_'. $term->tid] = array(
webmaster@1 62 'title' => $term->name,
webmaster@1 63 'href' => taxonomy_term_path($term),
webmaster@1 64 'attributes' => array('rel' => 'tag', 'title' => strip_tags($term->description))
webmaster@1 65 );
webmaster@1 66 }
webmaster@1 67 // Previewing free tagging terms; we don't link them because the
webmaster@1 68 // term-page might not exist yet.
webmaster@1 69 else {
webmaster@1 70 foreach ($term as $free_typed) {
webmaster@1 71 $typed_terms = drupal_explode_tags($free_typed);
webmaster@1 72 foreach ($typed_terms as $typed_term) {
webmaster@1 73 $links['taxonomy_preview_term_'. $typed_term] = array(
webmaster@1 74 'title' => $typed_term,
webmaster@1 75 );
webmaster@1 76 }
webmaster@1 77 }
webmaster@1 78 }
webmaster@1 79 }
webmaster@1 80 }
webmaster@1 81
webmaster@1 82 // We call this hook again because some modules and themes
webmaster@1 83 // call taxonomy_link('taxonomy terms') directly.
webmaster@1 84 drupal_alter('link', $links, $node);
webmaster@1 85
webmaster@1 86 return $links;
webmaster@1 87 }
webmaster@1 88 }
webmaster@1 89
webmaster@1 90 /**
webmaster@1 91 * For vocabularies not maintained by taxonomy.module, give the maintaining
webmaster@1 92 * module a chance to provide a path for terms in that vocabulary.
webmaster@1 93 *
webmaster@1 94 * @param $term
webmaster@1 95 * A term object.
webmaster@1 96 * @return
webmaster@1 97 * An internal Drupal path.
webmaster@1 98 */
webmaster@1 99
webmaster@1 100 function taxonomy_term_path($term) {
webmaster@1 101 $vocabulary = taxonomy_vocabulary_load($term->vid);
webmaster@1 102 if ($vocabulary->module != 'taxonomy' && $path = module_invoke($vocabulary->module, 'term_path', $term)) {
webmaster@1 103 return $path;
webmaster@1 104 }
webmaster@1 105 return 'taxonomy/term/'. $term->tid;
webmaster@1 106 }
webmaster@1 107
webmaster@1 108 /**
webmaster@1 109 * Implementation of hook_menu().
webmaster@1 110 */
webmaster@1 111 function taxonomy_menu() {
webmaster@1 112 $items['admin/content/taxonomy'] = array(
webmaster@1 113 'title' => 'Taxonomy',
webmaster@1 114 'description' => 'Manage tagging, categorization, and classification of your content.',
webmaster@1 115 'page callback' => 'drupal_get_form',
webmaster@1 116 'page arguments' => array('taxonomy_overview_vocabularies'),
webmaster@1 117 'access arguments' => array('administer taxonomy'),
webmaster@1 118 'file' => 'taxonomy.admin.inc',
webmaster@1 119 );
webmaster@1 120
webmaster@1 121 $items['admin/content/taxonomy/list'] = array(
webmaster@1 122 'title' => 'List',
webmaster@1 123 'type' => MENU_DEFAULT_LOCAL_TASK,
webmaster@1 124 'weight' => -10,
webmaster@1 125 );
webmaster@1 126
webmaster@1 127 $items['admin/content/taxonomy/add/vocabulary'] = array(
webmaster@1 128 'title' => 'Add vocabulary',
webmaster@1 129 'page callback' => 'drupal_get_form',
webmaster@1 130 'page arguments' => array('taxonomy_form_vocabulary'),
webmaster@1 131 'type' => MENU_LOCAL_TASK,
webmaster@1 132 'parent' => 'admin/content/taxonomy',
webmaster@1 133 'file' => 'taxonomy.admin.inc',
webmaster@1 134 );
webmaster@1 135
webmaster@1 136 $items['admin/content/taxonomy/edit/vocabulary/%taxonomy_vocabulary'] = array(
webmaster@1 137 'title' => 'Edit vocabulary',
webmaster@1 138 'page callback' => 'taxonomy_admin_vocabulary_edit',
webmaster@1 139 'page arguments' => array(5),
webmaster@1 140 'type' => MENU_CALLBACK,
webmaster@1 141 'file' => 'taxonomy.admin.inc',
webmaster@1 142 );
webmaster@1 143
webmaster@1 144 $items['admin/content/taxonomy/edit/term'] = array(
webmaster@1 145 'title' => 'Edit term',
webmaster@1 146 'page callback' => 'taxonomy_admin_term_edit',
webmaster@1 147 'type' => MENU_CALLBACK,
webmaster@1 148 'file' => 'taxonomy.admin.inc',
webmaster@1 149 );
webmaster@1 150
webmaster@1 151 $items['taxonomy/term/%'] = array(
webmaster@1 152 'title' => 'Taxonomy term',
webmaster@1 153 'page callback' => 'taxonomy_term_page',
webmaster@1 154 'page arguments' => array(2),
webmaster@1 155 'access arguments' => array('access content'),
webmaster@1 156 'type' => MENU_CALLBACK,
webmaster@1 157 'file' => 'taxonomy.pages.inc',
webmaster@1 158 );
webmaster@1 159
webmaster@1 160 $items['taxonomy/autocomplete'] = array(
webmaster@1 161 'title' => 'Autocomplete taxonomy',
webmaster@1 162 'page callback' => 'taxonomy_autocomplete',
webmaster@1 163 'access arguments' => array('access content'),
webmaster@1 164 'type' => MENU_CALLBACK,
webmaster@1 165 'file' => 'taxonomy.pages.inc',
webmaster@1 166 );
webmaster@1 167 $items['admin/content/taxonomy/%taxonomy_vocabulary'] = array(
webmaster@1 168 'title' => 'List terms',
webmaster@1 169 'page callback' => 'drupal_get_form',
webmaster@1 170 'page arguments' => array('taxonomy_overview_terms', 3),
webmaster@1 171 'access arguments' => array('administer taxonomy'),
webmaster@1 172 'type' => MENU_CALLBACK,
webmaster@1 173 'file' => 'taxonomy.admin.inc',
webmaster@1 174 );
webmaster@1 175
webmaster@1 176 $items['admin/content/taxonomy/%taxonomy_vocabulary/list'] = array(
webmaster@1 177 'title' => 'List',
webmaster@1 178 'type' => MENU_DEFAULT_LOCAL_TASK,
webmaster@1 179 'weight' => -10,
webmaster@1 180 );
webmaster@1 181
webmaster@1 182 $items['admin/content/taxonomy/%taxonomy_vocabulary/add/term'] = array(
webmaster@1 183 'title' => 'Add term',
webmaster@1 184 'page callback' => 'taxonomy_add_term_page',
webmaster@1 185 'page arguments' => array(3),
webmaster@1 186 'type' => MENU_LOCAL_TASK,
webmaster@1 187 'parent' => 'admin/content/taxonomy/%taxonomy_vocabulary',
webmaster@1 188 'file' => 'taxonomy.admin.inc',
webmaster@1 189 );
webmaster@1 190
webmaster@1 191 return $items;
webmaster@1 192 }
webmaster@1 193
webmaster@1 194 function taxonomy_save_vocabulary(&$edit) {
webmaster@1 195 $edit['nodes'] = empty($edit['nodes']) ? array() : $edit['nodes'];
webmaster@1 196
webmaster@1 197 if (!isset($edit['module'])) {
webmaster@1 198 $edit['module'] = 'taxonomy';
webmaster@1 199 }
webmaster@1 200
webmaster@1 201 if (!empty($edit['vid']) && !empty($edit['name'])) {
webmaster@1 202 drupal_write_record('vocabulary', $edit, 'vid');
webmaster@1 203 db_query("DELETE FROM {vocabulary_node_types} WHERE vid = %d", $edit['vid']);
webmaster@1 204 foreach ($edit['nodes'] as $type => $selected) {
webmaster@1 205 db_query("INSERT INTO {vocabulary_node_types} (vid, type) VALUES (%d, '%s')", $edit['vid'], $type);
webmaster@1 206 }
webmaster@1 207 module_invoke_all('taxonomy', 'update', 'vocabulary', $edit);
webmaster@1 208 $status = SAVED_UPDATED;
webmaster@1 209 }
webmaster@1 210 else if (!empty($edit['vid'])) {
webmaster@1 211 $status = taxonomy_del_vocabulary($edit['vid']);
webmaster@1 212 }
webmaster@1 213 else {
webmaster@1 214 drupal_write_record('vocabulary', $edit);
webmaster@1 215 foreach ($edit['nodes'] as $type => $selected) {
webmaster@1 216 db_query("INSERT INTO {vocabulary_node_types} (vid, type) VALUES (%d, '%s')", $edit['vid'], $type);
webmaster@1 217 }
webmaster@1 218 module_invoke_all('taxonomy', 'insert', 'vocabulary', $edit);
webmaster@1 219 $status = SAVED_NEW;
webmaster@1 220 }
webmaster@1 221
webmaster@1 222 cache_clear_all();
webmaster@1 223
webmaster@1 224 return $status;
webmaster@1 225 }
webmaster@1 226
webmaster@1 227 /**
webmaster@1 228 * Delete a vocabulary.
webmaster@1 229 *
webmaster@1 230 * @param $vid
webmaster@1 231 * A vocabulary ID.
webmaster@1 232 * @return
webmaster@1 233 * Constant indicating items were deleted.
webmaster@1 234 */
webmaster@1 235 function taxonomy_del_vocabulary($vid) {
webmaster@1 236 $vocabulary = (array) taxonomy_vocabulary_load($vid);
webmaster@1 237
webmaster@1 238 db_query('DELETE FROM {vocabulary} WHERE vid = %d', $vid);
webmaster@1 239 db_query('DELETE FROM {vocabulary_node_types} WHERE vid = %d', $vid);
webmaster@1 240 $result = db_query('SELECT tid FROM {term_data} WHERE vid = %d', $vid);
webmaster@1 241 while ($term = db_fetch_object($result)) {
webmaster@1 242 taxonomy_del_term($term->tid);
webmaster@1 243 }
webmaster@1 244
webmaster@1 245 module_invoke_all('taxonomy', 'delete', 'vocabulary', $vocabulary);
webmaster@1 246
webmaster@1 247 cache_clear_all();
webmaster@1 248
webmaster@1 249 return SAVED_DELETED;
webmaster@1 250 }
webmaster@1 251
webmaster@1 252 /**
webmaster@1 253 * Dynamicly check and update the hierarachy flag of a vocabulary.
webmaster@1 254 *
webmaster@1 255 * Checks the current parents of all terms in a vocabulary and updates the
webmaster@1 256 * vocabularies hierarchy setting to the lowest possible level. A hierarchy with
webmaster@1 257 * no parents in any of its terms will be given a hierarchy of 0. If terms
webmaster@1 258 * contain at most a single parent, the vocabulary will be given a hierarchy of
webmaster@1 259 * 1. If any term contain multiple parents, the vocabulary will be given a
webmaster@1 260 * hieararchy of 2.
webmaster@1 261 *
webmaster@1 262 * @param $vocabulary
webmaster@1 263 * An array of the vocabulary structure.
webmaster@1 264 * @param $changed_term
webmaster@1 265 * An array of the term structure that was updated.
webmaster@1 266 */
webmaster@1 267 function taxonomy_check_vocabulary_hierarchy($vocabulary, $changed_term) {
webmaster@1 268 $tree = taxonomy_get_tree($vocabulary['vid']);
webmaster@1 269 $hierarchy = 0;
webmaster@1 270 foreach ($tree as $term) {
webmaster@1 271 // Update the changed term with the new parent value before comparision.
webmaster@1 272 if ($term->tid == $changed_term['tid']) {
webmaster@1 273 $term = (object)$changed_term;
webmaster@1 274 $term->parents = $term->parent;
webmaster@1 275 }
webmaster@1 276 // Check this term's parent count.
webmaster@1 277 if (count($term->parents) > 1) {
webmaster@1 278 $hierarchy = 2;
webmaster@1 279 break;
webmaster@1 280 }
webmaster@1 281 elseif (count($term->parents) == 1 && 0 !== array_shift($term->parents)) {
webmaster@1 282 $hierarchy = 1;
webmaster@1 283 }
webmaster@1 284 }
webmaster@1 285 if ($hierarchy != $vocabulary['hierarchy']) {
webmaster@1 286 $vocabulary['hierarchy'] = $hierarchy;
webmaster@1 287 taxonomy_save_vocabulary($vocabulary);
webmaster@1 288 }
webmaster@1 289
webmaster@1 290 return $hierarchy;
webmaster@1 291 }
webmaster@1 292
webmaster@1 293 /**
webmaster@1 294 * Helper function for taxonomy_form_term_submit().
webmaster@1 295 *
webmaster@1 296 * @param $form_state['values']
webmaster@1 297 * @return
webmaster@1 298 * Status constant indicating if term was inserted or updated.
webmaster@1 299 */
webmaster@1 300 function taxonomy_save_term(&$form_values) {
webmaster@1 301 $form_values += array(
webmaster@1 302 'description' => '',
webmaster@1 303 'weight' => 0
webmaster@1 304 );
webmaster@1 305
webmaster@1 306 if (!empty($form_values['tid']) && $form_values['name']) {
webmaster@1 307 drupal_write_record('term_data', $form_values, 'tid');
webmaster@1 308 $hook = 'update';
webmaster@1 309 $status = SAVED_UPDATED;
webmaster@1 310 }
webmaster@1 311 else if (!empty($form_values['tid'])) {
webmaster@1 312 return taxonomy_del_term($form_values['tid']);
webmaster@1 313 }
webmaster@1 314 else {
webmaster@1 315 drupal_write_record('term_data', $form_values);
webmaster@1 316 $hook = 'insert';
webmaster@1 317 $status = SAVED_NEW;
webmaster@1 318 }
webmaster@1 319
webmaster@1 320 db_query('DELETE FROM {term_relation} WHERE tid1 = %d OR tid2 = %d', $form_values['tid'], $form_values['tid']);
webmaster@1 321 if (!empty($form_values['relations'])) {
webmaster@1 322 foreach ($form_values['relations'] as $related_id) {
webmaster@1 323 if ($related_id != 0) {
webmaster@1 324 db_query('INSERT INTO {term_relation} (tid1, tid2) VALUES (%d, %d)', $form_values['tid'], $related_id);
webmaster@1 325 }
webmaster@1 326 }
webmaster@1 327 }
webmaster@1 328
webmaster@1 329 db_query('DELETE FROM {term_hierarchy} WHERE tid = %d', $form_values['tid']);
webmaster@1 330 if (!isset($form_values['parent']) || empty($form_values['parent'])) {
webmaster@1 331 $form_values['parent'] = array(0);
webmaster@1 332 }
webmaster@1 333 if (is_array($form_values['parent'])) {
webmaster@1 334 foreach ($form_values['parent'] as $parent) {
webmaster@1 335 if (is_array($parent)) {
webmaster@1 336 foreach ($parent as $tid) {
webmaster@1 337 db_query('INSERT INTO {term_hierarchy} (tid, parent) VALUES (%d, %d)', $form_values['tid'], $tid);
webmaster@1 338 }
webmaster@1 339 }
webmaster@1 340 else {
webmaster@1 341 db_query('INSERT INTO {term_hierarchy} (tid, parent) VALUES (%d, %d)', $form_values['tid'], $parent);
webmaster@1 342 }
webmaster@1 343 }
webmaster@1 344 }
webmaster@1 345 else {
webmaster@1 346 db_query('INSERT INTO {term_hierarchy} (tid, parent) VALUES (%d, %d)', $form_values['tid'], $form_values['parent']);
webmaster@1 347 }
webmaster@1 348
webmaster@1 349 db_query('DELETE FROM {term_synonym} WHERE tid = %d', $form_values['tid']);
webmaster@1 350 if (!empty($form_values['synonyms'])) {
webmaster@1 351 foreach (explode ("\n", str_replace("\r", '', $form_values['synonyms'])) as $synonym) {
webmaster@1 352 if ($synonym) {
webmaster@1 353 db_query("INSERT INTO {term_synonym} (tid, name) VALUES (%d, '%s')", $form_values['tid'], chop($synonym));
webmaster@1 354 }
webmaster@1 355 }
webmaster@1 356 }
webmaster@1 357
webmaster@1 358 if (isset($hook)) {
webmaster@1 359 module_invoke_all('taxonomy', $hook, 'term', $form_values);
webmaster@1 360 }
webmaster@1 361
webmaster@1 362 cache_clear_all();
webmaster@1 363
webmaster@1 364 return $status;
webmaster@1 365 }
webmaster@1 366
webmaster@1 367 /**
webmaster@1 368 * Delete a term.
webmaster@1 369 *
webmaster@1 370 * @param $tid
webmaster@1 371 * The term ID.
webmaster@1 372 * @return
webmaster@1 373 * Status constant indicating deletion.
webmaster@1 374 */
webmaster@1 375 function taxonomy_del_term($tid) {
webmaster@1 376 $tids = array($tid);
webmaster@1 377 while ($tids) {
webmaster@1 378 $children_tids = $orphans = array();
webmaster@1 379 foreach ($tids as $tid) {
webmaster@1 380 // See if any of the term's children are about to be become orphans:
webmaster@1 381 if ($children = taxonomy_get_children($tid)) {
webmaster@1 382 foreach ($children as $child) {
webmaster@1 383 // If the term has multiple parents, we don't delete it.
webmaster@1 384 $parents = taxonomy_get_parents($child->tid);
webmaster@1 385 if (count($parents) == 1) {
webmaster@1 386 $orphans[] = $child->tid;
webmaster@1 387 }
webmaster@1 388 }
webmaster@1 389 }
webmaster@1 390
webmaster@1 391 $term = (array) taxonomy_get_term($tid);
webmaster@1 392
webmaster@1 393 db_query('DELETE FROM {term_data} WHERE tid = %d', $tid);
webmaster@1 394 db_query('DELETE FROM {term_hierarchy} WHERE tid = %d', $tid);
webmaster@1 395 db_query('DELETE FROM {term_relation} WHERE tid1 = %d OR tid2 = %d', $tid, $tid);
webmaster@1 396 db_query('DELETE FROM {term_synonym} WHERE tid = %d', $tid);
webmaster@1 397 db_query('DELETE FROM {term_node} WHERE tid = %d', $tid);
webmaster@1 398
webmaster@1 399 module_invoke_all('taxonomy', 'delete', 'term', $term);
webmaster@1 400 }
webmaster@1 401
webmaster@1 402 $tids = $orphans;
webmaster@1 403 }
webmaster@1 404
webmaster@1 405 cache_clear_all();
webmaster@1 406
webmaster@1 407 return SAVED_DELETED;
webmaster@1 408 }
webmaster@1 409
webmaster@1 410 /**
webmaster@1 411 * Generate a form element for selecting terms from a vocabulary.
webmaster@1 412 */
webmaster@1 413 function taxonomy_form($vid, $value = 0, $help = NULL, $name = 'taxonomy') {
webmaster@1 414 $vocabulary = taxonomy_vocabulary_load($vid);
webmaster@1 415 $help = ($help) ? $help : $vocabulary->help;
webmaster@1 416
webmaster@1 417 if (!$vocabulary->multiple) {
webmaster@1 418 $blank = ($vocabulary->required) ? t('- Please choose -') : t('- None selected -');
webmaster@1 419 }
webmaster@1 420 else {
webmaster@1 421 $blank = ($vocabulary->required) ? 0 : t('- None -');
webmaster@1 422 }
webmaster@1 423
webmaster@1 424 return _taxonomy_term_select(check_plain($vocabulary->name), $name, $value, $vid, $help, intval($vocabulary->multiple), $blank);
webmaster@1 425 }
webmaster@1 426
webmaster@1 427 /**
webmaster@1 428 * Generate a set of options for selecting a term from all vocabularies.
webmaster@1 429 */
webmaster@1 430 function taxonomy_form_all($free_tags = 0) {
webmaster@1 431 $vocabularies = taxonomy_get_vocabularies();
webmaster@1 432 $options = array();
webmaster@1 433 foreach ($vocabularies as $vid => $vocabulary) {
webmaster@1 434 if ($vocabulary->tags && !$free_tags) { continue; }
webmaster@1 435 $tree = taxonomy_get_tree($vid);
webmaster@1 436 if ($tree && (count($tree) > 0)) {
webmaster@1 437 $options[$vocabulary->name] = array();
webmaster@1 438 foreach ($tree as $term) {
webmaster@1 439 $options[$vocabulary->name][$term->tid] = str_repeat('-', $term->depth) . $term->name;
webmaster@1 440 }
webmaster@1 441 }
webmaster@1 442 }
webmaster@1 443 return $options;
webmaster@1 444 }
webmaster@1 445
webmaster@1 446 /**
webmaster@1 447 * Return an array of all vocabulary objects.
webmaster@1 448 *
webmaster@1 449 * @param $type
webmaster@1 450 * If set, return only those vocabularies associated with this node type.
webmaster@1 451 */
webmaster@1 452 function taxonomy_get_vocabularies($type = NULL) {
webmaster@1 453 if ($type) {
webmaster@1 454 $result = db_query(db_rewrite_sql("SELECT v.vid, v.*, n.type FROM {vocabulary} v LEFT JOIN {vocabulary_node_types} n ON v.vid = n.vid WHERE n.type = '%s' ORDER BY v.weight, v.name", 'v', 'vid'), $type);
webmaster@1 455 }
webmaster@1 456 else {
webmaster@1 457 $result = db_query(db_rewrite_sql('SELECT v.*, n.type FROM {vocabulary} v LEFT JOIN {vocabulary_node_types} n ON v.vid = n.vid ORDER BY v.weight, v.name', 'v', 'vid'));
webmaster@1 458 }
webmaster@1 459
webmaster@1 460 $vocabularies = array();
webmaster@1 461 $node_types = array();
webmaster@1 462 while ($voc = db_fetch_object($result)) {
webmaster@1 463 // If no node types are associated with a vocabulary, the LEFT JOIN will
webmaster@1 464 // return a NULL value for type.
webmaster@1 465 if (isset($voc->type)) {
webmaster@1 466 $node_types[$voc->vid][$voc->type] = $voc->type;
webmaster@1 467 unset($voc->type);
webmaster@1 468 $voc->nodes = $node_types[$voc->vid];
webmaster@1 469 }
webmaster@1 470 elseif (!isset($voc->nodes)) {
webmaster@1 471 $voc->nodes = array();
webmaster@1 472 }
webmaster@1 473 $vocabularies[$voc->vid] = $voc;
webmaster@1 474 }
webmaster@1 475
webmaster@1 476 return $vocabularies;
webmaster@1 477 }
webmaster@1 478
webmaster@1 479 /**
webmaster@1 480 * Implementation of hook_form_alter().
webmaster@1 481 * Generate a form for selecting terms to associate with a node.
webmaster@1 482 * We check for taxonomy_override_selector before loading the full
webmaster@1 483 * vocabulary, so contrib modules can intercept before hook_form_alter
webmaster@1 484 * and provide scalable alternatives.
webmaster@1 485 */
webmaster@1 486 function taxonomy_form_alter(&$form, $form_state, $form_id) {
webmaster@1 487 if (isset($form['type']) && isset($form['#node']) && (!variable_get('taxonomy_override_selector', FALSE)) && $form['type']['#value'] .'_node_form' == $form_id) {
webmaster@1 488 $node = $form['#node'];
webmaster@1 489
webmaster@1 490 if (!isset($node->taxonomy)) {
webmaster@1 491 $terms = empty($node->nid) ? array() : taxonomy_node_get_terms($node);
webmaster@1 492 }
webmaster@1 493 else {
webmaster@1 494 // After preview the terms must be converted to objects.
webmaster@1 495 if (isset($form_state['node_preview'])) {
webmaster@1 496 $node->taxonomy = taxonomy_preview_terms($node);
webmaster@1 497 }
webmaster@1 498 $terms = $node->taxonomy;
webmaster@1 499 }
webmaster@1 500
webmaster@1 501 $c = db_query(db_rewrite_sql("SELECT v.* FROM {vocabulary} v INNER JOIN {vocabulary_node_types} n ON v.vid = n.vid WHERE n.type = '%s' ORDER BY v.weight, v.name", 'v', 'vid'), $node->type);
webmaster@1 502
webmaster@1 503 while ($vocabulary = db_fetch_object($c)) {
webmaster@1 504 if ($vocabulary->tags) {
webmaster@1 505 if (isset($form_state['node_preview'])) {
webmaster@1 506 // Typed string can be changed by the user before preview,
webmaster@1 507 // so we just insert the tags directly as provided in the form.
webmaster@1 508 $typed_string = $node->taxonomy['tags'][$vocabulary->vid];
webmaster@1 509 }
webmaster@1 510 else {
webmaster@1 511 $typed_string = taxonomy_implode_tags($terms, $vocabulary->vid) . (array_key_exists('tags', $terms) ? $terms['tags'][$vocabulary->vid] : NULL);
webmaster@1 512 }
webmaster@1 513 if ($vocabulary->help) {
webmaster@1 514 $help = $vocabulary->help;
webmaster@1 515 }
webmaster@1 516 else {
webmaster@1 517 $help = t('A comma-separated list of terms describing this content. Example: funny, bungee jumping, "Company, Inc.".');
webmaster@1 518 }
webmaster@1 519 $form['taxonomy']['tags'][$vocabulary->vid] = array('#type' => 'textfield',
webmaster@1 520 '#title' => $vocabulary->name,
webmaster@1 521 '#description' => $help,
webmaster@1 522 '#required' => $vocabulary->required,
webmaster@1 523 '#default_value' => $typed_string,
webmaster@1 524 '#autocomplete_path' => 'taxonomy/autocomplete/'. $vocabulary->vid,
webmaster@1 525 '#weight' => $vocabulary->weight,
webmaster@1 526 '#maxlength' => 255,
webmaster@1 527 );
webmaster@1 528 }
webmaster@1 529 else {
webmaster@1 530 // Extract terms belonging to the vocabulary in question.
webmaster@1 531 $default_terms = array();
webmaster@1 532 foreach ($terms as $term) {
webmaster@1 533 // Free tagging has no default terms and also no vid after preview.
webmaster@1 534 if (isset($term->vid) && $term->vid == $vocabulary->vid) {
webmaster@1 535 $default_terms[$term->tid] = $term;
webmaster@1 536 }
webmaster@1 537 }
webmaster@1 538 $form['taxonomy'][$vocabulary->vid] = taxonomy_form($vocabulary->vid, array_keys($default_terms), $vocabulary->help);
webmaster@1 539 $form['taxonomy'][$vocabulary->vid]['#weight'] = $vocabulary->weight;
webmaster@1 540 $form['taxonomy'][$vocabulary->vid]['#required'] = $vocabulary->required;
webmaster@1 541 }
webmaster@1 542 }
webmaster@1 543 if (!empty($form['taxonomy']) && is_array($form['taxonomy'])) {
webmaster@1 544 if (count($form['taxonomy']) > 1) {
webmaster@1 545 // Add fieldset only if form has more than 1 element.
webmaster@1 546 $form['taxonomy'] += array(
webmaster@1 547 '#type' => 'fieldset',
webmaster@1 548 '#title' => t('Vocabularies'),
webmaster@1 549 '#collapsible' => TRUE,
webmaster@1 550 '#collapsed' => FALSE,
webmaster@1 551 );
webmaster@1 552 }
webmaster@1 553 $form['taxonomy']['#weight'] = -3;
webmaster@1 554 $form['taxonomy']['#tree'] = TRUE;
webmaster@1 555 }
webmaster@1 556 }
webmaster@1 557 }
webmaster@1 558
webmaster@1 559 /**
webmaster@1 560 * Helper function to convert terms after a preview.
webmaster@1 561 *
webmaster@1 562 * After preview the tags are an array instead of proper objects. This function
webmaster@1 563 * converts them back to objects with the exception of 'free tagging' terms,
webmaster@1 564 * because new tags can be added by the user before preview and those do not
webmaster@1 565 * yet exist in the database. We therefore save those tags as a string so
webmaster@1 566 * we can fill the form again after the preview.
webmaster@1 567 */
webmaster@1 568 function taxonomy_preview_terms($node) {
webmaster@1 569 $taxonomy = array();
webmaster@1 570 if (isset($node->taxonomy)) {
webmaster@1 571 foreach ($node->taxonomy as $key => $term) {
webmaster@1 572 unset($node->taxonomy[$key]);
webmaster@1 573 // A 'Multiple select' and a 'Free tagging' field returns an array.
webmaster@1 574 if (is_array($term)) {
webmaster@1 575 foreach ($term as $tid) {
webmaster@1 576 if ($key == 'tags') {
webmaster@1 577 // Free tagging; the values will be saved for later as strings
webmaster@1 578 // instead of objects to fill the form again.
webmaster@1 579 $taxonomy['tags'] = $term;
webmaster@1 580 }
webmaster@1 581 else {
webmaster@1 582 $taxonomy[$tid] = taxonomy_get_term($tid);
webmaster@1 583 }
webmaster@1 584 }
webmaster@1 585 }
webmaster@1 586 // A 'Single select' field returns the term id.
webmaster@1 587 elseif ($term) {
webmaster@1 588 $taxonomy[$term] = taxonomy_get_term($term);
webmaster@1 589 }
webmaster@1 590 }
webmaster@1 591 }
webmaster@1 592 return $taxonomy;
webmaster@1 593 }
webmaster@1 594
webmaster@1 595 /**
webmaster@1 596 * Find all terms associated with the given node, within one vocabulary.
webmaster@1 597 */
webmaster@1 598 function taxonomy_node_get_terms_by_vocabulary($node, $vid, $key = 'tid') {
webmaster@1 599 $result = db_query(db_rewrite_sql('SELECT t.tid, t.* FROM {term_data} t INNER JOIN {term_node} r ON r.tid = t.tid WHERE t.vid = %d AND r.vid = %d ORDER BY weight', 't', 'tid'), $vid, $node->vid);
webmaster@1 600 $terms = array();
webmaster@1 601 while ($term = db_fetch_object($result)) {
webmaster@1 602 $terms[$term->$key] = $term;
webmaster@1 603 }
webmaster@1 604 return $terms;
webmaster@1 605 }
webmaster@1 606
webmaster@1 607 /**
webmaster@1 608 * Find all terms associated with the given node, ordered by vocabulary and term weight.
webmaster@1 609 */
webmaster@1 610 function taxonomy_node_get_terms($node, $key = 'tid') {
webmaster@1 611 static $terms;
webmaster@1 612
webmaster@1 613 if (!isset($terms[$node->vid][$key])) {
webmaster@1 614 $result = db_query(db_rewrite_sql('SELECT t.* FROM {term_node} r INNER JOIN {term_data} t ON r.tid = t.tid INNER JOIN {vocabulary} v ON t.vid = v.vid WHERE r.vid = %d ORDER BY v.weight, t.weight, t.name', 't', 'tid'), $node->vid);
webmaster@1 615 $terms[$node->vid][$key] = array();
webmaster@1 616 while ($term = db_fetch_object($result)) {
webmaster@1 617 $terms[$node->vid][$key][$term->$key] = $term;
webmaster@1 618 }
webmaster@1 619 }
webmaster@1 620 return $terms[$node->vid][$key];
webmaster@1 621 }
webmaster@1 622
webmaster@1 623 /**
webmaster@1 624 * Make sure incoming vids are free tagging enabled.
webmaster@1 625 */
webmaster@1 626 function taxonomy_node_validate(&$node) {
webmaster@1 627 if (!empty($node->taxonomy)) {
webmaster@1 628 $terms = $node->taxonomy;
webmaster@1 629 if (!empty($terms['tags'])) {
webmaster@1 630 foreach ($terms['tags'] as $vid => $vid_value) {
webmaster@1 631 $vocabulary = taxonomy_vocabulary_load($vid);
webmaster@1 632 if (empty($vocabulary->tags)) {
webmaster@1 633 // see form_get_error $key = implode('][', $element['#parents']);
webmaster@1 634 // on why this is the key
webmaster@1 635 form_set_error("taxonomy][tags][$vid", t('The %name vocabulary can not be modified in this way.', array('%name' => $vocabulary->name)));
webmaster@1 636 }
webmaster@1 637 }
webmaster@1 638 }
webmaster@1 639 }
webmaster@1 640 }
webmaster@1 641
webmaster@1 642 /**
webmaster@1 643 * Save term associations for a given node.
webmaster@1 644 */
webmaster@1 645 function taxonomy_node_save($node, $terms) {
webmaster@1 646
webmaster@1 647 taxonomy_node_delete_revision($node);
webmaster@1 648
webmaster@1 649 // Free tagging vocabularies do not send their tids in the form,
webmaster@1 650 // so we'll detect them here and process them independently.
webmaster@1 651 if (isset($terms['tags'])) {
webmaster@1 652 $typed_input = $terms['tags'];
webmaster@1 653 unset($terms['tags']);
webmaster@1 654
webmaster@1 655 foreach ($typed_input as $vid => $vid_value) {
webmaster@1 656 $typed_terms = drupal_explode_tags($vid_value);
webmaster@1 657
webmaster@1 658 $inserted = array();
webmaster@1 659 foreach ($typed_terms as $typed_term) {
webmaster@1 660 // See if the term exists in the chosen vocabulary
webmaster@1 661 // and return the tid; otherwise, add a new record.
webmaster@1 662 $possibilities = taxonomy_get_term_by_name($typed_term);
webmaster@1 663 $typed_term_tid = NULL; // tid match, if any.
webmaster@1 664 foreach ($possibilities as $possibility) {
webmaster@1 665 if ($possibility->vid == $vid) {
webmaster@1 666 $typed_term_tid = $possibility->tid;
webmaster@1 667 }
webmaster@1 668 }
webmaster@1 669
webmaster@1 670 if (!$typed_term_tid) {
webmaster@1 671 $edit = array('vid' => $vid, 'name' => $typed_term);
webmaster@1 672 $status = taxonomy_save_term($edit);
webmaster@1 673 $typed_term_tid = $edit['tid'];
webmaster@1 674 }
webmaster@1 675
webmaster@1 676 // Defend against duplicate, differently cased tags
webmaster@1 677 if (!isset($inserted[$typed_term_tid])) {
webmaster@1 678 db_query('INSERT INTO {term_node} (nid, vid, tid) VALUES (%d, %d, %d)', $node->nid, $node->vid, $typed_term_tid);
webmaster@1 679 $inserted[$typed_term_tid] = TRUE;
webmaster@1 680 }
webmaster@1 681 }
webmaster@1 682 }
webmaster@1 683 }
webmaster@1 684
webmaster@1 685 if (is_array($terms)) {
webmaster@1 686 foreach ($terms as $term) {
webmaster@1 687 if (is_array($term)) {
webmaster@1 688 foreach ($term as $tid) {
webmaster@1 689 if ($tid) {
webmaster@1 690 db_query('INSERT INTO {term_node} (nid, vid, tid) VALUES (%d, %d, %d)', $node->nid, $node->vid, $tid);
webmaster@1 691 }
webmaster@1 692 }
webmaster@1 693 }
webmaster@1 694 else if (is_object($term)) {
webmaster@1 695 db_query('INSERT INTO {term_node} (nid, vid, tid) VALUES (%d, %d, %d)', $node->nid, $node->vid, $term->tid);
webmaster@1 696 }
webmaster@1 697 else if ($term) {
webmaster@1 698 db_query('INSERT INTO {term_node} (nid, vid, tid) VALUES (%d, %d, %d)', $node->nid, $node->vid, $term);
webmaster@1 699 }
webmaster@1 700 }
webmaster@1 701 }
webmaster@1 702 }
webmaster@1 703
webmaster@1 704 /**
webmaster@1 705 * Remove associations of a node to its terms.
webmaster@1 706 */
webmaster@1 707 function taxonomy_node_delete($node) {
webmaster@1 708 db_query('DELETE FROM {term_node} WHERE nid = %d', $node->nid);
webmaster@1 709 }
webmaster@1 710
webmaster@1 711 /**
webmaster@1 712 * Remove associations of a node to its terms.
webmaster@1 713 */
webmaster@1 714 function taxonomy_node_delete_revision($node) {
webmaster@1 715 db_query('DELETE FROM {term_node} WHERE vid = %d', $node->vid);
webmaster@1 716 }
webmaster@1 717
webmaster@1 718 /**
webmaster@1 719 * Implementation of hook_node_type().
webmaster@1 720 */
webmaster@1 721 function taxonomy_node_type($op, $info) {
webmaster@1 722 if ($op == 'update' && !empty($info->old_type) && $info->type != $info->old_type) {
webmaster@1 723 db_query("UPDATE {vocabulary_node_types} SET type = '%s' WHERE type = '%s'", $info->type, $info->old_type);
webmaster@1 724 }
webmaster@1 725 elseif ($op == 'delete') {
webmaster@1 726 db_query("DELETE FROM {vocabulary_node_types} WHERE type = '%s'", $info->type);
webmaster@1 727 }
webmaster@1 728 }
webmaster@1 729
webmaster@1 730 /**
webmaster@1 731 * Find all term objects related to a given term ID.
webmaster@1 732 */
webmaster@1 733 function taxonomy_get_related($tid, $key = 'tid') {
webmaster@1 734 if ($tid) {
webmaster@1 735 $result = db_query('SELECT t.*, tid1, tid2 FROM {term_relation}, {term_data} t WHERE (t.tid = tid1 OR t.tid = tid2) AND (tid1 = %d OR tid2 = %d) AND t.tid != %d ORDER BY weight, name', $tid, $tid, $tid);
webmaster@1 736 $related = array();
webmaster@1 737 while ($term = db_fetch_object($result)) {
webmaster@1 738 $related[$term->$key] = $term;
webmaster@1 739 }
webmaster@1 740 return $related;
webmaster@1 741 }
webmaster@1 742 else {
webmaster@1 743 return array();
webmaster@1 744 }
webmaster@1 745 }
webmaster@1 746
webmaster@1 747 /**
webmaster@1 748 * Find all parents of a given term ID.
webmaster@1 749 */
webmaster@1 750 function taxonomy_get_parents($tid, $key = 'tid') {
webmaster@1 751 if ($tid) {
webmaster@1 752 $result = db_query(db_rewrite_sql('SELECT t.tid, t.* FROM {term_data} t INNER JOIN {term_hierarchy} h ON h.parent = t.tid WHERE h.tid = %d ORDER BY weight, name', 't', 'tid'), $tid);
webmaster@1 753 $parents = array();
webmaster@1 754 while ($parent = db_fetch_object($result)) {
webmaster@1 755 $parents[$parent->$key] = $parent;
webmaster@1 756 }
webmaster@1 757 return $parents;
webmaster@1 758 }
webmaster@1 759 else {
webmaster@1 760 return array();
webmaster@1 761 }
webmaster@1 762 }
webmaster@1 763
webmaster@1 764 /**
webmaster@1 765 * Find all ancestors of a given term ID.
webmaster@1 766 */
webmaster@1 767 function taxonomy_get_parents_all($tid) {
webmaster@1 768 $parents = array();
webmaster@1 769 if ($tid) {
webmaster@1 770 $parents[] = taxonomy_get_term($tid);
webmaster@1 771 $n = 0;
webmaster@1 772 while ($parent = taxonomy_get_parents($parents[$n]->tid)) {
webmaster@1 773 $parents = array_merge($parents, $parent);
webmaster@1 774 $n++;
webmaster@1 775 }
webmaster@1 776 }
webmaster@1 777 return $parents;
webmaster@1 778 }
webmaster@1 779
webmaster@1 780 /**
webmaster@1 781 * Find all children of a term ID.
webmaster@1 782 */
webmaster@1 783 function taxonomy_get_children($tid, $vid = 0, $key = 'tid') {
webmaster@1 784 if ($vid) {
webmaster@1 785 $result = db_query(db_rewrite_sql('SELECT t.* FROM {term_data} t INNER JOIN {term_hierarchy} h ON h.tid = t.tid WHERE t.vid = %d AND h.parent = %d ORDER BY weight, name', 't', 'tid'), $vid, $tid);
webmaster@1 786 }
webmaster@1 787 else {
webmaster@1 788 $result = db_query(db_rewrite_sql('SELECT t.* FROM {term_data} t INNER JOIN {term_hierarchy} h ON h.tid = t.tid WHERE parent = %d ORDER BY weight, name', 't', 'tid'), $tid);
webmaster@1 789 }
webmaster@1 790 $children = array();
webmaster@1 791 while ($term = db_fetch_object($result)) {
webmaster@1 792 $children[$term->$key] = $term;
webmaster@1 793 }
webmaster@1 794 return $children;
webmaster@1 795 }
webmaster@1 796
webmaster@1 797 /**
webmaster@1 798 * Create a hierarchical representation of a vocabulary.
webmaster@1 799 *
webmaster@1 800 * @param $vid
webmaster@1 801 * Which vocabulary to generate the tree for.
webmaster@1 802 *
webmaster@1 803 * @param $parent
webmaster@1 804 * The term ID under which to generate the tree. If 0, generate the tree
webmaster@1 805 * for the entire vocabulary.
webmaster@1 806 *
webmaster@1 807 * @param $depth
webmaster@1 808 * Internal use only.
webmaster@1 809 *
webmaster@1 810 * @param $max_depth
webmaster@1 811 * The number of levels of the tree to return. Leave NULL to return all levels.
webmaster@1 812 *
webmaster@1 813 * @return
webmaster@1 814 * An array of all term objects in the tree. Each term object is extended
webmaster@1 815 * to have "depth" and "parents" attributes in addition to its normal ones.
webmaster@1 816 * Results are statically cached.
webmaster@1 817 */
webmaster@1 818 function taxonomy_get_tree($vid, $parent = 0, $depth = -1, $max_depth = NULL) {
webmaster@1 819 static $children, $parents, $terms;
webmaster@1 820
webmaster@1 821 $depth++;
webmaster@1 822
webmaster@1 823 // We cache trees, so it's not CPU-intensive to call get_tree() on a term
webmaster@1 824 // and its children, too.
webmaster@1 825 if (!isset($children[$vid])) {
webmaster@1 826 $children[$vid] = array();
webmaster@1 827
webmaster@1 828 $result = db_query(db_rewrite_sql('SELECT t.tid, t.*, parent FROM {term_data} t INNER JOIN {term_hierarchy} h ON t.tid = h.tid WHERE t.vid = %d ORDER BY weight, name', 't', 'tid'), $vid);
webmaster@1 829 while ($term = db_fetch_object($result)) {
webmaster@1 830 $children[$vid][$term->parent][] = $term->tid;
webmaster@1 831 $parents[$vid][$term->tid][] = $term->parent;
webmaster@1 832 $terms[$vid][$term->tid] = $term;
webmaster@1 833 }
webmaster@1 834 }
webmaster@1 835
webmaster@1 836 $max_depth = (is_null($max_depth)) ? count($children[$vid]) : $max_depth;
webmaster@1 837 $tree = array();
webmaster@1 838 if (!empty($children[$vid][$parent])) {
webmaster@1 839 foreach ($children[$vid][$parent] as $child) {
webmaster@1 840 if ($max_depth > $depth) {
webmaster@1 841 $term = drupal_clone($terms[$vid][$child]);
webmaster@1 842 $term->depth = $depth;
webmaster@1 843 // The "parent" attribute is not useful, as it would show one parent only.
webmaster@1 844 unset($term->parent);
webmaster@1 845 $term->parents = $parents[$vid][$child];
webmaster@1 846 $tree[] = $term;
webmaster@1 847
webmaster@1 848 if (!empty($children[$vid][$child])) {
webmaster@1 849 $tree = array_merge($tree, taxonomy_get_tree($vid, $child, $depth, $max_depth));
webmaster@1 850 }
webmaster@1 851 }
webmaster@1 852 }
webmaster@1 853 }
webmaster@1 854
webmaster@1 855 return $tree;
webmaster@1 856 }
webmaster@1 857
webmaster@1 858 /**
webmaster@1 859 * Return an array of synonyms of the given term ID.
webmaster@1 860 */
webmaster@1 861 function taxonomy_get_synonyms($tid) {
webmaster@1 862 if ($tid) {
webmaster@1 863 $synonyms = array();
webmaster@1 864 $result = db_query('SELECT name FROM {term_synonym} WHERE tid = %d', $tid);
webmaster@1 865 while ($synonym = db_fetch_array($result)) {
webmaster@1 866 $synonyms[] = $synonym['name'];
webmaster@1 867 }
webmaster@1 868 return $synonyms;
webmaster@1 869 }
webmaster@1 870 else {
webmaster@1 871 return array();
webmaster@1 872 }
webmaster@1 873 }
webmaster@1 874
webmaster@1 875 /**
webmaster@1 876 * Return the term object that has the given string as a synonym.
webmaster@1 877 */
webmaster@1 878 function taxonomy_get_synonym_root($synonym) {
webmaster@1 879 return db_fetch_object(db_query("SELECT * FROM {term_synonym} s, {term_data} t WHERE t.tid = s.tid AND s.name = '%s'", $synonym));
webmaster@1 880 }
webmaster@1 881
webmaster@1 882 /**
webmaster@1 883 * Count the number of published nodes classified by a term.
webmaster@1 884 *
webmaster@1 885 * @param $tid
webmaster@1 886 * The term's ID
webmaster@1 887 *
webmaster@1 888 * @param $type
webmaster@1 889 * The $node->type. If given, taxonomy_term_count_nodes only counts
webmaster@1 890 * nodes of $type that are classified with the term $tid.
webmaster@1 891 *
webmaster@1 892 * @return int
webmaster@1 893 * An integer representing a number of nodes.
webmaster@1 894 * Results are statically cached.
webmaster@1 895 */
webmaster@1 896 function taxonomy_term_count_nodes($tid, $type = 0) {
webmaster@1 897 static $count;
webmaster@1 898
webmaster@1 899 if (!isset($count[$type])) {
webmaster@1 900 // $type == 0 always evaluates TRUE if $type is a string
webmaster@1 901 if (is_numeric($type)) {
webmaster@1 902 $result = db_query(db_rewrite_sql('SELECT t.tid, COUNT(n.nid) AS c FROM {term_node} t INNER JOIN {node} n ON t.vid = n.vid WHERE n.status = 1 GROUP BY t.tid'));
webmaster@1 903 }
webmaster@1 904 else {
webmaster@1 905 $result = db_query(db_rewrite_sql("SELECT t.tid, COUNT(n.nid) AS c FROM {term_node} t INNER JOIN {node} n ON t.vid = n.vid WHERE n.status = 1 AND n.type = '%s' GROUP BY t.tid"), $type);
webmaster@1 906 }
webmaster@1 907 while ($term = db_fetch_object($result)) {
webmaster@1 908 $count[$type][$term->tid] = $term->c;
webmaster@1 909 }
webmaster@1 910 }
webmaster@1 911 $children_count = 0;
webmaster@1 912 foreach (_taxonomy_term_children($tid) as $c) {
webmaster@1 913 $children_count += taxonomy_term_count_nodes($c, $type);
webmaster@1 914 }
webmaster@1 915 return $children_count + (isset($count[$type][$tid]) ? $count[$type][$tid] : 0);
webmaster@1 916 }
webmaster@1 917
webmaster@1 918 /**
webmaster@1 919 * Helper for taxonomy_term_count_nodes(). Used to find out
webmaster@1 920 * which terms are children of a parent term.
webmaster@1 921 *
webmaster@1 922 * @param $tid
webmaster@1 923 * The parent term's ID
webmaster@1 924 *
webmaster@1 925 * @return array
webmaster@1 926 * An array of term IDs representing the children of $tid.
webmaster@1 927 * Results are statically cached.
webmaster@1 928 *
webmaster@1 929 */
webmaster@1 930 function _taxonomy_term_children($tid) {
webmaster@1 931 static $children;
webmaster@1 932
webmaster@1 933 if (!isset($children)) {
webmaster@1 934 $result = db_query('SELECT tid, parent FROM {term_hierarchy}');
webmaster@1 935 while ($term = db_fetch_object($result)) {
webmaster@1 936 $children[$term->parent][] = $term->tid;
webmaster@1 937 }
webmaster@1 938 }
webmaster@1 939 return isset($children[$tid]) ? $children[$tid] : array();
webmaster@1 940 }
webmaster@1 941
webmaster@1 942 /**
webmaster@1 943 * Try to map a string to an existing term, as for glossary use.
webmaster@1 944 *
webmaster@1 945 * Provides a case-insensitive and trimmed mapping, to maximize the
webmaster@1 946 * likelihood of a successful match.
webmaster@1 947 *
webmaster@1 948 * @param name
webmaster@1 949 * Name of the term to search for.
webmaster@1 950 *
webmaster@1 951 * @return
webmaster@1 952 * An array of matching term objects.
webmaster@1 953 */
webmaster@1 954 function taxonomy_get_term_by_name($name) {
webmaster@1 955 $db_result = db_query(db_rewrite_sql("SELECT t.tid, t.* FROM {term_data} t WHERE LOWER(t.name) LIKE LOWER('%s')", 't', 'tid'), trim($name));
webmaster@1 956 $result = array();
webmaster@1 957 while ($term = db_fetch_object($db_result)) {
webmaster@1 958 $result[] = $term;
webmaster@1 959 }
webmaster@1 960
webmaster@1 961 return $result;
webmaster@1 962 }
webmaster@1 963
webmaster@1 964 /**
webmaster@1 965 * Return the vocabulary object matching a vocabulary ID.
webmaster@1 966 *
webmaster@1 967 * @param $vid
webmaster@1 968 * The vocabulary's ID
webmaster@1 969 *
webmaster@1 970 * @return
webmaster@1 971 * The vocabulary object with all of its metadata, if exists, NULL otherwise.
webmaster@1 972 * Results are statically cached.
webmaster@1 973 */
webmaster@1 974 function taxonomy_vocabulary_load($vid) {
webmaster@1 975 static $vocabularies = array();
webmaster@1 976
webmaster@1 977 if (!isset($vocabularies[$vid])) {
webmaster@1 978 // Initialize so if this vocabulary does not exist, we have
webmaster@1 979 // that cached, and we will not try to load this later.
webmaster@1 980 $vocabularies[$vid] = FALSE;
webmaster@1 981 // Try to load the data and fill up the object.
webmaster@1 982 $result = db_query('SELECT v.*, n.type FROM {vocabulary} v LEFT JOIN {vocabulary_node_types} n ON v.vid = n.vid WHERE v.vid = %d', $vid);
webmaster@1 983 $node_types = array();
webmaster@1 984 while ($voc = db_fetch_object($result)) {
webmaster@1 985 if (!empty($voc->type)) {
webmaster@1 986 $node_types[$voc->type] = $voc->type;
webmaster@1 987 }
webmaster@1 988 unset($voc->type);
webmaster@1 989 $voc->nodes = $node_types;
webmaster@1 990 $vocabularies[$vid] = $voc;
webmaster@1 991 }
webmaster@1 992 }
webmaster@1 993
webmaster@1 994 // Return NULL if this vocabulary does not exist.
webmaster@1 995 return !empty($vocabularies[$vid]) ? $vocabularies[$vid] : NULL;
webmaster@1 996 }
webmaster@1 997
webmaster@1 998 /**
webmaster@1 999 * Return the term object matching a term ID.
webmaster@1 1000 *
webmaster@1 1001 * @param $tid
webmaster@1 1002 * A term's ID
webmaster@1 1003 *
webmaster@1 1004 * @return Object
webmaster@1 1005 * A term object. Results are statically cached.
webmaster@1 1006 */
webmaster@1 1007 function taxonomy_get_term($tid) {
webmaster@1 1008 static $terms = array();
webmaster@1 1009
webmaster@1 1010 if (!isset($terms[$tid])) {
webmaster@1 1011 $terms[$tid] = db_fetch_object(db_query('SELECT * FROM {term_data} WHERE tid = %d', $tid));
webmaster@1 1012 }
webmaster@1 1013
webmaster@1 1014 return $terms[$tid];
webmaster@1 1015 }
webmaster@1 1016
webmaster@1 1017 function _taxonomy_term_select($title, $name, $value, $vocabulary_id, $description, $multiple, $blank, $exclude = array()) {
webmaster@1 1018 $tree = taxonomy_get_tree($vocabulary_id);
webmaster@1 1019 $options = array();
webmaster@1 1020
webmaster@1 1021 if ($blank) {
webmaster@1 1022 $options[''] = $blank;
webmaster@1 1023 }
webmaster@1 1024 if ($tree) {
webmaster@1 1025 foreach ($tree as $term) {
webmaster@1 1026 if (!in_array($term->tid, $exclude)) {
webmaster@1 1027 $choice = new stdClass();
webmaster@1 1028 $choice->option = array($term->tid => str_repeat('-', $term->depth) . $term->name);
webmaster@1 1029 $options[] = $choice;
webmaster@1 1030 }
webmaster@1 1031 }
webmaster@1 1032 }
webmaster@1 1033
webmaster@1 1034 return array('#type' => 'select',
webmaster@1 1035 '#title' => $title,
webmaster@1 1036 '#default_value' => $value,
webmaster@1 1037 '#options' => $options,
webmaster@1 1038 '#description' => $description,
webmaster@1 1039 '#multiple' => $multiple,
webmaster@1 1040 '#size' => $multiple ? min(9, count($options)) : 0,
webmaster@1 1041 '#weight' => -15,
webmaster@1 1042 '#theme' => 'taxonomy_term_select',
webmaster@1 1043 );
webmaster@1 1044 }
webmaster@1 1045
webmaster@1 1046 /**
webmaster@1 1047 * Format the selection field for choosing terms
webmaster@1 1048 * (by deafult the default selection field is used).
webmaster@1 1049 *
webmaster@1 1050 * @ingroup themeable
webmaster@1 1051 */
webmaster@1 1052 function theme_taxonomy_term_select($element) {
webmaster@1 1053 return theme('select', $element);
webmaster@1 1054 }
webmaster@1 1055
webmaster@1 1056 /**
webmaster@1 1057 * Finds all nodes that match selected taxonomy conditions.
webmaster@1 1058 *
webmaster@1 1059 * @param $tids
webmaster@1 1060 * An array of term IDs to match.
webmaster@1 1061 * @param $operator
webmaster@1 1062 * How to interpret multiple IDs in the array. Can be "or" or "and".
webmaster@1 1063 * @param $depth
webmaster@1 1064 * How many levels deep to traverse the taxonomy tree. Can be a nonnegative
webmaster@1 1065 * integer or "all".
webmaster@1 1066 * @param $pager
webmaster@1 1067 * Whether the nodes are to be used with a pager (the case on most Drupal
webmaster@1 1068 * pages) or not (in an XML feed, for example).
webmaster@1 1069 * @param $order
webmaster@1 1070 * The order clause for the query that retrieve the nodes.
webmaster@1 1071 * @return
webmaster@1 1072 * A resource identifier pointing to the query results.
webmaster@1 1073 */
webmaster@1 1074 function taxonomy_select_nodes($tids = array(), $operator = 'or', $depth = 0, $pager = TRUE, $order = 'n.sticky DESC, n.created DESC') {
webmaster@1 1075 if (count($tids) > 0) {
webmaster@1 1076 // For each term ID, generate an array of descendant term IDs to the right depth.
webmaster@1 1077 $descendant_tids = array();
webmaster@1 1078 if ($depth === 'all') {
webmaster@1 1079 $depth = NULL;
webmaster@1 1080 }
webmaster@1 1081 foreach ($tids as $index => $tid) {
webmaster@1 1082 $term = taxonomy_get_term($tid);
webmaster@1 1083 $tree = taxonomy_get_tree($term->vid, $tid, -1, $depth);
webmaster@1 1084 $descendant_tids[] = array_merge(array($tid), array_map('_taxonomy_get_tid_from_term', $tree));
webmaster@1 1085 }
webmaster@1 1086
webmaster@1 1087 if ($operator == 'or') {
webmaster@1 1088 $args = call_user_func_array('array_merge', $descendant_tids);
webmaster@1 1089 $placeholders = db_placeholders($args, 'int');
webmaster@1 1090 $sql = 'SELECT DISTINCT(n.nid), n.sticky, n.title, n.created FROM {node} n INNER JOIN {term_node} tn ON n.vid = tn.vid WHERE tn.tid IN ('. $placeholders .') AND n.status = 1 ORDER BY '. $order;
webmaster@1 1091 $sql_count = 'SELECT COUNT(DISTINCT(n.nid)) FROM {node} n INNER JOIN {term_node} tn ON n.vid = tn.vid WHERE tn.tid IN ('. $placeholders .') AND n.status = 1';
webmaster@1 1092 }
webmaster@1 1093 else {
webmaster@1 1094 $joins = '';
webmaster@1 1095 $wheres = '';
webmaster@1 1096 $args = array();
webmaster@1 1097 foreach ($descendant_tids as $index => $tids) {
webmaster@1 1098 $joins .= ' INNER JOIN {term_node} tn'. $index .' ON n.vid = tn'. $index .'.vid';
webmaster@1 1099 $wheres .= ' AND tn'. $index .'.tid IN ('. db_placeholders($tids, 'int') .')';
webmaster@1 1100 $args = array_merge($args, $tids);
webmaster@1 1101 }
webmaster@1 1102 $sql = 'SELECT DISTINCT(n.nid), n.sticky, n.title, n.created FROM {node} n '. $joins .' WHERE n.status = 1 '. $wheres .' ORDER BY '. $order;
webmaster@1 1103 $sql_count = 'SELECT COUNT(DISTINCT(n.nid)) FROM {node} n '. $joins .' WHERE n.status = 1 '. $wheres;
webmaster@1 1104 }
webmaster@1 1105 $sql = db_rewrite_sql($sql);
webmaster@1 1106 $sql_count = db_rewrite_sql($sql_count);
webmaster@1 1107 if ($pager) {
webmaster@1 1108 $result = pager_query($sql, variable_get('default_nodes_main', 10), 0, $sql_count, $args);
webmaster@1 1109 }
webmaster@1 1110 else {
webmaster@1 1111 $result = db_query_range($sql, $args, 0, variable_get('feed_default_items', 10));
webmaster@1 1112 }
webmaster@1 1113 }
webmaster@1 1114
webmaster@1 1115 return $result;
webmaster@1 1116 }
webmaster@1 1117
webmaster@1 1118 /**
webmaster@1 1119 * Accepts the result of a pager_query() call, such as that performed by
webmaster@1 1120 * taxonomy_select_nodes(), and formats each node along with a pager.
webmaster@1 1121 */
webmaster@1 1122 function taxonomy_render_nodes($result) {
webmaster@1 1123 $output = '';
webmaster@1 1124 $has_rows = FALSE;
webmaster@1 1125 while ($node = db_fetch_object($result)) {
webmaster@1 1126 $output .= node_view(node_load($node->nid), 1);
webmaster@1 1127 $has_rows = TRUE;
webmaster@1 1128 }
webmaster@1 1129 if ($has_rows) {
webmaster@1 1130 $output .= theme('pager', NULL, variable_get('default_nodes_main', 10), 0);
webmaster@1 1131 }
webmaster@1 1132 else {
webmaster@1 1133 $output .= '<p>'. t('There are currently no posts in this category.') .'</p>';
webmaster@1 1134 }
webmaster@1 1135 return $output;
webmaster@1 1136 }
webmaster@1 1137
webmaster@1 1138 /**
webmaster@1 1139 * Implementation of hook_nodeapi().
webmaster@1 1140 */
webmaster@1 1141 function taxonomy_nodeapi($node, $op, $arg = 0) {
webmaster@1 1142 switch ($op) {
webmaster@1 1143 case 'load':
webmaster@1 1144 $output['taxonomy'] = taxonomy_node_get_terms($node);
webmaster@1 1145 return $output;
webmaster@1 1146
webmaster@1 1147 case 'insert':
webmaster@1 1148 if (!empty($node->taxonomy)) {
webmaster@1 1149 taxonomy_node_save($node, $node->taxonomy);
webmaster@1 1150 }
webmaster@1 1151 break;
webmaster@1 1152
webmaster@1 1153 case 'update':
webmaster@1 1154 if (!empty($node->taxonomy)) {
webmaster@1 1155 taxonomy_node_save($node, $node->taxonomy);
webmaster@1 1156 }
webmaster@1 1157 break;
webmaster@1 1158
webmaster@1 1159 case 'delete':
webmaster@1 1160 taxonomy_node_delete($node);
webmaster@1 1161 break;
webmaster@1 1162
webmaster@1 1163 case 'delete revision':
webmaster@1 1164 taxonomy_node_delete_revision($node);
webmaster@1 1165 break;
webmaster@1 1166
webmaster@1 1167 case 'validate':
webmaster@1 1168 taxonomy_node_validate($node);
webmaster@1 1169 break;
webmaster@1 1170
webmaster@1 1171 case 'rss item':
webmaster@1 1172 return taxonomy_rss_item($node);
webmaster@1 1173
webmaster@1 1174 case 'update index':
webmaster@1 1175 return taxonomy_node_update_index($node);
webmaster@1 1176 }
webmaster@1 1177 }
webmaster@1 1178
webmaster@1 1179 /**
webmaster@1 1180 * Implementation of hook_nodeapi('update_index').
webmaster@1 1181 */
webmaster@1 1182 function taxonomy_node_update_index(&$node) {
webmaster@1 1183 $output = array();
webmaster@1 1184 foreach ($node->taxonomy as $term) {
webmaster@1 1185 $output[] = $term->name;
webmaster@1 1186 }
webmaster@1 1187 if (count($output)) {
webmaster@1 1188 return '<strong>('. implode(', ', $output) .')</strong>';
webmaster@1 1189 }
webmaster@1 1190 }
webmaster@1 1191
webmaster@1 1192 /**
webmaster@1 1193 * Parses a comma or plus separated string of term IDs.
webmaster@1 1194 *
webmaster@1 1195 * @param $str_tids
webmaster@1 1196 * A string of term IDs, separated by plus or comma.
webmaster@1 1197 * comma (,) means AND
webmaster@1 1198 * plus (+) means OR
webmaster@1 1199 *
webmaster@1 1200 * @return an associative array with an operator key (either 'and'
webmaster@1 1201 * or 'or') and a tid key containing an array of the term ids.
webmaster@1 1202 */
webmaster@1 1203 function taxonomy_terms_parse_string($str_tids) {
webmaster@1 1204 $terms = array('operator' => '', 'tids' => array());
webmaster@1 1205 if (preg_match('/^([0-9]+[+ ])+[0-9]+$/', $str_tids)) {
webmaster@1 1206 $terms['operator'] = 'or';
webmaster@1 1207 // The '+' character in a query string may be parsed as ' '.
webmaster@1 1208 $terms['tids'] = preg_split('/[+ ]/', $str_tids);
webmaster@1 1209 }
webmaster@1 1210 else if (preg_match('/^([0-9]+,)*[0-9]+$/', $str_tids)) {
webmaster@1 1211 $terms['operator'] = 'and';
webmaster@1 1212 $terms['tids'] = explode(',', $str_tids);
webmaster@1 1213 }
webmaster@1 1214 return $terms;
webmaster@1 1215 }
webmaster@1 1216
webmaster@1 1217 /**
webmaster@1 1218 * Provides category information for RSS feeds.
webmaster@1 1219 */
webmaster@1 1220 function taxonomy_rss_item($node) {
webmaster@1 1221 $output = array();
webmaster@1 1222 foreach ($node->taxonomy as $term) {
webmaster@1 1223 $output[] = array('key' => 'category',
webmaster@1 1224 'value' => check_plain($term->name),
webmaster@1 1225 'attributes' => array('domain' => url('taxonomy/term/'. $term->tid, array('absolute' => TRUE))));
webmaster@1 1226 }
webmaster@1 1227 return $output;
webmaster@1 1228 }
webmaster@1 1229
webmaster@1 1230 /**
webmaster@1 1231 * Implementation of hook_help().
webmaster@1 1232 */
webmaster@1 1233 function taxonomy_help($path, $arg) {
webmaster@1 1234 switch ($path) {
webmaster@1 1235 case 'admin/help#taxonomy':
webmaster@1 1236 $output = '<p>'. t('The taxonomy module allows you to categorize content using various systems of classification. Free-tagging vocabularies are created by users on the fly when they submit posts (as commonly found in blogs and social bookmarking applications). Controlled vocabularies allow for administrator-defined short lists of terms as well as complex hierarchies with multiple relationships between different terms. These methods can be applied to different content types and combined together to create a powerful and flexible method of classifying and presenting your content.') .'</p>';
webmaster@1 1237 $output .= '<p>'. t('For example, when creating a recipe site, you might want to classify posts by both the type of meal and preparation time. A vocabulary for each allows you to categorize using each criteria independently instead of creating a tag for every possible combination.') .'</p>';
webmaster@1 1238 $output .= '<p>'. t('Type of Meal: <em>Appetizer, Main Course, Salad, Dessert</em>') .'</p>';
webmaster@1 1239 $output .= '<p>'. t('Preparation Time: <em>0-30mins, 30-60mins, 1-2 hrs, 2hrs+</em>') .'</p>';
webmaster@1 1240 $output .= '<p>'. t("Each taxonomy term (often called a 'category' or 'tag' in other systems) automatically provides lists of posts and a corresponding RSS feed. These taxonomy/term URLs can be manipulated to generate AND and OR lists of posts classified with terms. In our recipe site example, it then becomes easy to create pages displaying 'Main courses', '30 minute recipes', or '30 minute main courses and appetizers' by using terms on their own or in combination with others. There are a significant number of contributed modules which you to alter and extend the behavior of the core module for both display and organization of terms.") .'</p>';
webmaster@1 1241 $output .= '<p>'. t("Terms can also be organized in parent/child relationships from the admin interface. An example would be a vocabulary grouping countries under their parent geo-political regions. The taxonomy module also enables advanced implementations of hierarchy, for example placing Turkey in both the 'Middle East' and 'Europe'.") .'</p>';
webmaster@1 1242 $output .= '<p>'. t('The taxonomy module supports the use of both synonyms and related terms, but does not directly use this functionality. However, optional contributed or custom modules may make full use of these advanced features.') .'</p>';
webmaster@1 1243 $output .= '<p>'. t('For more information, see the online handbook entry for <a href="@taxonomy">Taxonomy module</a>.', array('@taxonomy' => 'http://drupal.org/handbook/modules/taxonomy/')) .'</p>';
webmaster@1 1244 return $output;
webmaster@1 1245 case 'admin/content/taxonomy':
webmaster@1 1246 $output = '<p>'. t("The taxonomy module allows you to categorize your content using both tags and administrator defined terms. It is a flexible tool for classifying content with many advanced features. To begin, create a 'Vocabulary' to hold one set of terms or tags. You can create one free-tagging vocabulary for everything, or separate controlled vocabularies to define the various properties of your content, for example 'Countries' or 'Colors'.") .'</p>';
webmaster@1 1247 $output .= '<p>'. t('Use the list below to configure and review the vocabularies defined on your site, or to list and manage the terms (tags) they contain. A vocabulary may (optionally) be tied to specific content types as shown in the <em>Type</em> column and, if so, will be displayed when creating or editing posts of that type. Multiple vocabularies tied to the same content type will be displayed in the order shown below. To change the order of a vocabulary, grab a drag-and-drop handle under the <em>Name</em> column and drag it to a new location in the list. (Grab a handle by clicking and holding the mouse while hovering over a handle icon.) Remember that your changes will not be saved until you click the <em>Save</em> button at the bottom of the page.') .'</p>';
webmaster@1 1248 return $output;
webmaster@1 1249 case 'admin/content/taxonomy/%':
webmaster@1 1250 $vocabulary = taxonomy_vocabulary_load($arg[3]);
webmaster@1 1251 if ($vocabulary->tags) {
webmaster@1 1252 return '<p>'. t('%capital_name is a free-tagging vocabulary. To change the name or description of a term, click the <em>edit</em> link next to the term.', array('%capital_name' => drupal_ucfirst($vocabulary->name))) .'</p>';
webmaster@1 1253 }
webmaster@1 1254 switch ($vocabulary->hierarchy) {
webmaster@1 1255 case 0:
webmaster@1 1256 return '<p>'. t('%capital_name is a flat vocabulary. You may organize the terms in the %name vocabulary by using the handles on the left side of the table. To change the name or description of a term, click the <em>edit</em> link next to the term.', array('%capital_name' => drupal_ucfirst($vocabulary->name), '%name' => $vocabulary->name)) .'</p>';
webmaster@1 1257 case 1:
webmaster@1 1258 return '<p>'. t('%capital_name is a single hierarchy vocabulary. You may organize the terms in the %name vocabulary by using the handles on the left side of the table. To change the name or description of a term, click the <em>edit</em> link next to the term.', array('%capital_name' => drupal_ucfirst($vocabulary->name), '%name' => $vocabulary->name)) .'</p>';
webmaster@1 1259 case 2:
webmaster@1 1260 return '<p>'. t('%capital_name is a multiple hierarchy vocabulary. To change the name or description of a term, click the <em>edit</em> link next to the term. Drag and drop of multiple hierarchies is not supported, but you can re-enable drag and drop support by editing each term to include only a single parent.', array('%capital_name' => drupal_ucfirst($vocabulary->name))) .'</p>';
webmaster@1 1261 }
webmaster@1 1262 case 'admin/content/taxonomy/add/vocabulary':
webmaster@1 1263 return '<p>'. t('Define how your vocabulary will be presented to administrators and users, and which content types to categorize with it. Tags allows users to create terms when submitting posts by typing a comma separated list. Otherwise terms are chosen from a select list and can only be created by users with the "administer taxonomy" permission.') .'</p>';
webmaster@1 1264 }
webmaster@1 1265 }
webmaster@1 1266
webmaster@1 1267 /**
webmaster@1 1268 * Helper function for array_map purposes.
webmaster@1 1269 */
webmaster@1 1270 function _taxonomy_get_tid_from_term($term) {
webmaster@1 1271 return $term->tid;
webmaster@1 1272 }
webmaster@1 1273
webmaster@1 1274 /**
webmaster@1 1275 * Implode a list of tags of a certain vocabulary into a string.
webmaster@1 1276 */
webmaster@1 1277 function taxonomy_implode_tags($tags, $vid = NULL) {
webmaster@1 1278 $typed_tags = array();
webmaster@1 1279 foreach ($tags as $tag) {
webmaster@1 1280 // Extract terms belonging to the vocabulary in question.
webmaster@1 1281 if (is_null($vid) || $tag->vid == $vid) {
webmaster@1 1282
webmaster@1 1283 // Commas and quotes in tag names are special cases, so encode 'em.
webmaster@1 1284 if (strpos($tag->name, ',') !== FALSE || strpos($tag->name, '"') !== FALSE) {
webmaster@1 1285 $tag->name = '"'. str_replace('"', '""', $tag->name) .'"';
webmaster@1 1286 }
webmaster@1 1287
webmaster@1 1288 $typed_tags[] = $tag->name;
webmaster@1 1289 }
webmaster@1 1290 }
webmaster@1 1291 return implode(', ', $typed_tags);
webmaster@1 1292 }
webmaster@1 1293
webmaster@1 1294 /**
webmaster@1 1295 * Implementation of hook_hook_info().
webmaster@1 1296 */
webmaster@1 1297 function taxonomy_hook_info() {
webmaster@1 1298 return array(
webmaster@1 1299 'taxonomy' => array(
webmaster@1 1300 'taxonomy' => array(
webmaster@1 1301 'insert' => array(
webmaster@1 1302 'runs when' => t('After saving a new term to the database'),
webmaster@1 1303 ),
webmaster@1 1304 'update' => array(
webmaster@1 1305 'runs when' => t('After saving an updated term to the database'),
webmaster@1 1306 ),
webmaster@1 1307 'delete' => array(
webmaster@1 1308 'runs when' => t('After deleting a term')
webmaster@1 1309 ),
webmaster@1 1310 ),
webmaster@1 1311 ),
webmaster@1 1312 );
webmaster@1 1313 }