taxonomy.module 49.1 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);
33
        $links[] = l($term->name, taxonomy_term_path($term), array('rel' => 'tag', 'title' => $term->description));
Dries's avatar
 
Dries committed
34 35 36 37
      }
    }
    else {
      foreach (taxonomy_node_get_terms($node->nid) as $term) {
38
        $links[] = l($term->name, taxonomy_term_path($term), array('rel' => 'tag', 'title' => $term->description));
Dries's avatar
 
Dries committed
39
      }
Dries's avatar
 
Dries committed
40 41 42
    }
    return $links;
  }
Kjartan's avatar
Kjartan committed
43 44
}

45 46 47 48 49 50 51 52
function taxonomy_term_path($term) {
  $vocabulary = taxonomy_get_vocabulary($term->vid);
  if ($vocabulary->module != 'taxonomy' && $path = module_invoke($vocabulary->module, 'term_path', $term)) {
    return $path;
  }
  return 'taxonomy/term/'. $term->tid;
}

Dries's avatar
 
Dries committed
53 54 55
/**
 * Implementation of hook_menu().
 */
Dries's avatar
 
Dries committed
56
function taxonomy_menu($may_cache) {
Dries's avatar
 
Dries committed
57
  $items = array();
Dries's avatar
 
Dries committed
58

Dries's avatar
 
Dries committed
59 60 61 62
  if ($may_cache) {
    $items[] = array('path' => 'admin/taxonomy', 'title' => t('categories'),
      'callback' => 'taxonomy_admin',
      'access' => user_access('administer taxonomy'));
63

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

Dries's avatar
 
Dries committed
67 68 69 70 71
    $items[] = array('path' => 'admin/taxonomy/add/vocabulary', 'title' => t('add vocabulary'),
      'callback' => 'taxonomy_admin',
      'access' => user_access('administer taxonomy'),
      'type' => MENU_LOCAL_TASK);

72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
    $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
87 88 89 90
    $items[] = array('path' => 'taxonomy/term', 'title' => t('taxonomy term'),
      'callback' => 'taxonomy_term_page',
      'access' => user_access('access content'),
      'type' => MENU_CALLBACK);
Steven Wittens's avatar
Steven Wittens committed
91 92 93 94 95

    $items[] = array('path' => 'taxonomy/autocomplete', 'title' => t('autocomplete taxonomy'),
      'callback' => 'taxonomy_autocomplete',
      'access' => user_access('access content'),
      'type' => MENU_CALLBACK);
Dries's avatar
 
Dries committed
96
  }
Dries's avatar
Dries committed
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
  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
113

Dries's avatar
 
Dries committed
114 115
  return $items;
}
Dries's avatar
 
Dries committed
116

Kjartan's avatar
Kjartan committed
117
function taxonomy_form_vocabulary($edit = array()) {
118
  $form['name'] = array('#type' => 'textfield', '#title' => t('Vocabulary name'), '#default_value' => $edit['name'], '#maxlength' => 64, '#description' => t('The name for this vocabulary.  Example: "Topic".'), '#required' => TRUE);
119

120 121
  $form['description'] = array('#type' => 'textarea', '#title' => t('Description'), '#default_value' => $edit['description'], '#description' => t('Description of the vocabulary; can be used by modules.'));
  $form['help'] = array('#type' => 'textfield', '#title' => t('Help text'), '#default_value' => $edit['help'], '#maxlength' => 255, '#description' => t('Instructions to present to the user when choosing a term.'));
122 123
  $form['nodes'] = array('#type' => 'checkboxes', '#title' => t('Types'), '#default_value' => $edit['nodes'], '#options' => node_get_types(), '#description' => t('A list of node types you want to associate with this vocabulary.'), '#required' => TRUE);
  $form['hierarchy'] = array('#type' => 'radios', '#title' => t('Hierarchy'), '#default_value' => $edit['hierarchy'], '#options' => array(t('Disabled'), t('Single'), t('Multiple')), '#description' => 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'))));
124 125 126 127 128
  $form['relations'] = array('#type' => 'checkbox', '#title' => t('Related terms'), '#default_value' => $edit['relations'], '#description' => t('Allows <a href="%help-url">related terms</a> in this vocabulary.', array('%help-url' => url('admin/help/taxonomy', NULL, NULL, 'related-terms'))));
  $form['tags'] = array('#type' => 'checkbox', '#title' => t('Free tagging'), '#default_value' => $edit['tags'], '#description' => t('Content is categorized by typing terms instead of choosing from a list.'));
  $form['multiple'] = array('#type' => 'checkbox', '#title' => t('Multiple select'), '#default_value' => $edit['multiple'], '#description' => t('Allows nodes to have more than one term from this vocabulary (always true for free tagging).'));
  $form['required'] = array('#type' => 'checkbox', '#title' => t('Required'), '#default_value' => $edit['required'], '#description' => t('If enabled, every node <strong>must</strong> have at least one term in this vocabulary.'));
  $form['weight'] = array('#type' => 'weight', '#title' => t('Weight'), '#default_value' => $edit['weight'], '#description' => t('In listings, the heavier vocabularies will sink and the lighter vocabularies will be positioned nearer the top.'));
129

130 131 132 133
  // Add extra vocabulary form elements.
  $extra = module_invoke_all('taxonomy', 'form', 'vocabulary');
  if (is_array($extra)) {
    foreach ($extra as $key => $element) {
134
      $extra[$key]['#weight'] = isset($extra[$key]['#weight']) ? $nodeapi[$key]['#weight'] : -18;
135 136 137
    }
    $form = array_merge($form, $extra);
  }
Dries's avatar
 
Dries committed
138

139
  $form['submit'] = array('#type' => 'submit', '#value' => t('Submit'));
Dries's avatar
 
Dries committed
140
  if ($edit['vid']) {
141 142
    $form['delete'] = array('#type' => 'submit', '#value' => t('Delete'));
    $form['vid'] = array('#type' => 'hidden', '#value' => $edit['vid']);
Dries's avatar
 
Dries committed
143
  }
144
  return drupal_get_form('taxonomy_form_vocabulary', $form);
Kjartan's avatar
Kjartan committed
145
}
Kjartan's avatar
Kjartan committed
146

147
function taxonomy_save_vocabulary(&$edit) {
Dries's avatar
Dries committed
148 149
  $edit['nodes'] = ($edit['nodes']) ? $edit['nodes'] : array();
  $edit['weight'] = ($edit['weight']) ? $edit['weight'] : 0;
150
  $edit['tags'] = ($edit['tags']) ? $edit['tags'] : 0;
Dries's avatar
 
Dries committed
151

Dries's avatar
Dries committed
152
  $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
153
  if ($edit['vid'] && $edit['name']) {
Dries's avatar
 
Dries committed
154
    db_query('UPDATE {vocabulary} SET '. _taxonomy_prepare_update($data) .' WHERE vid = %d', $edit['vid']);
Dries's avatar
 
Dries committed
155
    db_query("DELETE FROM {vocabulary_node_types} WHERE vid = %d", $edit['vid']);
156
    foreach ($edit['nodes'] as $type => $selected) {
Dries's avatar
 
Dries committed
157 158
      db_query("INSERT INTO {vocabulary_node_types} (vid, type) VALUES (%d, '%s')", $edit['vid'], $type);
    }
Dries's avatar
 
Dries committed
159
    module_invoke_all('taxonomy', 'update', 'vocabulary', $edit);
160
    $status = SAVED_UPDATED;
Dries's avatar
 
Dries committed
161
  }
Dries's avatar
 
Dries committed
162
  else if ($edit['vid']) {
163
    $status = taxonomy_del_vocabulary($edit['vid']);
Kjartan's avatar
Kjartan committed
164 165
  }
  else {
Dries's avatar
 
Dries committed
166
    $data['vid'] = $edit['vid'] = db_next_id('{vocabulary}_vid');
Dries's avatar
 
Dries committed
167
    db_query('INSERT INTO {vocabulary} '. _taxonomy_prepare_insert($data, 1) .' VALUES '. _taxonomy_prepare_insert($data, 2));
168
    foreach ($edit['nodes'] as $type => $selected) {
Dries's avatar
 
Dries committed
169 170
      db_query("INSERT INTO {vocabulary_node_types} (vid, type) VALUES (%d, '%s')", $edit['vid'], $type);
    }
Dries's avatar
 
Dries committed
171
    module_invoke_all('taxonomy', 'insert', 'vocabulary', $edit);
172
    $status = SAVED_NEW;
Kjartan's avatar
Kjartan committed
173
  }
Dries's avatar
 
Dries committed
174 175

  cache_clear_all();
Dries's avatar
 
Dries committed
176

177
  return $status;
Kjartan's avatar
Kjartan committed
178
}
Dries's avatar
 
Dries committed
179

Kjartan's avatar
Kjartan committed
180
function taxonomy_del_vocabulary($vid) {
Dries's avatar
 
Dries committed
181 182
  $vocabulary = taxonomy_get_vocabulary($vid);

Dries's avatar
 
Dries committed
183
  db_query('DELETE FROM {vocabulary} WHERE vid = %d', $vid);
Dries's avatar
 
Dries committed
184
  db_query('DELETE FROM {vocabulary_node_types} WHERE vid = %d', $vid);
Dries's avatar
 
Dries committed
185
  $result = db_query('SELECT tid FROM {term_data} WHERE vid = %d', $vid);
Kjartan's avatar
Kjartan committed
186 187
  while ($term = db_fetch_object($result)) {
    taxonomy_del_term($term->tid);
Dries's avatar
 
Dries committed
188
  }
Dries's avatar
 
Dries committed
189

Dries's avatar
 
Dries committed
190
  module_invoke_all('taxonomy', 'delete', 'vocabulary', $vocabulary);
Dries's avatar
 
Dries committed
191

Dries's avatar
 
Dries committed
192 193
  cache_clear_all();

194
  return SAVED_DELETED;
Dries's avatar
 
Dries committed
195 196 197 198 199
}

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

200 201 202
  $form['type'] = array('#type' => 'hidden', '#value' => 'vocabulary');
  $form['vid'] = array('#type' => 'hidden', '#value' => $vid);
  $form['name'] = array('#type' => 'hidden', '#value' => $vocabulary->name);
203 204 205 206
  return confirm_form('vocabulary_confirm_delete', $form,
                  t('Are you sure you want to delete the vocabulary %title?',
                  array('%title' => theme('placeholder', $vocabulary->name))),
                  'admin/taxonomy', t('Deleting a vocabulary will delete all the terms in it. This action cannot be undone.'),
207
                  t('Delete'),
208
                  t('Cancel'));
Kjartan's avatar
Kjartan committed
209
}
Dries's avatar
 
Dries committed
210

Kjartan's avatar
Kjartan committed
211
function taxonomy_form_term($edit = array()) {
Dries's avatar
 
Dries committed
212
  $vocabulary_id = isset($edit['vid']) ? $edit['vid'] : arg(4);
Kjartan's avatar
Kjartan committed
213
  $vocabulary = taxonomy_get_vocabulary($vocabulary_id);
Dries's avatar
 
Dries committed
214

215
  $form['name'] = array('#type' => 'textfield', '#title' => t('Term name'), '#default_value' => $edit['name'], '#maxlength' => 64, '#description' => t('The name for this term.  Example: "Linux".'), '#required' => TRUE);
216

217
  $form['description'] = array('#type' => 'textarea', '#title' => t('Description'), '#default_value' => $edit['description'], '#description' => t('A description of the term.'));
Dries's avatar
 
Dries committed
218

Kjartan's avatar
Kjartan committed
219
  if ($vocabulary->hierarchy) {
Dries's avatar
 
Dries committed
220 221
    $parent = array_keys(taxonomy_get_parents($edit['tid']));
    $children = taxonomy_get_tree($vocabulary_id, $edit['tid']);
Dries's avatar
 
Dries committed
222

Dries's avatar
 
Dries committed
223
    // A term can't be the child of itself, nor of its children.
Dries's avatar
 
Dries committed
224 225 226
    foreach ($children as $child) {
      $exclude[] = $child->tid;
    }
Dries's avatar
 
Dries committed
227
    $exclude[] = $edit['tid'];
Dries's avatar
 
Dries committed
228

Kjartan's avatar
Kjartan committed
229
    if ($vocabulary->hierarchy == 1) {
230
      $form['parent'] = _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
231
    }
Kjartan's avatar
Kjartan committed
232
    elseif ($vocabulary->hierarchy == 2) {
233
      $form['parent'] = _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
234
    }
Kjartan's avatar
Kjartan committed
235
  }
Dries's avatar
 
Dries committed
236

237
  if ($vocabulary->relations) {
238
    $form['relations'] = _taxonomy_term_select(t('Related terms'), 'relations', array_keys(taxonomy_get_related($edit['tid'])), $vocabulary_id, NULL, 1, '<'. t('none') .'>', array($edit['tid']));
239 240
  }

241 242
  $form['synonyms'] = array('#type' => 'textarea', '#title' => t('Synonyms'), '#default_value' => implode("\n", taxonomy_get_synonyms($edit['tid'])), '#description' => t('<a href="%help-url">Synonyms</a> of this term, one synonym per line.', array('%help-url' => url('admin/help/taxonomy', NULL, NULL, 'synonyms'))));
  $form['weight'] = array('#type' => 'weight', '#title' => t('Weight'), '#default_value' => $edit['weight'], '#description' => t('In listings, the heavier terms will sink and the lighter terms will be positioned nearer the top.'));
243 244 245 246 247

  // Add extra term form elements.
  $extra = module_invoke_all('taxonomy', 'term', 'vocabulary');
  if (is_array($extra)) {
    foreach ($extra as $key => $element) {
248
      $extra[$key]['#weight'] = isset($extra[$key]['#weight']) ? $nodeapi[$key]['#weight'] : -18;
249 250 251 252 253
    }
    $form = array_merge($form, $extra);
  }


254 255
  $form['vid'] = array('#type' => 'hidden', '#value' => $vocabulary->vid);
  $form['submit'] = array('#type' => 'submit', '#value' => t('Submit'));
Kjartan's avatar
Kjartan committed
256

Dries's avatar
 
Dries committed
257
  if ($edit['tid']) {
258 259
    $form['delete'] = array('#type' => 'submit', '#value' => t('Delete'));
    $form['tid'] = array('#type' => 'hidden', '#value' => $edit['tid']);
Dries's avatar
 
Dries committed
260
  }
261
  else {
262
    $form['destination'] = array('#type' => 'hidden', '#value' => $_GET['q']);
263
  }
Dries's avatar
 
Dries committed
264

265
  return drupal_get_form('taxonomy_form_term', $form);
Kjartan's avatar
Kjartan committed
266
}
Dries's avatar
 
Dries committed
267

268
function taxonomy_save_term(&$edit) {
Dries's avatar
 
Dries committed
269 270
  if ($edit['tid'] && $edit['name']) {
    $data = array('name' => $edit['name'], 'description' => $edit['description'], 'weight' => $edit['weight']);
Dries's avatar
 
Dries committed
271

Dries's avatar
 
Dries committed
272
    db_query('UPDATE {term_data} SET '. _taxonomy_prepare_update($data) .' WHERE tid = %d', $edit['tid']);
Dries's avatar
 
Dries committed
273
    module_invoke_all('taxonomy', 'update', 'term', $edit);
274
    $status = SAVED_UPDATED;
Kjartan's avatar
Kjartan committed
275
  }
Dries's avatar
 
Dries committed
276 277
  else if ($edit['tid']) {
    return taxonomy_del_term($edit['tid']);
Kjartan's avatar
Kjartan committed
278 279
  }
  else {
Dries's avatar
 
Dries committed
280 281
    $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
282
    db_query('INSERT INTO {term_data} '. _taxonomy_prepare_insert($data, 1) .' VALUES '. _taxonomy_prepare_insert($data, 2));
Dries's avatar
 
Dries committed
283
    module_invoke_all('taxonomy', 'insert', 'term', $edit);
284
    $status = SAVED_NEW;
Kjartan's avatar
Kjartan committed
285
  }
Dries's avatar
 
Dries committed
286

Dries's avatar
 
Dries committed
287 288 289
  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
290
      if ($related_id != 0) {
Dries's avatar
 
Dries committed
291
        db_query('INSERT INTO {term_relation} (tid1, tid2) VALUES (%d, %d)', $edit['tid'], $related_id);
Dries's avatar
 
Dries committed
292
      }
Kjartan's avatar
Kjartan committed
293
    }
Kjartan's avatar
Kjartan committed
294
  }
Dries's avatar
 
Dries committed
295

Dries's avatar
 
Dries committed
296 297
  db_query('DELETE FROM {term_hierarchy} WHERE tid = %d', $edit['tid']);
  if (!isset($edit['parent'])) {
298
    $edit['parent'] = array(0);
Kjartan's avatar
Kjartan committed
299
  }
Dries's avatar
 
Dries committed
300 301
  if (is_array($edit['parent'])) {
    foreach ($edit['parent'] as $parent) {
302 303 304 305 306 307 308 309
      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
310
    }
Kjartan's avatar
Kjartan committed
311
  }
312 313 314
  else {
    db_query('INSERT INTO {term_hierarchy} (tid, parent) VALUES (%d, %d)', $edit['tid'], $edit['parent']);
  }
Dries's avatar
 
Dries committed
315

Dries's avatar
 
Dries committed
316 317 318
  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
319
      if ($synonym) {
Dries's avatar
 
Dries committed
320
        db_query("INSERT INTO {term_synonym} (tid, name) VALUES (%d, '%s')", $edit['tid'], chop($synonym));
Dries's avatar
 
Dries committed
321
      }
Kjartan's avatar
Kjartan committed
322
    }
Dries's avatar
 
Dries committed
323
  }
Dries's avatar
 
Dries committed
324

Dries's avatar
 
Dries committed
325 326
  cache_clear_all();

327
  return $status;
Kjartan's avatar
Kjartan committed
328
}
Dries's avatar
 
Dries committed
329

Kjartan's avatar
Kjartan committed
330
function taxonomy_del_term($tid) {
331 332 333 334 335 336 337 338 339 340 341 342 343 344
  $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
345

346
      $term = taxonomy_get_term($tid);
Dries's avatar
 
Dries committed
347

348 349 350 351 352
      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
353

354
      module_invoke_all('taxonomy', 'delete', 'term', $term);
355
      drupal_set_message(t('Deleted term %name.', array('%name' => theme('placeholder', $term->name))));
356
    }
Dries's avatar
 
Dries committed
357

358 359
    $tids = $orphans;
  }
Dries's avatar
 
Dries committed
360

Dries's avatar
 
Dries committed
361
  cache_clear_all();
Dries's avatar
 
Dries committed
362 363 364 365 366
}

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

367 368
  $form['type'] = array('#type' => 'hidden', '#value' => 'term');
  $form['tid'] = array('#type' => 'hidden', '#value' => $tid);
369 370 371
  return confirm_form('term_confirm_delete', $form,
                  t('Are you sure you want to delete the term %title?',
                  array('%title' => theme('placeholder', $term->name))),
372 373 374
                  'admin/taxonomy',
                  t('Deleting a term will delete all its children if there are any. This action cannot be undone.'),
                  t('Delete'),
375
                  t('Cancel'));
Kjartan's avatar
Kjartan committed
376
}
Dries's avatar
 
Dries committed
377

Dries's avatar
 
Dries committed
378 379 380
/**
 * Generate a tabular listing of administrative functions for vocabularies.
 */
Kjartan's avatar
Kjartan committed
381
function taxonomy_overview() {
Dries's avatar
Dries committed
382 383
  $vid = arg(2);

384
  // Show all vocabularies, and a "view terms" link to the pagers.
Dries's avatar
Dries committed
385
  if (!$vid) {
386
    $header = array(t('Name'), t('Type'), array('data' => t('Operations'), 'colspan' => '2'));
Dries's avatar
Dries committed
387 388
    $vocabularies = taxonomy_get_vocabularies();
    foreach ($vocabularies as $vocabulary) {
389 390
      $types = array();
      foreach ($vocabulary->nodes as $type) {
391
        $node_type = node_get_name($type);
392 393
        $types[] = $node_type ? $node_type : $type;
      }
Dries's avatar
Dries committed
394
      $rows[] = array(check_plain($vocabulary->name), implode(', ', $types), l(t('edit vocabulary'), "admin/taxonomy/edit/vocabulary/$vocabulary->vid"), l(t('edit terms'), "admin/taxonomy/$vocabulary->vid"));
Dries's avatar
Dries committed
395 396 397
    }

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

402
  // Show the vocabulary's terms with a pager.
Dries's avatar
Dries committed
403
  else {
404 405 406
    $destination = drupal_get_destination();

    $header = array(t('Name'), t('Operations'));
Dries's avatar
Dries committed
407
    $vocabulary = taxonomy_get_vocabulary($vid);
408

Dries's avatar
Dries committed
409 410 411 412 413 414 415 416 417 418
    drupal_set_title(check_plain($vocabulary->name));
    $start_from      = $_GET['page'] ? $_GET['page'] : 0;
    $total_entries   = 0;  // total count for pager
    $page_increment  = 25; // number of tids per page
    $displayed_count = 0;  // number of tids shown

    $tree = taxonomy_get_tree($vocabulary->vid);
    foreach ($tree as $term) {
      $total_entries++; // we're counting all-totals, not displayed
      if (($start_from && ($start_from * $page_increment) >= $total_entries) || ($displayed_count == $page_increment)) { continue; }
419
      $rows[] = array(_taxonomy_depth($term->depth) . ' ' . l(check_plain($term->name), "taxonomy/term/$term->tid"), l(t('edit'), "admin/taxonomy/edit/term/$term->tid", array(), $destination));
Dries's avatar
Dries committed
420 421 422 423 424 425
      $displayed_count++; // we're counting tids displayed
    }

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

Dries's avatar
Dries committed
427 428
    $GLOBALS['pager_page_array'][] = $start_from;  // FIXME
    $GLOBALS['pager_total'][] = intval($total_entries / $page_increment) + 1; // FIXME
429

Dries's avatar
Dries committed
430 431
    if ($total_entries >= $page_increment) {
      $rows[] = array(array('data' => theme('pager', NULL, $page_increment), 'colspan' => '2'));
Dries's avatar
Dries committed
432
    }
Dries's avatar
 
Dries committed
433 434
  }

Dries's avatar
Dries committed
435
  return theme('table', $header, $rows, array('id' => 'taxonomy'));
Kjartan's avatar
Kjartan committed
436 437
}

Dries's avatar
 
Dries committed
438 439 440
/**
 * Generate a form element for selecting terms from a vocabulary.
 */
Dries's avatar
 
Dries committed
441
function taxonomy_form($vid, $value = 0, $help = NULL, $name = 'taxonomy') {
Dries's avatar
 
Dries committed
442
  $vocabulary = taxonomy_get_vocabulary($vid);
443
  $help = ($help) ? $help : $vocabulary->help;
Kjartan's avatar
Kjartan committed
444 445 446 447
  if ($vocabulary->required) {
    $blank = 0;
  }
  else {
Dries's avatar
 
Dries committed
448
    $blank = '<'. t('none') .'>';
Kjartan's avatar
Kjartan committed
449
  }
Dries's avatar
 
Dries committed
450

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

Dries's avatar
 
Dries committed
454 455 456 457 458 459
/**
 * 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
460
function taxonomy_get_vocabularies($type = NULL) {
Kjartan's avatar
Kjartan committed
461
  if ($type) {
462
    $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);
Kjartan's avatar
Kjartan committed
463 464
  }
  else {
465
    $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'));
Kjartan's avatar
Kjartan committed
466
  }
Dries's avatar
 
Dries committed
467

Kjartan's avatar
Kjartan committed
468
  $vocabularies = array();
Dries's avatar
 
Dries committed
469
  $node_types = array();
Kjartan's avatar
Kjartan committed
470
  while ($voc = db_fetch_object($result)) {
Dries's avatar
 
Dries committed
471 472 473 474
    $node_types[$voc->vid][] = $voc->type;
    unset($voc->type);
    $voc->nodes = $node_types[$voc->vid];
    $vocabularies[$voc->vid] = $voc;
Dries's avatar
 
Dries committed
475
  }
Dries's avatar
 
Dries committed
476

Kjartan's avatar
Kjartan committed
477 478
  return $vocabularies;
}
Dries's avatar
 
Dries committed
479

Dries's avatar
 
Dries committed
480 481 482
/**
 * Generate a form for selecting terms to associate with a node.
 */
483
function taxonomy_node_form($node) {
Dries's avatar
Dries committed
484
  if (!array_key_exists('taxonomy', $node)) {
Kjartan's avatar
Kjartan committed
485
    if ($node->nid) {
Dries's avatar
Dries committed
486
      $terms = taxonomy_node_get_terms($node->nid);
Kjartan's avatar
Kjartan committed
487 488
    }
    else {
Dries's avatar
Dries committed
489
      $terms = array();
Dries's avatar
 
Dries committed
490
    }
Kjartan's avatar
Kjartan committed
491 492 493 494
  }
  else {
    $terms = $node->taxonomy;
  }
Dries's avatar
 
Dries committed
495

496
  $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);
Kjartan's avatar
Kjartan committed
497
  while ($vocabulary = db_fetch_object($c)) {
Dries's avatar
Dries committed
498 499 500 501 502 503 504 505 506 507 508 509 510 511
    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);
512

513
      $form['taxonomy']['tags'][$vocabulary->vid] = array('#type' => 'textfield', '#default_value' => $typed_string, '#maxlength' => 100, '#autocomplete_path' => 'taxonomy/autocomplete/'. $vocabulary->vid, '#required' => $vocabulary->required, '#title' => $vocabulary->name, '#description' => t('A comma-separated list of terms describing this content (Example: funny, bungie jumping, "Company, Inc.").'));
Dries's avatar
Dries committed
514 515 516
    }
    else {
      $ntterms = array_key_exists('taxonomy', $node) ? $terms : array_keys($terms);
517
      $form['taxonomy'][$vocabulary->vid] = taxonomy_form($vocabulary->vid, $ntterms, $help, 'taxonomy');
Dries's avatar
Dries committed
518
    }
Dries's avatar
 
Dries committed
519
  }
520 521 522 523 524 525 526 527
  if ($form) {
    $form['taxonomy']['#tree'] = TRUE;
    $form['taxonomy']['#weight'] = -15;
    return $form;
  }
  else {
    return array();
  }
Kjartan's avatar
Kjartan committed
528
}
Dries's avatar
 
Dries committed
529

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

Dries's avatar
 
Dries committed
542
/**
543
 * Find all terms associated to the given node, ordered by vocabulary and term weight.
Dries's avatar
 
Dries committed
544 545
 */
function taxonomy_node_get_terms($nid, $key = 'tid') {
Kjartan's avatar
Kjartan committed
546
  static $terms;
Dries's avatar
 
Dries committed
547

Dries's avatar
 
Dries committed
548
  if (!isset($terms[$nid])) {
549
    $result = db_query('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.nid = %d ORDER BY v.weight, t.weight, t.name', $nid);
Kjartan's avatar
Kjartan committed
550
    $terms[$nid] = array();
Dries's avatar
 
Dries committed
551
    while ($term = db_fetch_object($result)) {
Kjartan's avatar
Kjartan committed
552
      $terms[$nid][$term->$key] = $term;
Dries's avatar
 
Dries committed
553 554
    }
  }
Kjartan's avatar
Kjartan committed
555 556
  return $terms[$nid];
}
Dries's avatar
 
Dries committed
557

Dries's avatar
Dries committed
558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574
/**
 * 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
575 576 577
/**
 * Save term associations for a given node.
 */
Kjartan's avatar
Kjartan committed
578
function taxonomy_node_save($nid, $terms) {
579
  taxonomy_node_delete($nid);
Dries's avatar
Dries committed
580 581 582 583 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

  // 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) {
613 614 615
          $edit = array('vid' => $vid, 'name' => $typed_term);
          $status = taxonomy_save_term($edit);
          $typed_term_tid = $edit['tid'];
Dries's avatar
Dries committed
616 617 618 619 620 621
        }

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

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

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

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

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

Dries's avatar
 
Dries committed
680 681 682 683
/**
 * Find all ancestors of a given term ID.
 */
function taxonomy_get_parents_all($tid) {
Dries's avatar
 
Dries committed
684 685 686 687 688 689 690 691 692 693 694 695
  $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
696 697 698 699
/**
 * Find all children of a term ID.
 */
function taxonomy_get_children($tid, $vid = 0, $key = 'tid') {
Kjartan's avatar
Kjartan committed
700
  if ($vid) {
701
    $result = db_query(db_rewrite_sql('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', 't', 'tid'), $vid, $tid);
Dries's avatar
 
Dries committed
702
  }
Kjartan's avatar
Kjartan committed
703
  else {
704
    $result = db_query(db_rewrite_sql('SELECT t.* FROM {term_hierarchy} h, {term_data} t WHERE h.tid = t.tid AND parent = %d ORDER BY weight, name', 't', 'tid'), $tid);
Kjartan's avatar
Kjartan committed
705 706 707 708 709 710 711
  }
  $children = array();
  while ($term = db_fetch_object($result)) {
    $children[$term->$key] = $term;
  }
  return $children;
}
Dries's avatar
 
Dries committed
712

Dries's avatar
 
Dries committed
713 714 715 716 717 718 719 720 721 722 723 724 725
/**
 * 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
726 727 728
 * @param $max_depth
 *   The number of levels of the tree to return. Leave NULL to return all levels.
 *
Dries's avatar
 
Dries committed
729 730 731 732 733
 * @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
734
  static $children, $parents, $terms;
Dries's avatar
 
Dries committed
735

Kjartan's avatar
Kjartan committed
736
  $depth++;
Dries's avatar
 
Dries committed
737

Dries's avatar
 
Dries committed
738 739 740 741
  // 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
742

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

Dries's avatar
 
Dries committed
751
  $max_depth = (is_null($max_depth)) ? count($children[$vid]) : $max_depth;
Dries's avatar
Dries committed
752 753 754 755 756 757 758 759 760 761 762 763
  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
764
      }
Dries's avatar
 
Dries committed
765
    }
Kjartan's avatar
Kjartan committed
766
  }
Dries's avatar
 
Dries committed
767

Dries's avatar
 
Dries committed
768
  return $tree ? $tree : array();
Kjartan's avatar
Kjartan committed
769
}
Dries's avatar
 
Dries committed
770

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

Dries's avatar
 
Dries committed
787 788 789 790 791
/**
 * 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
792
}
Dries's avatar
 
Dries committed
793

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

Dries's avatar
 
Dries committed
800 801 802
  if (!isset($count[$type])) {
    // $type == 0 always evaluates true is $type is a string
    if (is_numeric($type)) {