annotate modules/taxonomy/taxonomy.module @ 20:e3d20ebd63d1 tip

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