taxonomy.module 49.2 KB
Newer Older
Dries's avatar
 
Dries committed
1
<?php
Kjartan's avatar
Kjartan committed
2
// $Id$
Dries's avatar
 
Dries committed
3

Dries's avatar
 
Dries committed
4 5 6 7 8
/**
 * @file
 * Enables the organization of content into categories.
 */

Dries's avatar
 
Dries committed
9 10 11
/**
 * Implementation of hook_perm().
 */
Kjartan's avatar
Kjartan committed
12
function taxonomy_perm() {
Dries's avatar
 
Dries committed
13
  return array('administer taxonomy');
Kjartan's avatar
Kjartan committed
14
}
Dries's avatar
 
Dries committed
15

Dries's avatar
 
Dries committed
16 17 18 19 20 21 22 23 24 25 26
/**
 * Implementation of hook_link().
 *
 * This hook is extended with $type = 'taxonomy terms' to allow themes to
 * print lists of terms associated with a node. Themes can print taxonomy
 * links with:
 *
 * if (module_exist('taxonomy')) {
 *   $this->links(taxonomy_link('taxonomy terms', $node));
 * }
 */
Dries's avatar
 
Dries committed
27
function taxonomy_link($type, $node = NULL) {
Dries's avatar
 
Dries committed
28
  if ($type == 'taxonomy terms' && $node != NULL) {
Kjartan's avatar
 
Kjartan committed
29
    $links = array();
Dries's avatar
 
Dries committed
30
    if (array_key_exists('taxonomy', $node)) {
Dries's avatar
 
Dries committed
31 32
      foreach ($node->taxonomy as $tid) {
        $term = taxonomy_get_term($tid);
Dries's avatar
 
Dries committed
33
        $links[] = l($term->name, 'taxonomy/term/'. $term->tid);
Dries's avatar
 
Dries committed
34 35 36 37 38
      }
    }
    else {
      $links = array();
      foreach (taxonomy_node_get_terms($node->nid) as $term) {
Dries's avatar
 
Dries committed
39
        $links[] = l($term->name, 'taxonomy/term/'. $term->tid);
Dries's avatar
 
Dries committed
40
      }
Dries's avatar
 
Dries committed
41 42 43 44

    }
    return $links;
  }
Kjartan's avatar
Kjartan committed
45 46
}

Dries's avatar
 
Dries committed
47 48 49
/**
 * Implementation of hook_menu().
 */
Dries's avatar
 
Dries committed
50
function taxonomy_menu($may_cache) {
Dries's avatar
 
Dries committed
51
  $items = array();
Dries's avatar
 
Dries committed
52

Dries's avatar
 
Dries committed
53 54 55 56
  if ($may_cache) {
    $items[] = array('path' => 'admin/taxonomy', 'title' => t('categories'),
      'callback' => 'taxonomy_admin',
      'access' => user_access('administer taxonomy'));
57

Dries's avatar
 
Dries committed
58 59
    $items[] = array('path' => 'admin/taxonomy/list', 'title' => t('list'),
      'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10);
60

Dries's avatar
 
Dries committed
61 62 63 64 65
    $items[] = array('path' => 'admin/taxonomy/add/vocabulary', 'title' => t('add vocabulary'),
      'callback' => 'taxonomy_admin',
      'access' => user_access('administer taxonomy'),
      'type' => MENU_LOCAL_TASK);

66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
    $items[] = array('path' => 'admin/taxonomy/edit/vocabulary', 'title' => t('edit vocabulary'),
      'callback' => 'taxonomy_admin',
      'access' => user_access('administer taxonomy'),
      'type' => MENU_CALLBACK);

    $items[] = array('path' => 'admin/taxonomy/add/term', 'title' => t('add term'),
      'callback' => 'taxonomy_admin',
      'access' => user_access('administer taxonomy'),
      'type' => MENU_CALLBACK);

    $items[] = array('path' => 'admin/taxonomy/edit/term', 'title' => t('edit term'),
      'callback' => 'taxonomy_admin',
      'access' => user_access('administer taxonomy'),
      'type' => MENU_CALLBACK);

Dries's avatar
 
Dries committed
81 82 83 84 85
    $items[] = array('path' => 'taxonomy/term', 'title' => t('taxonomy term'),
      'callback' => 'taxonomy_term_page',
      'access' => user_access('access content'),
      'type' => MENU_CALLBACK);
  }
Dries's avatar
Dries committed
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
  else {
    if (is_numeric(arg(2))) {
      $items[] = array('path' => 'admin/taxonomy/' . arg(2), 'title' => t('add term'),
        'callback' => 'taxonomy_admin',
        'access' => user_access('administer taxonomy'),
        'type' => MENU_CALLBACK);

      $items[] = array('path' => 'admin/taxonomy/' . arg(2) . '/list', 'title' => t('list'),
        'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10);

      $items[] = array('path' => 'admin/taxonomy/' . arg(2) . '/add/term', 'title' => t('add term'),
        'callback' => 'taxonomy_admin',
        'access' => user_access('administer taxonomy'),
        'type' => MENU_LOCAL_TASK);
    }
  }
Dries's avatar
 
Dries committed
102

Dries's avatar
 
Dries committed
103 104
  return $items;
}
Dries's avatar
 
Dries committed
105

Kjartan's avatar
Kjartan committed
106
function taxonomy_form_vocabulary($edit = array()) {
Dries's avatar
Dries committed
107
  foreach (node_list() as $type) {
Dries's avatar
 
Dries committed
108 109
    $node_type = node_invoke($type, 'node_name');
    $nodes[$type] = $node_type ? $node_type : $type;
Kjartan's avatar
Kjartan committed
110
  }
Dries's avatar
 
Dries committed
111

Dries's avatar
 
Dries committed
112 113 114
  $form .= form_textfield(t('Vocabulary name'), 'name', $edit['name'], 50, 64, t('The name for this vocabulary.  Example: "Topic".'), NULL, TRUE);
  $form .= form_textarea(t('Description'), 'description', $edit['description'], 60, 5, t('Description of the vocabulary; can be used by modules.'));
  $form .= form_textfield(t('Help text'), 'help', $edit['help'], 50, 255, t('Instructions to present to the user when choosing a term.'));
Dries's avatar
 
Dries committed
115
  $form .= form_checkboxes(t('Types'), 'nodes', $edit['nodes'], $nodes, t('A list of node types you want to associate with this vocabulary.'), NULL, TRUE);
116
  $form .= form_radios(t('Hierarchy'), 'hierarchy', $edit['hierarchy'], array(t('Disabled'), t('Single'), t('Multiple')), t('Allows <a href="%help-url">a tree-like hierarchy</a> between terms of this vocabulary.', array('%help-url' => url('admin/help/taxonomy', NULL, NULL, 'hierarchy'))));
Dries's avatar
Dries committed
117 118 119
  $form .= form_checkbox(t('Related terms'), 'relations', 1, $edit['relations'], t('Allows <a href="%help-url">related terms</a> in this vocabulary.', array('%help-url' => url('admin/help/taxonomy', NULL, NULL, 'related-terms'))));
  $form .= form_checkbox(t('Free tagging'), 'tags', 1, $edit['tags'], t('Content is categorized by typing terms instead of choosing from a list.'));
  $form .= form_checkbox(t('Multiple select'), 'multiple', 1, $edit['multiple'], t('Allows nodes to have more than one term from this vocabulary (always true for free tagging).'));
Dries's avatar
 
Dries committed
120
  $form .= form_checkbox(t('Required'), 'required', 1, $edit['required'], t('If enabled, every node <strong>must</strong> have at least one term in this vocabulary.'));
Dries's avatar
 
Dries committed
121
  $form .= form_weight(t('Weight'), 'weight', $edit['weight'], 10, t('In listings, the heavier vocabularies will sink and the lighter vocabularies will be positioned nearer the top.'));
Dries's avatar
 
Dries committed
122
  $form .= form_submit(t('Submit'));
Dries's avatar
 
Dries committed
123

Dries's avatar
 
Dries committed
124 125 126
  if ($edit['vid']) {
    $form .= form_submit(t('Delete'));
    $form .= form_hidden('vid', $edit['vid']);
Dries's avatar
 
Dries committed
127 128
  }

Kjartan's avatar
Kjartan committed
129 130
  return form($form);
}
Kjartan's avatar
Kjartan committed
131

Kjartan's avatar
Kjartan committed
132
function taxonomy_save_vocabulary($edit) {
Dries's avatar
Dries committed
133 134
  $edit['nodes'] = ($edit['nodes']) ? $edit['nodes'] : array();
  $edit['weight'] = ($edit['weight']) ? $edit['weight'] : 0;
Dries's avatar
 
Dries committed
135

Dries's avatar
Dries committed
136
  $data = array('name' => $edit['name'], 'description' => $edit['description'], 'help' => $edit['help'], 'multiple' => $edit['multiple'], 'required' => $edit['required'], 'hierarchy' => $edit['hierarchy'], 'relations' => $edit['relations'], 'tags' => $edit['tags'], 'weight' => $edit['weight'],  'module' => isset($edit['module']) ? $edit['module'] : 'taxonomy');
Dries's avatar
 
Dries committed
137
  if ($edit['vid'] && $edit['name']) {
Dries's avatar
 
Dries committed
138
    db_query('UPDATE {vocabulary} SET '. _taxonomy_prepare_update($data) .' WHERE vid = %d', $edit['vid']);
Dries's avatar
 
Dries committed
139 140 141 142
    db_query("DELETE FROM {vocabulary_node_types} WHERE vid = %d", $edit['vid']);
    foreach ($edit['nodes'] as $type) {
      db_query("INSERT INTO {vocabulary_node_types} (vid, type) VALUES (%d, '%s')", $edit['vid'], $type);
    }
Dries's avatar
 
Dries committed
143
    module_invoke_all('taxonomy', 'update', 'vocabulary', $edit);
144
    $message = t('Updated vocabulary %name.', array('%name' => theme('placeholder', $edit['name'])));
Dries's avatar
 
Dries committed
145
  }
Dries's avatar
 
Dries committed
146 147
  else if ($edit['vid']) {
    $message = taxonomy_del_vocabulary($edit['vid']);
Kjartan's avatar
Kjartan committed
148 149
  }
  else {
Dries's avatar
 
Dries committed
150
    $data['vid'] = $edit['vid'] = db_next_id('{vocabulary}_vid');
Dries's avatar
 
Dries committed
151
    db_query('INSERT INTO {vocabulary} '. _taxonomy_prepare_insert($data, 1) .' VALUES '. _taxonomy_prepare_insert($data, 2));
Dries's avatar
 
Dries committed
152 153 154
    foreach ($edit['nodes'] as $type) {
      db_query("INSERT INTO {vocabulary_node_types} (vid, type) VALUES (%d, '%s')", $edit['vid'], $type);
    }
Dries's avatar
 
Dries committed
155
    module_invoke_all('taxonomy', 'insert', 'vocabulary', $edit);
156
    $message = t('Created new vocabulary %name.', array('%name' => theme('placeholder', $edit['name'])));
Kjartan's avatar
Kjartan committed
157
  }
Dries's avatar
 
Dries committed
158 159

  cache_clear_all();
Dries's avatar
 
Dries committed
160

Dries's avatar
 
Dries committed
161
  drupal_set_message($message);
162

Dries's avatar
 
Dries committed
163
  return $edit;
Kjartan's avatar
Kjartan committed
164
}
Dries's avatar
 
Dries committed
165

Kjartan's avatar
Kjartan committed
166
function taxonomy_del_vocabulary($vid) {
Dries's avatar
 
Dries committed
167 168
  $vocabulary = taxonomy_get_vocabulary($vid);

Dries's avatar
 
Dries committed
169
  db_query('DELETE FROM {vocabulary} WHERE vid = %d', $vid);
Dries's avatar
 
Dries committed
170
  db_query('DELETE FROM {vocabulary_node_types} WHERE vid = %d', $vid);
Dries's avatar
 
Dries committed
171
  $result = db_query('SELECT tid FROM {term_data} WHERE vid = %d', $vid);
Kjartan's avatar
Kjartan committed
172 173
  while ($term = db_fetch_object($result)) {
    taxonomy_del_term($term->tid);
Dries's avatar
 
Dries committed
174
  }
Dries's avatar
 
Dries committed
175

Dries's avatar
 
Dries committed
176
  module_invoke_all('taxonomy', 'delete', 'vocabulary', $vocabulary);
Dries's avatar
 
Dries committed
177

Dries's avatar
 
Dries committed
178 179
  cache_clear_all();

Dries's avatar
 
Dries committed
180
  return t('deleted vocabulary "%name".', array('%name' => $vocabulary->name));
Dries's avatar
 
Dries committed
181 182 183 184 185
}

function _taxonomy_confirm_del_vocabulary($vid) {
  $vocabulary = taxonomy_get_vocabulary($vid);

186 187 188 189 190 191 192 193 194 195 196
  $extra  = form_hidden('type', 'vocabulary');
  $extra .= form_hidden('vid', $vid);

  $output = theme('confirm',
                  t('Are you sure you want to delete the vocabulary %title?', array('%title' => $vocabulary->name)),
                  'admin/taxonomy',
                  t('Deleting a vocabulary will delete all the terms in it. This action cannot be undone.'),
                  t('Delete'),
                  t('Cancel'),
                  $extra);
  return $output;
Kjartan's avatar
Kjartan committed
197
}
Dries's avatar
 
Dries committed
198

Kjartan's avatar
Kjartan committed
199
function taxonomy_form_term($edit = array()) {
Dries's avatar
 
Dries committed
200
  $vocabulary_id = isset($edit['vid']) ? $edit['vid'] : arg(4);
Kjartan's avatar
Kjartan committed
201
  $vocabulary = taxonomy_get_vocabulary($vocabulary_id);
Dries's avatar
 
Dries committed
202

Dries's avatar
 
Dries committed
203 204
  $form = form_textfield(t('Term name'), 'name', $edit['name'], 50, 64, t('The name for this term.  Example: "Linux".'), NULL, TRUE);
  $form .= form_textarea(t('Description'), 'description', $edit['description'], 60, 5, t('A description of the term.'));
Dries's avatar
 
Dries committed
205

Kjartan's avatar
Kjartan committed
206
  if ($vocabulary->hierarchy) {
Dries's avatar
 
Dries committed
207 208
    $parent = array_keys(taxonomy_get_parents($edit['tid']));
    $children = taxonomy_get_tree($vocabulary_id, $edit['tid']);
Dries's avatar
 
Dries committed
209

Dries's avatar
 
Dries committed
210
    // A term can't be the child of itself, nor of its children.
Dries's avatar
 
Dries committed
211 212 213
    foreach ($children as $child) {
      $exclude[] = $child->tid;
    }
Dries's avatar
 
Dries committed
214
    $exclude[] = $edit['tid'];
Dries's avatar
 
Dries committed
215

Kjartan's avatar
Kjartan committed
216
    if ($vocabulary->hierarchy == 1) {
217
      $form .= _taxonomy_term_select(t('Parent'), 'parent', $parent, $vocabulary_id, l(t('Parent term'), 'admin/help/taxonomy', NULL, NULL, 'parent') .'.', 0, '<'. t('root') .'>', $exclude);
Dries's avatar
 
Dries committed
218
    }
Kjartan's avatar
Kjartan committed
219
    elseif ($vocabulary->hierarchy == 2) {
220
      $form .= _taxonomy_term_select(t('Parents'), 'parent', $parent, $vocabulary_id, l(t('Parent terms'), 'admin/help/taxonomy', NULL, NULL, 'parent') .'.', 1, '<'. t('root') .'>', $exclude);
Dries's avatar
 
Dries committed
221
    }
Kjartan's avatar
Kjartan committed
222
  }
Dries's avatar
 
Dries committed
223

224
  if ($vocabulary->relations) {
Dries's avatar
 
Dries committed
225
    $form .= _taxonomy_term_select(t('Related terms'), 'relations', array_keys(taxonomy_get_related($edit['tid'])), $vocabulary_id, NULL, 1, '<'. t('none') .'>', array($edit['tid']));
226 227
  }

228
  $form .= form_textarea(t('Synonyms'), 'synonyms', implode("\n", taxonomy_get_synonyms($edit['tid'])), 30, 5, t('<a href="%help-url">Synonyms</a> of this term, one synonym per line.', array('%help-url' => url('admin/help/taxonomy', NULL, NULL, 'synonyms'))));
Dries's avatar
 
Dries committed
229
  $form .= form_weight(t('Weight'), 'weight', $edit['weight'], 10, t('In listings, the heavier terms will sink and the lighter terms will be positioned nearer the top.'));
Dries's avatar
 
Dries committed
230 231
  $form .= form_hidden('vid', $vocabulary->vid);
  $form .= form_submit(t('Submit'));
Kjartan's avatar
Kjartan committed
232

Dries's avatar
 
Dries committed
233 234 235
  if ($edit['tid']) {
    $form .= form_submit(t('Delete'));
    $form .= form_hidden('tid', $edit['tid']);
Dries's avatar
 
Dries committed
236
  }
237 238 239
  else {
    $form .= form_hidden('destination', $_GET['q']);
  }
Dries's avatar
 
Dries committed
240

Kjartan's avatar
Kjartan committed
241 242
  return form($form);
}
Dries's avatar
 
Dries committed
243

Kjartan's avatar
Kjartan committed
244
function taxonomy_save_term($edit) {
Dries's avatar
 
Dries committed
245 246
  if ($edit['tid'] && $edit['name']) {
    $data = array('name' => $edit['name'], 'description' => $edit['description'], 'weight' => $edit['weight']);
Dries's avatar
 
Dries committed
247

Dries's avatar
 
Dries committed
248
    db_query('UPDATE {term_data} SET '. _taxonomy_prepare_update($data) .' WHERE tid = %d', $edit['tid']);
Dries's avatar
 
Dries committed
249
    module_invoke_all('taxonomy', 'update', 'term', $edit);
250
    $message = t('The term %term has been updated.', array('%term' => theme('placeholder', $edit['name'])));
Kjartan's avatar
Kjartan committed
251
  }
Dries's avatar
 
Dries committed
252 253
  else if ($edit['tid']) {
    return taxonomy_del_term($edit['tid']);
Kjartan's avatar
Kjartan committed
254 255
  }
  else {
Dries's avatar
 
Dries committed
256 257
    $edit['tid'] = db_next_id('{term_data}_tid');
    $data = array('tid' => $edit['tid'], 'name' => $edit['name'], 'description' => $edit['description'], 'vid' => $edit['vid'], 'weight' => $edit['weight']);
Dries's avatar
 
Dries committed
258
    db_query('INSERT INTO {term_data} '. _taxonomy_prepare_insert($data, 1) .' VALUES '. _taxonomy_prepare_insert($data, 2));
Dries's avatar
 
Dries committed
259
    module_invoke_all('taxonomy', 'insert', 'term', $edit);
260
    $message = t('Created new term %term.', array('%term' => theme('placeholder', $edit['name'])));
Kjartan's avatar
Kjartan committed
261
  }
Dries's avatar
 
Dries committed
262

Dries's avatar
 
Dries committed
263 264 265
  db_query('DELETE FROM {term_relation} WHERE tid1 = %d OR tid2 = %d', $edit['tid'], $edit['tid']);
  if ($edit['relations']) {
    foreach ($edit['relations'] as $related_id) {
Kjartan's avatar
Kjartan committed
266
      if ($related_id != 0) {
Dries's avatar
 
Dries committed
267
        db_query('INSERT INTO {term_relation} (tid1, tid2) VALUES (%d, %d)', $edit['tid'], $related_id);
Dries's avatar
 
Dries committed
268
      }
Kjartan's avatar
Kjartan committed
269
    }
Kjartan's avatar
Kjartan committed
270
  }
Dries's avatar
 
Dries committed
271

Dries's avatar
 
Dries committed
272 273
  db_query('DELETE FROM {term_hierarchy} WHERE tid = %d', $edit['tid']);
  if (!isset($edit['parent'])) {
274
    $edit['parent'] = array(0);
Kjartan's avatar
Kjartan committed
275
  }
Dries's avatar
 
Dries committed
276 277
  if (is_array($edit['parent'])) {
    foreach ($edit['parent'] as $parent) {
278 279 280 281 282 283 284 285
      if (is_array($parent)) {
        foreach ($parent as $tid) {
          db_query('INSERT INTO {term_hierarchy} (tid, parent) VALUES (%d, %d)', $edit['tid'], $tid);
        }
      }
      else {
        db_query('INSERT INTO {term_hierarchy} (tid, parent) VALUES (%d, %d)', $edit['tid'], $parent);
      }
Dries's avatar
 
Dries committed
286
    }
Kjartan's avatar
Kjartan committed
287
  }
Dries's avatar
 
Dries committed
288

Dries's avatar
 
Dries committed
289 290 291
  db_query('DELETE FROM {term_synonym} WHERE tid = %d', $edit['tid']);
  if ($edit['synonyms']) {
    foreach (explode ("\n", str_replace("\r", '', $edit['synonyms'])) as $synonym) {
Dries's avatar
 
Dries committed
292
      if ($synonym) {
Dries's avatar
 
Dries committed
293
        db_query("INSERT INTO {term_synonym} (tid, name) VALUES (%d, '%s')", $edit['tid'], chop($synonym));
Dries's avatar
 
Dries committed
294
      }
Kjartan's avatar
Kjartan committed
295
    }
Dries's avatar
 
Dries committed
296
  }
Dries's avatar
 
Dries committed
297

Dries's avatar
 
Dries committed
298 299
  cache_clear_all();

Dries's avatar
 
Dries committed
300
  drupal_set_message($message);
Dries's avatar
 
Dries committed
301
  return $edit;
Kjartan's avatar
Kjartan committed
302
}
Dries's avatar
 
Dries committed
303

Kjartan's avatar
Kjartan committed
304
function taxonomy_del_term($tid) {
305 306 307 308 309 310 311 312 313 314 315 316 317 318
  $tids = array($tid);
  while ($tids) {
    $children_tids = $orphans = array();
    foreach ($tids as $tid) {
      // See if any of the term's children are about to be become orphans:
      if ($children = taxonomy_get_children($tid)) {
        foreach ($children as $child) {
          // If the term has multiple parents, we don't delete it.
          $parents = taxonomy_get_parents($child->tid);
          if (count($parents) == 1) {
            $orphans[] = $child->tid;
          }
        }
      }
Dries's avatar
 
Dries committed
319

320
      $term = taxonomy_get_term($tid);
Dries's avatar
 
Dries committed
321

322 323 324 325 326
      db_query('DELETE FROM {term_data} WHERE tid = %d', $tid);
      db_query('DELETE FROM {term_hierarchy} WHERE tid = %d', $tid);
      db_query('DELETE FROM {term_relation} WHERE tid1 = %d OR tid2 = %d', $tid, $tid);
      db_query('DELETE FROM {term_synonym} WHERE tid = %d', $tid);
      db_query('DELETE FROM {term_node} WHERE tid = %d', $tid);
Dries's avatar
 
Dries committed
327

328
      module_invoke_all('taxonomy', 'delete', 'term', $term);
329
      drupal_set_message(t('Deleted term %name.', array('%name' => theme('placeholder', $term->name))));
330
    }
Dries's avatar
 
Dries committed
331

332 333
    $tids = $orphans;
  }
Dries's avatar
 
Dries committed
334

Dries's avatar
 
Dries committed
335
  cache_clear_all();
Dries's avatar
 
Dries committed
336 337 338 339 340
}

function _taxonomy_confirm_del_term($tid) {
  $term = taxonomy_get_term($tid);

341 342
  $extra  = form_hidden('type', 'term');
  $extra .= form_hidden('tid', $tid);
Dries's avatar
 
Dries committed
343

344
  $output = theme('confirm',
345
                  t('Are you sure you want to delete the term %title?', array('%title' => theme('placeholder', $term->name))),
346 347 348 349 350
                  'admin/taxonomy',
                  t('Deleting a term will delete all its children if there are any. This action cannot be undone.'),
                  t('Delete'),
                  t('Cancel'),
                  $extra);
351 352

  return $output;
Kjartan's avatar
Kjartan committed
353
}
Dries's avatar
 
Dries committed
354

Dries's avatar
 
Dries committed
355 356 357
/**
 * Generate a tabular listing of administrative functions for vocabularies.
 */
Kjartan's avatar
Kjartan committed
358
function taxonomy_overview() {
Dries's avatar
 
Dries committed
359

Dries's avatar
Dries committed
360 361 362 363 364 365 366 367
  $vid = arg(2);

  // Show all vocabularies and their terms. if vocabulary is "Free tagging",
  // don't show terms here, but instruct user to "view terms" instead.
  if (!$vid) {
    $header = array(t('Name'), t('Type'), array('data' => t('Operations'), 'colspan' => '3'));
    $vocabularies = taxonomy_get_vocabularies();
    foreach ($vocabularies as $vocabulary) {
368 369 370 371 372 373 374 375 376 377 378 379 380
      $types = array();
      foreach ($vocabulary->nodes as $type) {
        $node_type = node_invoke($type, 'node_name');
        $types[] = $node_type ? $node_type : $type;
      }
      $rows[] = array('<strong>'.check_plain($vocabulary->name).'</strong>', implode(', ', $types), l(t('edit vocabulary'), "admin/taxonomy/edit/vocabulary/$vocabulary->vid"), l(t('add term'), "admin/taxonomy/add/term/$vocabulary->vid"), l(t('view terms'), "admin/taxonomy/$vocabulary->vid"));

      // Show terms if non-free.
      if (!$vocabulary->tags) {
        $tree = taxonomy_get_tree($vocabulary->vid);
        if ($tree) {
          foreach ($tree as $term) {
            $rows[] = array(array('data' => _taxonomy_depth($term->depth) . ' ' . check_plain($term->name), 'class' => 'term'), NULL, NULL, NULL, l(t('edit term'), "admin/taxonomy/edit/term/$term->tid"));
Dries's avatar
Dries committed
381 382
          }
        }
383 384
        else {
          $rows[] = array(array('data' => t('No terms available.'), 'colspan' => '5', 'class' => 'message'));
Dries's avatar
Dries committed
385
        }
386
      }
387 388 389
      elseif ($vocabulary->tags) {
        $rows[] = array(array('data' => t('This is a free tagging vocabulary:') . ' ' . l(t('view terms'), "admin/taxonomy/$vocabulary->vid") . '.', 'colspan' => '5', 'class' => 'message'));
      }
Dries's avatar
Dries committed
390 391 392 393 394 395
    }

    if (!$rows) {
      $rows[] = array(array('data' => t('No categories available.'), 'colspan' => '5', 'class' => 'message'));
    }
  }
Dries's avatar
 
Dries committed
396

Dries's avatar
Dries committed
397 398 399 400 401 402 403 404 405 406 407
  // Free tagging vocabularies get their own terms pager
  // since there is a greater chance of 1000+ terms.
  else {
    $header = array(t('Name'), array('data' => t('Operations'), 'width' => '60'));
    $vocabulary = taxonomy_get_vocabulary($vid);
    if ($vocabulary->module == 'taxonomy') {
      drupal_set_title(check_plain($vocabulary->name));
      $start_from      = $_GET['from'] ? $_GET['from'] : 0;
      $total_entries   = 0;  // total count for pager
      $page_increment  = 25; // number of tids per page
      $displayed_count = 0;  // number of tids shown
Kjartan's avatar
Kjartan committed
408

409
      $tree = taxonomy_get_tree($vocabulary->vid);
Kjartan's avatar
Kjartan committed
410
      foreach ($tree as $term) {
Dries's avatar
Dries committed
411 412 413 414
        $total_entries++; // we're counting all-totals, not displayed
        if (($start_from && $start_from > $total_entries) || ($displayed_count == $page_increment)) { continue; }
        $rows[] = array(_taxonomy_depth($term->depth) . ' ' . check_plain($term->name), l(t('edit term'), "admin/taxonomy/edit/term/$term->tid"));
        $displayed_count++; // we're counting tids displayed
Dries's avatar
 
Dries committed
415
      }
Dries's avatar
Dries committed
416 417 418

      if (!$rows) {
        $rows[] = array(array('data' => t('No terms available.'), 'colspan' => '2'));
419
      }
Dries's avatar
 
Dries committed
420

Dries's avatar
Dries committed
421 422 423 424
      $GLOBALS['pager_from_array'][] = $start_from;
      $GLOBALS['pager_total'][]      = $total_entries;
      $rows[] = array(array('data' => theme('pager', NULL, $page_increment), 'colspan' => '2'));
    }
Dries's avatar
 
Dries committed
425 426
  }

Dries's avatar
Dries committed
427
  return theme('table', $header, $rows, array('id' => 'taxonomy'));
Kjartan's avatar
Kjartan committed
428 429
}

Dries's avatar
 
Dries committed
430 431 432
/**
 * Generate a form element for selecting terms from a vocabulary.
 */
Dries's avatar
 
Dries committed
433
function taxonomy_form($vid, $value = 0, $help = NULL, $name = 'taxonomy') {
Dries's avatar
 
Dries committed
434
  $vocabulary = taxonomy_get_vocabulary($vid);
435
  $help = ($help) ? $help : $vocabulary->help;
Kjartan's avatar
Kjartan committed
436 437 438 439
  if ($vocabulary->required) {
    $blank = 0;
  }
  else {
Dries's avatar
 
Dries committed
440
    $blank = '<'. t('none') .'>';
Kjartan's avatar
Kjartan committed
441
  }
Dries's avatar
 
Dries committed
442

443
  return _taxonomy_term_select(check_plain($vocabulary->name), $name, $value, $vid, $help, intval($vocabulary->multiple), $blank);
Kjartan's avatar
Kjartan committed
444
}
Dries's avatar
 
Dries committed
445

446
/**
447 448 449
 * Generate a set of options for selecting a term from all vocabularies. Can be
 * passed to form_select.
 */
Dries's avatar
Dries committed
450
function taxonomy_form_all($free_tags = 0) {
451 452 453
  $vocabularies = taxonomy_get_vocabularies();
  $options = array();
  foreach ($vocabularies as $vid => $vocabulary) {
Dries's avatar
Dries committed
454
    if ($vocabulary->tags && !$free_tags) { continue; }
455 456 457 458 459 460 461 462 463 464 465
    $tree = taxonomy_get_tree($vid);
    $options[$vocabulary->name] = array();
    if ($tree) {
      foreach ($tree as $term) {
        $options[$vocabulary->name][$term->tid] = _taxonomy_depth($term->depth, '-') . $term->name;
      }
    }
  }
  return $options;
}

Dries's avatar
 
Dries committed
466 467 468 469 470 471
/**
 * Return an array of all vocabulary objects.
 *
 * @param $type
 *   If set, return only those vocabularies associated with this node type.
 */
Dries's avatar
 
Dries committed
472
function taxonomy_get_vocabularies($type = NULL) {
Kjartan's avatar
Kjartan committed
473
  if ($type) {
474
    $result = db_query("SELECT 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", $type);
Kjartan's avatar
Kjartan committed
475 476
  }
  else {
477
    $result = db_query('SELECT v.*, n.type FROM {vocabulary} v LEFT JOIN {vocabulary_node_types} n ON v.vid = n.vid ORDER BY v.weight, v.name');
Kjartan's avatar
Kjartan committed
478
  }
Dries's avatar
 
Dries committed
479

Kjartan's avatar
Kjartan committed
480
  $vocabularies = array();
Dries's avatar
 
Dries committed
481
  $node_types = array();
Kjartan's avatar
Kjartan committed
482
  while ($voc = db_fetch_object($result)) {
Dries's avatar
 
Dries committed
483 484 485 486
    $node_types[$voc->vid][] = $voc->type;
    unset($voc->type);
    $voc->nodes = $node_types[$voc->vid];
    $vocabularies[$voc->vid] = $voc;
Dries's avatar
 
Dries committed
487
  }
Dries's avatar
 
Dries committed
488

Kjartan's avatar
Kjartan committed
489 490
  return $vocabularies;
}
Dries's avatar
 
Dries committed
491

Dries's avatar
 
Dries committed
492 493 494
/**
 * Generate a form for selecting terms to associate with a node.
 */
Dries's avatar
 
Dries committed
495
function taxonomy_node_form($type, $node = '', $help = NULL, $name = 'taxonomy') {
Dries's avatar
Dries committed
496
  if (!array_key_exists('taxonomy', $node)) {
Kjartan's avatar
Kjartan committed
497
    if ($node->nid) {
Dries's avatar
Dries committed
498
      $terms = taxonomy_node_get_terms($node->nid);
Kjartan's avatar
Kjartan committed
499 500
    }
    else {
Dries's avatar
Dries committed
501
      $terms = array();
Dries's avatar
 
Dries committed
502
    }
Kjartan's avatar
Kjartan committed
503 504 505 506
  }
  else {
    $terms = $node->taxonomy;
  }
Dries's avatar
 
Dries committed
507

Dries's avatar
 
Dries committed
508
  $c = db_query("SELECT v.*, n.type FROM {vocabulary} v INNER JOIN {vocabulary_node_types} n ON v.vid = n.vid WHERE n.type = '%s' ORDER BY v.weight, v.name", $type);
Kjartan's avatar
Kjartan committed
509
  while ($vocabulary = db_fetch_object($c)) {
Dries's avatar
Dries committed
510 511 512 513 514 515 516 517 518 519 520 521 522 523
    if ($vocabulary->tags) {
      $typed_terms = array();
      foreach ($terms as $term) {
        if ($term->vid == $vocabulary->vid) {

          // Commas and quotes in terms are special cases, so encode 'em.
          if (preg_match('/,/', $term->name) || preg_match('/"/', $term->name)) {
            $term->name = '"'.preg_replace('/"/', '""', $term->name).'"';
          }

          $typed_terms[] = $term->name;
        }
      }
      $typed_string = implode(', ', $typed_terms) . (array_key_exists('tags', $terms) ? $terms['tags'][$vocabulary->vid] : NULL);
524
      $result[] = form_textfield($vocabulary->name, "$name][tags][". $vocabulary->vid, $typed_string, 50, 100, t('A comma-separated list of terms describing this content (Example: funny, bungie jumping, "Company, Inc.").'), NULL, ($vocabulary->required ? TRUE : FALSE));
Dries's avatar
Dries committed
525 526 527 528 529
    }
    else {
      $ntterms = array_key_exists('taxonomy', $node) ? $terms : array_keys($terms);
      $result[] = taxonomy_form($vocabulary->vid, $ntterms, $help, $name);
    }
Dries's avatar
 
Dries committed
530
  }
Kjartan's avatar
Kjartan committed
531 532
  return $result ? $result : array();
}
Dries's avatar
 
Dries committed
533

Dries's avatar
 
Dries committed
534 535 536 537 538
/**
 * Find all terms associated to the given node, within one vocabulary.
 */
function taxonomy_node_get_terms_by_vocabulary($nid, $vid, $key = 'tid') {
  $result = db_query('SELECT t.* FROM {term_data} t, {term_node} r WHERE t.tid = r.tid AND t.vid = %d AND r.nid = %d ORDER BY weight', $vid, $nid);
Kjartan's avatar
Kjartan committed
539 540 541
  $terms = array();
  while ($term = db_fetch_object($result)) {
    $terms[$term->$key] = $term;
Dries's avatar
 
Dries committed
542
  }
Kjartan's avatar
Kjartan committed
543 544 545
  return $terms;
}

Dries's avatar
 
Dries committed
546 547 548 549
/**
 * Find all terms associated to the given node.
 */
function taxonomy_node_get_terms($nid, $key = 'tid') {
Kjartan's avatar
Kjartan committed
550
  static $terms;
Dries's avatar
 
Dries committed
551

Dries's avatar
 
Dries committed
552
  if (!isset($terms[$nid])) {
Dries's avatar
 
Dries committed
553
    $result = db_query('SELECT t.* FROM {term_data} t, {term_node} r WHERE r.tid = t.tid AND r.nid = %d ORDER BY weight, name', $nid);
Kjartan's avatar
Kjartan committed
554
    $terms[$nid] = array();
Dries's avatar
 
Dries committed
555
    while ($term = db_fetch_object($result)) {
Kjartan's avatar
Kjartan committed
556
      $terms[$nid][$term->$key] = $term;
Dries's avatar
 
Dries committed
557 558
    }
  }
Kjartan's avatar
Kjartan committed
559 560
  return $terms[$nid];
}
Dries's avatar
 
Dries committed
561

Dries's avatar
Dries committed
562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578
/**
 * Make sure incoming vids are free tagging enabled.
 */
function taxonomy_node_validate(&$node) {
  if ($node->taxonomy) {
    $terms = $node->taxonomy;
    if ($terms['tags']) {
      foreach ($terms['tags'] as $vid => $vid_value) {
        $vocabulary = taxonomy_get_vocabulary($vid);
        if (!$vocabulary->tags) {
          form_set_error("taxonomy[tags][$vid", t('The %name vocabulary can not be modified in this way.', array('%name' => theme('placeholder', $vocabulary->name))));
        }
      }
    }
  }
}

Dries's avatar
 
Dries committed
579 580 581
/**
 * Save term associations for a given node.
 */
Kjartan's avatar
Kjartan committed
582
function taxonomy_node_save($nid, $terms) {
583
  taxonomy_node_delete($nid);
Dries's avatar
Dries committed
584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624

  // Free tagging vocabularies do not send their tids in the form,
  // so we'll detect them here and process them independently.
  if ($terms['tags']) {
    $typed_input = $terms['tags'];
    unset($terms['tags']);

    foreach ($typed_input as $vid => $vid_value) {
      // This regexp allows the following types of user input:
      // this, "somecmpany, llc", "and ""this"" w,o.rks", foo bar
      $regexp = '%(?:^|,\ *)("(?>[^"]*)(?>""[^"]* )*"|(?: [^",]*))%x';
      preg_match_all($regexp, $vid_value, $matches);
      $typed_terms = $matches[1];

      foreach ($typed_terms as $typed_term) {
        // If a user has escaped a term (to demonstrate that it is a group,
        // or includes a comma or quote character), we remove the escape
        // formatting so to save the term into the DB as the user intends.
        $typed_term = str_replace('""', '"', preg_replace('/^"(.*)"$/', '\1', $typed_term));
        $typed_term = trim($typed_term);
        if ($typed_term == "") { continue; }

        // See if the term exists in the chosen vocabulary
        // and return the tid, otherwise, add a new record.
        $possibilities = taxonomy_get_term_by_name($typed_term);
        $typed_term_tid = NULL; // tid match if any.
        foreach ($possibilities as $possibility) {
          if ($possibility->vid == $vid) {
            $typed_term_tid = $possibility->tid;
          }
        }

        if (!$typed_term_tid) {
          $new_term = taxonomy_save_term(array('vid' => $vid, 'name' => $typed_term));
          $typed_term_tid = $new_term['tid'];
        }

        db_query('INSERT INTO {term_node} (nid, tid) VALUES (%d, %d)', $nid, $typed_term_tid);
      }
    }
  }
Dries's avatar
 
Dries committed
625

626
  if (is_array($terms)) {
Dries's avatar
 
Dries committed
627
    foreach ($terms as $term) {
628 629 630 631 632 633 634
      if (is_array($term)) {
        foreach ($term as $tid) {
          if ($tid) {
            db_query('INSERT INTO {term_node} (nid, tid) VALUES (%d, %d)', $nid, $tid);
          }
        }
      }
635
      else if ($term) {
Dries's avatar
 
Dries committed
636
        db_query('INSERT INTO {term_node} (nid, tid) VALUES (%d, %d)', $nid, $term);
637
      }
Dries's avatar
 
Dries committed
638 639
    }
  }
Kjartan's avatar
Kjartan committed
640
}
Dries's avatar
 
Dries committed
641

Dries's avatar
 
Dries committed
642 643 644
/**
 * Remove associations of a node to its terms.
 */
Kjartan's avatar
Kjartan committed
645
function taxonomy_node_delete($nid) {
Dries's avatar
 
Dries committed
646
  db_query('DELETE FROM {term_node} WHERE nid = %d', $nid);
Kjartan's avatar
Kjartan committed
647
}
Dries's avatar
 
Dries committed
648

Dries's avatar
 
Dries committed
649 650 651 652
/**
 * Find all term objects related to a given term ID.
 */
function taxonomy_get_related($tid, $key = 'tid') {
Kjartan's avatar
Kjartan committed
653
  if ($tid) {
Dries's avatar
 
Dries committed
654
    $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);
Kjartan's avatar
Kjartan committed
655 656 657
    $related = array();
    while ($term = db_fetch_object($result)) {
      $related[$term->$key] = $term;
Dries's avatar
 
Dries committed
658
    }
Kjartan's avatar
Kjartan committed
659
    return $related;
Dries's avatar
 
Dries committed
660
  }
Kjartan's avatar
Kjartan committed
661 662
  else {
    return array();
Dries's avatar
 
Dries committed
663
  }
Kjartan's avatar
Kjartan committed
664
}
Dries's avatar
 
Dries committed
665

Dries's avatar
 
Dries committed
666 667 668 669
/**
 * Find all parents of a given term ID.
 */
function taxonomy_get_parents($tid, $key = 'tid') {
Kjartan's avatar
Kjartan committed
670
  if ($tid) {
Dries's avatar
 
Dries committed
671
    $result = db_query('SELECT t.* FROM {term_hierarchy} h, {term_data} t WHERE h.parent = t.tid AND h.tid = %d ORDER BY weight, name', $tid);
Kjartan's avatar
Kjartan committed
672 673 674
    $parents = array();
    while ($parent = db_fetch_object($result)) {
      $parents[$parent->$key] = $parent;
Dries's avatar
 
Dries committed
675
    }
Kjartan's avatar
Kjartan committed
676
    return $parents;
Dries's avatar
 
Dries committed
677
  }
Kjartan's avatar
Kjartan committed
678 679 680 681
  else {
    return array();
  }
}
Dries's avatar
 
Dries committed
682

Dries's avatar
 
Dries committed
683 684 685 686
/**
 * Find all ancestors of a given term ID.
 */
function taxonomy_get_parents_all($tid) {
Dries's avatar
 
Dries committed
687 688 689 690 691 692 693 694 695 696 697 698
  $parents = array();
  if ($tid) {
    $parents[] = taxonomy_get_term($tid);
    $n = 0;
    while ($parent = taxonomy_get_parents($parents[$n]->tid)) {
      $parents = array_merge($parents, $parent);
      $n++;
    }
  }
  return $parents;
}

Dries's avatar
 
Dries committed
699 700 701 702
/**
 * Find all children of a term ID.
 */
function taxonomy_get_children($tid, $vid = 0, $key = 'tid') {
Kjartan's avatar
Kjartan committed
703
  if ($vid) {
Dries's avatar
 
Dries committed
704
    $result = db_query('SELECT t.* FROM {term_hierarchy} h, {term_data} t WHERE t.vid = %d AND h.tid = t.tid AND h.parent = %d ORDER BY weight, name', $vid, $tid);
Dries's avatar
 
Dries committed
705
  }
Kjartan's avatar
Kjartan committed
706
  else {
Dries's avatar
 
Dries committed
707
    $result = db_query('SELECT t.* FROM {term_hierarchy} h, {term_data} t WHERE h.tid = t.tid AND parent = %d ORDER BY weight', $tid);
Kjartan's avatar
Kjartan committed
708 709 710 711 712 713 714
  }
  $children = array();
  while ($term = db_fetch_object($result)) {
    $children[$term->$key] = $term;
  }
  return $children;
}
Dries's avatar
 
Dries committed
715

Dries's avatar
 
Dries committed
716 717 718 719 720 721 722 723 724 725 726 727 728
/**
 * Create a hierarchical representation of a vocabulary.
 *
 * @param $vid
 *   Which vocabulary to generate the tree for.
 *
 * @param $parent
 *   The term ID under which to generate the tree. If 0, generate the tree
 *   for the entire vocabulary.
 *
 * @param $depth
 *   Internal use only.
 *
Dries's avatar
 
Dries committed
729 730 731
 * @param $max_depth
 *   The number of levels of the tree to return. Leave NULL to return all levels.
 *
Dries's avatar
 
Dries committed
732 733 734 735 736
 * @return
 *   An array of all term objects in the tree. Each term object is extended
 *   to have "depth" and "parents" attributes in addition to its normal ones.
 */
function taxonomy_get_tree($vid, $parent = 0, $depth = -1, $max_depth = NULL) {
Dries's avatar
 
Dries committed
737
  static $children, $parents, $terms;
Dries's avatar
 
Dries committed
738

Kjartan's avatar
Kjartan committed
739
  $depth++;
Dries's avatar
 
Dries committed
740

Dries's avatar
 
Dries committed
741 742 743 744
  // We cache trees, so it's not CPU-intensive to call get_tree() on a term
  // and its children, too.
  if (!isset($children[$vid])) {
    $children[$vid] = array();
Dries's avatar
 
Dries committed
745

Dries's avatar
 
Dries committed
746
    $result = db_query('SELECT t.*, parent FROM {term_data} t, {term_hierarchy} h WHERE t.tid = h.tid AND t.vid = %d ORDER BY weight, name', $vid);
Dries's avatar
 
Dries committed
747
    while ($term = db_fetch_object($result)) {
Dries's avatar
 
Dries committed
748 749 750
      $children[$vid][$term->parent][] = $term->tid;
      $parents[$vid][$term->tid][] = $term->parent;
      $terms[$vid][$term->tid] = $term;
Dries's avatar
 
Dries committed
751 752
    }
  }
Dries's avatar
 
Dries committed
753

Dries's avatar
 
Dries committed
754
  $max_depth = (is_null($max_depth)) ? count($children[$vid]) : $max_depth;
Dries's avatar
Dries committed
755 756 757 758 759 760 761 762 763 764 765 766
  if ($children[$vid][$parent]) {
    foreach ($children[$vid][$parent] as $child) {
      if ($max_depth > $depth) {
        $terms[$vid][$child]->depth = $depth;
        // The "parent" attribute is not useful, as it would show one parent only.
        unset($terms[$vid][$child]->parent);
        $terms[$vid][$child]->parents = $parents[$vid][$child];
        $tree[] = $terms[$vid][$child];

        if ($children[$vid][$child]) {
          $tree = array_merge($tree, taxonomy_get_tree($vid, $child, $depth, $max_depth));
        }
Dries's avatar
 
Dries committed
767
      }
Dries's avatar
 
Dries committed
768
    }
Kjartan's avatar
Kjartan committed
769
  }
Dries's avatar
 
Dries committed
770

Dries's avatar
 
Dries committed
771
  return $tree ? $tree : array();
Kjartan's avatar
Kjartan committed
772
}
Dries's avatar
 
Dries committed
773

Dries's avatar
 
Dries committed
774 775 776
/**
 * Return an array of synonyms of the given term ID.
 */
Kjartan's avatar
Kjartan committed
777 778
function taxonomy_get_synonyms($tid) {
  if ($tid) {
Dries's avatar
 
Dries committed
779
    $result = db_query('SELECT name FROM {term_synonym} WHERE tid = %d', $tid);
Kjartan's avatar
Kjartan committed
780
    while ($synonym = db_fetch_array($result)) {
Dries's avatar
 
Dries committed
781
      $synonyms[] = $synonym['name'];
Dries's avatar
 
Dries committed
782
    }
Kjartan's avatar
Kjartan committed
783
    return $synonyms ? $synonyms : array();
Dries's avatar
 
Dries committed
784
  }
Kjartan's avatar
Kjartan committed
785 786
  else {
    return array();
Dries's avatar
 
Dries committed
787
  }
Kjartan's avatar
Kjartan committed
788
}
Dries's avatar
 
Dries committed
789

Dries's avatar
 
Dries committed
790 791 792 793 794
/**
 * Return the term object that has the given string as a synonym.
 */
function taxonomy_get_synonym_root($synonym) {
  return db_fetch_object(db_query("SELECT * FROM {term_synonym} s, {term_data} t WHERE t.tid = s.tid AND s.name = '%s'", $synonym));
Kjartan's avatar
Kjartan committed
795
}
Dries's avatar
 
Dries committed
796

Dries's avatar
 
Dries committed
797 798 799
/**
 * Given a term id, count the number of published nodes in it.
 */
Dries's avatar
 
Dries committed
800
function taxonomy_term_count_nodes($tid, $type = 0) {
Kjartan's avatar
Kjartan committed
801
  static $count;
Dries's avatar
 
Dries committed
802

Dries's avatar
 
Dries committed
803 804 805
  if (!isset($count[$type])) {
    // $type == 0 always evaluates true is $type is a string
    if (is_numeric($type)) {
806
      $result = db_query(db_rewrite_sql('SELECT t.tid, COUNT(n.nid) AS c FROM {term_node} t INNER JOIN {node} n ON t.nid = n.nid WHERE n.status = 1 GROUP BY t.tid'));
Dries's avatar
 
Dries committed
807 808
    }
    else {
809
      $result = db_query(db_rewrite_sql("SELECT t.tid, COUNT(n.nid) AS c FROM {term_node} t, {node} n WHERE t.nid = n.nid AND n.status = 1 AND n.type = '%s' GROUP BY t.tid"), $type);
Dries's avatar
 
Dries committed
810
    }
Kjartan's avatar
Kjartan committed
811
    while ($term = db_fetch_object($result)) {
Dries's avatar
 
Dries committed
812
      $count[$type][$term->tid] = $term->c;
Dries's avatar
 
Dries committed
813 814 815
    }
  }

Kjartan's avatar
Kjartan committed
816
  foreach (_taxonomy_term_children($tid) as $c) {
Dries's avatar
 
Dries committed
817
    $children_count += taxonomy_term_count_nodes($c, $type);
Kjartan's avatar
Kjartan committed
818
  }
Dries's avatar
 
Dries committed
819
  return $count[$type][$tid] + $children_count;
Kjartan's avatar
Kjartan committed
820 821
}

Dries's avatar
 
Dries committed
822 823 824
/**
 * Helper for taxonomy_term_count_nodes().
 */
Kjartan's avatar
Kjartan committed
825 826
function _taxonomy_term_children($tid) {
  static $children;
Dries's avatar
 
Dries committed
827

Dries's avatar
 
Dries committed
828
  if (!isset($children)) {
Dries's avatar
 
Dries committed
829
    $result = db_query('SELECT tid, parent FROM {term_hierarchy}');
Kjartan's avatar
Kjartan committed
830 831
    while ($term = db_fetch_object($result)) {
      $children[$term->parent][] = $term->tid;
Dries's avatar
 
Dries committed
832
    }
Dries's avatar
 
Dries committed
833
  }
Kjartan's avatar
Kjartan committed
834 835
  return $children[$tid] ? $children[$tid] : array();
}
Dries's avatar
 
Dries committed
836

Dries's avatar
 
Dries committed
837
/**
Dries's avatar