taxonomy.module 51.3 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
      }
    }
    else {
      foreach (taxonomy_node_get_terms($node->nid) as $term) {
Dries's avatar
 
Dries committed
38
        $links[] = l($term->name, 'taxonomy/term/'. $term->tid);
Dries's avatar
 
Dries committed
39
      }
Dries's avatar
 
Dries committed
40 41 42
    }
    return $links;
  }
Kjartan's avatar
Kjartan committed
43 44
}

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

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

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

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

64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
    $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
79 80 81 82
    $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
83 84 85 86 87

    $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
88
  }
Dries's avatar
Dries committed
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
  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
105

Dries's avatar
 
Dries committed
106 107
  return $items;
}
Dries's avatar
 
Dries committed
108

Kjartan's avatar
Kjartan committed
109
function taxonomy_form_vocabulary($edit = array()) {
110
  $form .= form_textfield(t('Vocabulary name'), 'name', $edit['name'], 60, 64, t('The name for this vocabulary.  Example: "Topic".'), NULL, TRUE);
111 112
  // Prepend extra vocabulary form elements.
  $form .= implode('', module_invoke_all('taxonomy', 'form pre', 'vocabulary', $edit));
Dries's avatar
 
Dries committed
113
  $form .= form_textarea(t('Description'), 'description', $edit['description'], 60, 5, t('Description of the vocabulary; can be used by modules.'));
114
  $form .= form_textfield(t('Help text'), 'help', $edit['help'], 60, 255, t('Instructions to present to the user when choosing a term.'));
115
  $form .= form_checkboxes(t('Types'), 'nodes', $edit['nodes'], node_get_types(), 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.'));
122 123
  // Append extra vocabulary form elements.
  $form .= implode('', module_invoke_all('taxonomy', 'form post', 'vocabulary', $edit));
Dries's avatar
 
Dries committed
124
  $form .= form_submit(t('Submit'));
Dries's avatar
 
Dries committed
125

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

Kjartan's avatar
Kjartan committed
131 132
  return form($form);
}
Kjartan's avatar
Kjartan committed
133

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

Dries's avatar
Dries committed
138
  $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
139
  if ($edit['vid'] && $edit['name']) {
Dries's avatar
 
Dries committed
140
    db_query('UPDATE {vocabulary} SET '. _taxonomy_prepare_update($data) .' WHERE vid = %d', $edit['vid']);
Dries's avatar
 
Dries committed
141 142 143 144
    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
145
    module_invoke_all('taxonomy', 'update', 'vocabulary', $edit);
146
    $status = SAVED_UPDATED;
Dries's avatar
 
Dries committed
147
  }
Dries's avatar
 
Dries committed
148
  else if ($edit['vid']) {
149
    $status = taxonomy_del_vocabulary($edit['vid']);
Kjartan's avatar
Kjartan committed
150 151
  }
  else {
Dries's avatar
 
Dries committed
152
    $data['vid'] = $edit['vid'] = db_next_id('{vocabulary}_vid');
Dries's avatar
 
Dries committed
153
    db_query('INSERT INTO {vocabulary} '. _taxonomy_prepare_insert($data, 1) .' VALUES '. _taxonomy_prepare_insert($data, 2));
Dries's avatar
 
Dries committed
154 155 156
    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
157
    module_invoke_all('taxonomy', 'insert', 'vocabulary', $edit);
158
    $status = SAVED_NEW;
Kjartan's avatar
Kjartan committed
159
  }
Dries's avatar
 
Dries committed
160 161

  cache_clear_all();
Dries's avatar
 
Dries committed
162

163
  return array('status' => $status, 'object' => $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();

180
  return SAVED_DELETED;
Dries's avatar
 
Dries committed
181 182 183 184 185
}

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

186 187
  $extra  = form_hidden('type', 'vocabulary');
  $extra .= form_hidden('vid', $vid);
188
  $extra .= form_hidden('name', $vocabulary->name);
189 190

  $output = theme('confirm',
191
                  t('Are you sure you want to delete the vocabulary %title?', array('%title' => theme('placeholder', $vocabulary->name))),
192 193 194 195 196 197
                  '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
198
}
Dries's avatar
 
Dries committed
199

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

204
  $form = form_textfield(t('Term name'), 'name', $edit['name'], 60, 64, t('The name for this term.  Example: "Linux".'), NULL, TRUE);
205 206
  // Prepend extra term form elements.
  $form .= implode('', module_invoke_all('taxonomy', 'form pre', 'term', $edit));
Dries's avatar
 
Dries committed
207
  $form .= form_textarea(t('Description'), 'description', $edit['description'], 60, 5, t('A description of the term.'));
Dries's avatar
 
Dries committed
208

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

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

Kjartan's avatar
Kjartan committed
219
    if ($vocabulary->hierarchy == 1) {
220
      $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
221
    }
Kjartan's avatar
Kjartan committed
222
    elseif ($vocabulary->hierarchy == 2) {
223
      $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
224
    }
Kjartan's avatar
Kjartan committed
225
  }
Dries's avatar
 
Dries committed
226

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

231
  $form .= form_textarea(t('Synonyms'), 'synonyms', implode("\n", taxonomy_get_synonyms($edit['tid'])), 60, 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
232
  $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.'));
233 234
  // Append extra term form elements.
  $form .= implode('', module_invoke_all('taxonomy', 'form post', 'term', $edit));
Dries's avatar
 
Dries committed
235 236
  $form .= form_hidden('vid', $vocabulary->vid);
  $form .= form_submit(t('Submit'));
Kjartan's avatar
Kjartan committed
237

Dries's avatar
 
Dries committed
238 239 240
  if ($edit['tid']) {
    $form .= form_submit(t('Delete'));
    $form .= form_hidden('tid', $edit['tid']);
Dries's avatar
 
Dries committed
241
  }
242 243 244
  else {
    $form .= form_hidden('destination', $_GET['q']);
  }
Dries's avatar
 
Dries committed
245

Kjartan's avatar
Kjartan committed
246 247
  return form($form);
}
Dries's avatar
 
Dries committed
248

Kjartan's avatar
Kjartan committed
249
function taxonomy_save_term($edit) {
Dries's avatar
 
Dries committed
250 251
  if ($edit['tid'] && $edit['name']) {
    $data = array('name' => $edit['name'], 'description' => $edit['description'], 'weight' => $edit['weight']);
Dries's avatar
 
Dries committed
252

Dries's avatar
 
Dries committed
253
    db_query('UPDATE {term_data} SET '. _taxonomy_prepare_update($data) .' WHERE tid = %d', $edit['tid']);
Dries's avatar
 
Dries committed
254
    module_invoke_all('taxonomy', 'update', 'term', $edit);
255
    $status = SAVED_UPDATED;
Kjartan's avatar
Kjartan committed
256
  }
Dries's avatar
 
Dries committed
257 258
  else if ($edit['tid']) {
    return taxonomy_del_term($edit['tid']);
Kjartan's avatar
Kjartan committed
259 260
  }
  else {
Dries's avatar
 
Dries committed
261 262
    $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
263
    db_query('INSERT INTO {term_data} '. _taxonomy_prepare_insert($data, 1) .' VALUES '. _taxonomy_prepare_insert($data, 2));
Dries's avatar
 
Dries committed
264
    module_invoke_all('taxonomy', 'insert', 'term', $edit);
265
    $status = SAVED_NEW;
Kjartan's avatar
Kjartan committed
266
  }
Dries's avatar
 
Dries committed
267

Dries's avatar
 
Dries committed
268 269 270
  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
271
      if ($related_id != 0) {
Dries's avatar
 
Dries committed
272
        db_query('INSERT INTO {term_relation} (tid1, tid2) VALUES (%d, %d)', $edit['tid'], $related_id);
Dries's avatar
 
Dries committed
273
      }
Kjartan's avatar
Kjartan committed
274
    }
Kjartan's avatar
Kjartan committed
275
  }
Dries's avatar
 
Dries committed
276

Dries's avatar
 
Dries committed
277 278
  db_query('DELETE FROM {term_hierarchy} WHERE tid = %d', $edit['tid']);
  if (!isset($edit['parent'])) {
279
    $edit['parent'] = array(0);
Kjartan's avatar
Kjartan committed
280
  }
Dries's avatar
 
Dries committed
281 282
  if (is_array($edit['parent'])) {
    foreach ($edit['parent'] as $parent) {
283 284 285 286 287 288 289 290
      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
291
    }
Kjartan's avatar
Kjartan committed
292
  }
Dries's avatar
 
Dries committed
293

Dries's avatar
 
Dries committed
294 295 296
  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
297
      if ($synonym) {
Dries's avatar
 
Dries committed
298
        db_query("INSERT INTO {term_synonym} (tid, name) VALUES (%d, '%s')", $edit['tid'], chop($synonym));
Dries's avatar
 
Dries committed
299
      }
Kjartan's avatar
Kjartan committed
300
    }
Dries's avatar
 
Dries committed
301
  }
Dries's avatar
 
Dries committed
302

Dries's avatar
 
Dries committed
303 304
  cache_clear_all();

305
  return array('status' => $status, 'object' => $edit);
Kjartan's avatar
Kjartan committed
306
}
Dries's avatar
 
Dries committed
307

Kjartan's avatar
Kjartan committed
308
function taxonomy_del_term($tid) {
309 310 311 312 313 314 315 316 317 318 319 320 321 322
  $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
323

324
      $term = taxonomy_get_term($tid);
Dries's avatar
 
Dries committed
325

326 327 328 329 330
      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
331

332
      module_invoke_all('taxonomy', 'delete', 'term', $term);
333
      drupal_set_message(t('Deleted term %name.', array('%name' => theme('placeholder', $term->name))));
334
    }
Dries's avatar
 
Dries committed
335

336 337
    $tids = $orphans;
  }
Dries's avatar
 
Dries committed
338

Dries's avatar
 
Dries committed
339
  cache_clear_all();
Dries's avatar
 
Dries committed
340 341 342 343 344
}

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

345 346
  $extra  = form_hidden('type', 'term');
  $extra .= form_hidden('tid', $tid);
Dries's avatar
 
Dries committed
347

348
  $output = theme('confirm',
349
                  t('Are you sure you want to delete the term %title?', array('%title' => theme('placeholder', $term->name))),
350 351 352 353 354
                  '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);
355 356

  return $output;
Kjartan's avatar
Kjartan committed
357
}
Dries's avatar
 
Dries committed
358

Dries's avatar
 
Dries committed
359 360 361
/**
 * Generate a tabular listing of administrative functions for vocabularies.
 */
Kjartan's avatar
Kjartan committed
362
function taxonomy_overview() {
Dries's avatar
Dries committed
363 364
  $vid = arg(2);

365
  // Show all vocabularies, and a "view terms" link to the pagers.
Dries's avatar
Dries committed
366
  if (!$vid) {
367
    $header = array(t('Name'), t('Type'), array('data' => t('Operations'), 'colspan' => '2'));
Dries's avatar
Dries committed
368 369
    $vocabularies = taxonomy_get_vocabularies();
    foreach ($vocabularies as $vocabulary) {
370 371
      $types = array();
      foreach ($vocabulary->nodes as $type) {
372
        $node_type = node_get_name($type);
373 374
        $types[] = $node_type ? $node_type : $type;
      }
Dries's avatar
Dries committed
375
      $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
376 377 378
    }

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

383
  // Show the vocabulary's terms with a pager.
Dries's avatar
Dries committed
384
  else {
385 386 387
    $destination = drupal_get_destination();

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

Dries's avatar
Dries committed
390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406
    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; }
      $rows[] = array(_taxonomy_depth($term->depth) . ' ' . check_plain($term->name), l(t('edit'), "admin/taxonomy/edit/term/$term->tid", array(), $destination));
      $displayed_count++; // we're counting tids displayed
    }

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

Dries's avatar
Dries committed
408 409
    $GLOBALS['pager_page_array'][] = $start_from;  // FIXME
    $GLOBALS['pager_total'][] = intval($total_entries / $page_increment) + 1; // FIXME
410

Dries's avatar
Dries committed
411 412
    if ($total_entries >= $page_increment) {
      $rows[] = array(array('data' => theme('pager', NULL, $page_increment), 'colspan' => '2'));
Dries's avatar
Dries committed
413
    }
Dries's avatar
 
Dries committed
414 415
  }

Dries's avatar
Dries committed
416
  return theme('table', $header, $rows, array('id' => 'taxonomy'));
Kjartan's avatar
Kjartan committed
417 418
}

Dries's avatar
 
Dries committed
419 420 421
/**
 * Generate a form element for selecting terms from a vocabulary.
 */
Dries's avatar
 
Dries committed
422
function taxonomy_form($vid, $value = 0, $help = NULL, $name = 'taxonomy') {
Dries's avatar
 
Dries committed
423
  $vocabulary = taxonomy_get_vocabulary($vid);
424
  $help = ($help) ? $help : $vocabulary->help;
Kjartan's avatar
Kjartan committed
425 426 427 428
  if ($vocabulary->required) {
    $blank = 0;
  }
  else {
Dries's avatar
 
Dries committed
429
    $blank = '<'. t('none') .'>';
Kjartan's avatar
Kjartan committed
430
  }
Dries's avatar
 
Dries committed
431

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

435
/**
436 437 438
 * Generate a set of options for selecting a term from all vocabularies. Can be
 * passed to form_select.
 */
Dries's avatar
Dries committed
439
function taxonomy_form_all($free_tags = 0) {
440 441 442
  $vocabularies = taxonomy_get_vocabularies();
  $options = array();
  foreach ($vocabularies as $vid => $vocabulary) {
Dries's avatar
Dries committed
443
    if ($vocabulary->tags && !$free_tags) { continue; }
444 445 446 447 448 449 450 451 452 453 454
    $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
455 456 457 458 459 460
/**
 * 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
461
function taxonomy_get_vocabularies($type = NULL) {
Kjartan's avatar
Kjartan committed
462
  if ($type) {
463
    $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
464 465
  }
  else {
466
    $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
467
  }
Dries's avatar
 
Dries committed
468

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

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

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

Dries's avatar
 
Dries committed
497
  $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
498
  while ($vocabulary = db_fetch_object($c)) {
Dries's avatar
Dries committed
499 500 501 502 503 504 505 506 507 508 509 510 511 512
    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);
513
      $result[] = form_autocomplete($vocabulary->name, "$name][tags][". $vocabulary->vid, $typed_string, 60, 100, 'taxonomy/autocomplete/'. $vocabulary->vid, 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
514 515 516 517 518
    }
    else {
      $ntterms = array_key_exists('taxonomy', $node) ? $terms : array_keys($terms);
      $result[] = taxonomy_form($vocabulary->vid, $ntterms, $help, $name);
    }
Dries's avatar
 
Dries committed
519
  }
Kjartan's avatar
Kjartan committed
520 521
  return $result ? $result : array();
}
Dries's avatar
 
Dries committed
522

Dries's avatar
 
Dries committed
523 524 525 526 527
/**
 * 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
528 529 530
  $terms = array();
  while ($term = db_fetch_object($result)) {
    $terms[$term->$key] = $term;
Dries's avatar
 
Dries committed
531
  }
Kjartan's avatar
Kjartan committed
532 533 534
  return $terms;
}

Dries's avatar
 
Dries committed
535
/**
536
 * Find all terms associated to the given node, ordered by vocabulary and term weight.
Dries's avatar
 
Dries committed
537 538
 */
function taxonomy_node_get_terms($nid, $key = 'tid') {
Kjartan's avatar
Kjartan committed
539
  static $terms;
Dries's avatar
 
Dries committed
540

Dries's avatar
 
Dries committed
541
  if (!isset($terms[$nid])) {
542
    $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
543
    $terms[$nid] = array();
Dries's avatar
 
Dries committed
544
    while ($term = db_fetch_object($result)) {
Kjartan's avatar
Kjartan committed
545
      $terms[$nid][$term->$key] = $term;
Dries's avatar
 
Dries committed
546 547
    }
  }
Kjartan's avatar
Kjartan committed
548 549
  return $terms[$nid];
}
Dries's avatar
 
Dries committed
550

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

  // 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) {
606 607
          list($status, $object) = array_values(taxonomy_save_term(array('vid' => $vid, 'name' => $typed_term)));
          $typed_term_tid = $object['tid'];
Dries's avatar
Dries committed
608 609 610 611 612 613
        }

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

615
  if (is_array($terms)) {
Dries's avatar
 
Dries committed
616
    foreach ($terms as $term) {
617 618 619 620 621 622 623
      if (is_array($term)) {
        foreach ($term as $tid) {
          if ($tid) {
            db_query('INSERT INTO {term_node} (nid, tid) VALUES (%d, %d)', $nid, $tid);
          }
        }
      }
624
      else if ($term) {
Dries's avatar
 
Dries committed
625
        db_query('INSERT INTO {term_node} (nid, tid) VALUES (%d, %d)', $nid, $term);
626
      }
Dries's avatar
 
Dries committed
627 628
    }
  }
Kjartan's avatar
Kjartan committed
629
}
Dries's avatar
 
Dries committed
630

Dries's avatar
 
Dries committed
631 632 633
/**
 * Remove associations of a node to its terms.
 */
Kjartan's avatar
Kjartan committed
634
function taxonomy_node_delete($nid) {
Dries's avatar
 
Dries committed
635
  db_query('DELETE FROM {term_node} WHERE nid = %d', $nid);
Kjartan's avatar
Kjartan committed
636
}
Dries's avatar
 
Dries committed
637

Dries's avatar
 
Dries committed
638 639 640 641
/**
 * Find all term objects related to a given term ID.
 */
function taxonomy_get_related($tid, $key = 'tid') {
Kjartan's avatar
Kjartan committed
642
  if ($tid) {
Dries's avatar
 
Dries committed
643
    $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
644 645 646
    $related = array();
    while ($term = db_fetch_object($result)) {
      $related[$term->$key] = $term;
Dries's avatar
 
Dries committed
647
    }
Kjartan's avatar
Kjartan committed
648
    return $related;
Dries's avatar
 
Dries committed
649
  }
Kjartan's avatar
Kjartan committed
650 651
  else {
    return array();
Dries's avatar
 
Dries committed
652
  }
Kjartan's avatar
Kjartan committed
653
}
Dries's avatar
 
Dries committed
654

Dries's avatar
 
Dries committed
655 656 657 658
/**
 * Find all parents of a given term ID.
 */
function taxonomy_get_parents($tid, $key = 'tid') {
Kjartan's avatar
Kjartan committed
659
  if ($tid) {
Dries's avatar
 
Dries committed
660
    $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
661 662 663
    $parents = array();
    while ($parent = db_fetch_object($result)) {
      $parents[$parent->$key] = $parent;
Dries's avatar
 
Dries committed
664
    }
Kjartan's avatar
Kjartan committed
665
    return $parents;
Dries's avatar
 
Dries committed
666
  }
Kjartan's avatar
Kjartan committed
667 668 669 670
  else {
    return array();
  }
}
Dries's avatar
 
Dries committed
671

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

Dries's avatar
 
Dries committed
705 706 707 708 709 710 711 712 713 714 715 716 717
/**
 * 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
718 719 720
 * @param $max_depth
 *   The number of levels of the tree to return. Leave NULL to return all levels.
 *
Dries's avatar
 
Dries committed
721 722 723 724 725
 * @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
726
  static $children, $parents, $terms;
Dries's avatar
 
Dries committed
727

Kjartan's avatar
Kjartan committed
728
  $depth++;
Dries's avatar
 
Dries committed
729

Dries's avatar
 
Dries committed
730 731 732 733
  // 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
734

735
    $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
736
    while ($term = db_fetch_object($result)) {
Dries's avatar
 
Dries committed
737 738 739
      $children[$vid][$term->parent][] = $term->tid;
      $parents[$vid][$term->tid][] = $term->parent;
      $terms[$vid][$term->tid] = $term;
Dries's avatar
 
Dries committed
740 741
    }
  }
Dries's avatar
 
Dries committed
742

Dries's avatar
 
Dries committed
743
  $max_depth = (is_null($max_depth)) ? count($children[$vid]) : $max_depth;
Dries's avatar
Dries committed
744 745 746 747 748 749 750 751 752 753 754 755
  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
756
      }
Dries's avatar
 
Dries committed
757
    }
Kjartan's avatar
Kjartan committed
758
  }
Dries's avatar
 
Dries committed
759

Dries's avatar
 
Dries committed
760
  return $tree ? $tree : array();
Kjartan's avatar
Kjartan committed
761
}
Dries's avatar
 
Dries committed
762

Dries's avatar
 
Dries committed
763 764 765
/**
 * Return an array of synonyms of the given term ID.
 */
Kjartan's avatar
Kjartan committed
766 767
function taxonomy_get_synonyms($tid) {
  if ($tid) {
Dries's avatar
 
Dries committed
768
    $result = db_query('SELECT name FROM {term_synonym} WHERE tid = %d', $tid);
Kjartan's avatar
Kjartan committed
769
    while ($synonym = db_fetch_array($result)) {
Dries's avatar
 
Dries committed
770
      $synonyms[] = $synonym['name'];
Dries's avatar
 
Dries committed
771
    }
Kjartan's avatar
Kjartan committed
772
    return $synonyms ? $synonyms : array();
Dries's avatar
 
Dries committed
773
  }
Kjartan's avatar
Kjartan committed
774 775
  else {
    return array();
Dries's avatar
 
Dries committed
776
  }
Kjartan's avatar
Kjartan committed
777
}
Dries's avatar
 
Dries committed
778

Dries's avatar
 
Dries committed
779 780 781 782 783
/**
 * 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
784
}
Dries's avatar
 
Dries committed
785

Dries's avatar
 
Dries committed
786 787 788
/**
 * Given a term id, count the number of published nodes in it.
 */
Dries's avatar
 
Dries committed
789
function taxonomy_term_count_nodes($tid, $type = 0) {
Kjartan's avatar
Kjartan committed
790
  static $count;
Dries's avatar
 
Dries committed
791

Dries's avatar
 
Dries committed
792 793 794
  if (!isset($count[$type])) {
    // $type == 0 always evaluates true is $type is a string
    if (is_numeric($type)) {
795
      $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
796 797
    }
    else {
798
      $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
799
    }
Kjartan's avatar
Kjartan committed
800
    while ($term = db_fetch_object($result)) {
Dries's avatar
 
Dries committed
801
      $count[$type][$term->tid] = $term->c;
Dries's avatar
 
Dries committed
802 803 804
    }
  }

Kjartan's avatar
Kjartan committed
805
  foreach (_taxonomy_term_children($tid) as $c) {
Dries's avatar
 
Dries committed
806
    $children_count += taxonomy_term_count_nodes($c, $type);
Kjartan's avatar
Kjartan committed
807
  }
Dries's avatar
 
Dries committed
808
  return $count[$type][$tid] + $children_count;
Kjartan's avatar
Kjartan committed
809 810
}

Dries's avatar
 
Dries committed
811 812 813
/**
 * Helper for taxonomy_term_count_nodes().
 */
Kjartan's avatar
Kjartan committed