taxonomy.module 51.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)) {
31
      foreach ($node->taxonomy as $term) {
32
        $links[] = l($term->name, taxonomy_term_path($term), array('rel' => 'tag', 'title' => strip_tags($term->description)));
Dries's avatar
   
Dries committed
33
      }
Dries's avatar
   
Dries committed
34
35
36
    }
    return $links;
  }
Kjartan's avatar
Kjartan committed
37
38
}

39
40
41
42
43
44
45
46
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
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
  if ($may_cache) {
54
55
56
    $items[] = array('path' => 'admin/taxonomy',
      'title' => t('categories'),
      'callback' => 'taxonomy_overview_vocabularies',
Dries's avatar
   
Dries committed
57
      'access' => user_access('administer taxonomy'));
58

59
60
61
62
    $items[] = array('path' => 'admin/taxonomy/list',
      'title' => t('list'),
      'type' => MENU_DEFAULT_LOCAL_TASK,
      'weight' => -10);
63

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

70
71
72
    $items[] = array('path' => 'admin/taxonomy/edit/vocabulary',
      'title' => t('edit vocabulary'),
      'callback' => 'taxonomy_admin_vocabulary_edit',
73
74
75
      'access' => user_access('administer taxonomy'),
      'type' => MENU_CALLBACK);

76
77
78
    $items[] = array('path' => 'admin/taxonomy/edit/term',
      'title' => t('edit term'),
      'callback' => 'taxonomy_admin_term_edit',
79
80
81
      'access' => user_access('administer taxonomy'),
      'type' => MENU_CALLBACK);

82
83
    $items[] = array('path' => 'taxonomy/term',
      'title' => t('taxonomy term'),
Dries's avatar
   
Dries committed
84
85
86
      'callback' => 'taxonomy_term_page',
      'access' => user_access('access content'),
      'type' => MENU_CALLBACK);
Steven Wittens's avatar
Steven Wittens committed
87

88
89
    $items[] = array('path' => 'taxonomy/autocomplete',
      'title' => t('autocomplete taxonomy'),
Steven Wittens's avatar
Steven Wittens committed
90
91
92
      'callback' => 'taxonomy_autocomplete',
      'access' => user_access('access content'),
      'type' => MENU_CALLBACK);
Dries's avatar
   
Dries committed
93
  }
Dries's avatar
Dries committed
94
95
  else {
    if (is_numeric(arg(2))) {
96
97
98
99
      $items[] = array('path' => 'admin/taxonomy/' . arg(2),
        'title' => t('list terms'),
        'callback' => 'taxonomy_overview_terms',
        'callback arguments' => array(arg(2)),
Dries's avatar
Dries committed
100
101
102
        'access' => user_access('administer taxonomy'),
        'type' => MENU_CALLBACK);

103
104
105
106
      $items[] = array('path' => 'admin/taxonomy/' . arg(2) . '/list',
        'title' => t('list'),
        'type' => MENU_DEFAULT_LOCAL_TASK,
        'weight' => -10);
Dries's avatar
Dries committed
107

108
109
      $items[] = array('path' => 'admin/taxonomy/' . arg(2) . '/add/term',
        'title' => t('add term'),
110
111
        'callback' => 'taxonomy_form_term',
        'callback arguments' => array(array('vid' => arg(2))),
Dries's avatar
Dries committed
112
113
114
115
        'access' => user_access('administer taxonomy'),
        'type' => MENU_LOCAL_TASK);
    }
  }
Dries's avatar
   
Dries committed
116

Dries's avatar
   
Dries committed
117
118
  return $items;
}
Dries's avatar
 
Dries committed
119

120
121
122
123
/**
 * List and manage vocabularies.
 */
function taxonomy_overview_vocabularies() {
124
  $vocabularies = taxonomy_get_vocabularies();
125
  $rows = array();
126
127
128
129
130
131
  foreach ($vocabularies as $vocabulary) {
    $types = array();
    foreach ($vocabulary->nodes as $type) {
      $node_type = node_get_name($type);
      $types[] = $node_type ? $node_type : $type;
    }
132
133
134
135
136
137
138
139
    $rows[] = array('name' => check_plain($vocabulary->name),
      'type' => implode(', ', $types),
      'edit' => l(t('edit vocabulary'), "admin/taxonomy/edit/vocabulary/$vocabulary->vid"),
      'list' => l(t('list terms'), "admin/taxonomy/$vocabulary->vid"),
      'add' => l(t('add terms'), "admin/taxonomy/$vocabulary->vid/add/term")
    );
  }
  if (empty($rows)) {
drumm's avatar
drumm committed
140
    $rows[] = array(array('data' => t('No categories available.'), 'colspan' => '5', 'class' => 'message'));
141
  }
drumm's avatar
drumm committed
142
  $header = array(t('Name'), t('Type'), array('data' => t('Operations'), 'colspan' => '3'));
143

144
  return theme('table', $header, $rows, array('id' => 'taxonomy'));
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
}

/**
 * Display a tree of all the terms in a vocabulary, with options to edit
 * each one.
 */
function taxonomy_overview_terms($vid) {
  $destination = drupal_get_destination();

  $header = array(t('Name'), t('Operations'));
  $vocabulary = taxonomy_get_vocabulary($vid);

  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) . ' ' . l($term->name, "taxonomy/term/$term->tid"), 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'));
  }

  $GLOBALS['pager_page_array'][] = $start_from;  // FIXME
  $GLOBALS['pager_total'][] = intval($total_entries / $page_increment) + 1; // FIXME

  if ($total_entries >= $page_increment) {
    $rows[] = array(array('data' => theme('pager', NULL, $page_increment), 'colspan' => '2'));
  }

  return theme('table', $header, $rows, array('id' => 'taxonomy'));
}

/**
 * Display form for adding and editing vocabularies.
 */
Kjartan's avatar
Kjartan committed
188
function taxonomy_form_vocabulary($edit = array()) {
189
190
191
192
  $form['name'] = array('#type' => 'textfield',
    '#title' => t('Vocabulary name'),
    '#default_value' => $edit['name'],
    '#maxlength' => 64,
193
    '#description' => t('The name for this vocabulary. Example: "Topic".'),
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
    '#required' => TRUE,
  );
  $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.'),
  );
  $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'))),
  );
  $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.'),
  );
245

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

255
  $form['submit'] = array('#type' => 'submit', '#value' => t('Submit'));
Dries's avatar
   
Dries committed
256
  if ($edit['vid']) {
257
    $form['delete'] = array('#type' => 'submit', '#value' => t('Delete'));
258
    $form['vid'] = array('#type' => 'value', '#value' => $edit['vid']);
259
    $form['module'] = array('#type' => 'value', '#value' => $edit['module']);
Dries's avatar
 
Dries committed
260
  }
261
  return drupal_get_form('taxonomy_form_vocabulary', $form);
Kjartan's avatar
Kjartan committed
262
}
Kjartan's avatar
Kjartan committed
263

264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
/**
 * Accept the form submission for a vocabulary and save the results.
 */
function taxonomy_form_vocabulary_submit($form_id, $form_values) {
  // Fix up the nodes array to remove unchecked nodes.
  $form_values['nodes'] = array_filter($form_values['nodes']);
  switch (taxonomy_save_vocabulary($form_values)) {
  case SAVED_NEW:
    drupal_set_message(t('Created new vocabulary %name.', array('%name' => theme('placeholder', $form_values['name']))));
    break;
  case SAVED_UPDATED:
    drupal_set_message(t('Updated vocabulary %name.', array('%name' => theme('placeholder', $form_values['name']))));
    break;
  }
  return 'admin/taxonomy';
}

281
function taxonomy_save_vocabulary(&$edit) {
282
  $edit['nodes'] = empty($edit['nodes']) ? array() : $edit['nodes'];
Dries's avatar
   
Dries committed
283

Dries's avatar
   
Dries committed
284
  if ($edit['vid'] && $edit['name']) {
285
    db_query("UPDATE {vocabulary} SET name = '%s', description = '%s', help = '%s', multiple = %d, required = %d, hierarchy = %d, relations = %d, tags = %d, weight = %d, module = '%s' WHERE vid = %d", $edit['name'], $edit['description'], $edit['help'], $edit['multiple'], $edit['required'], $edit['hierarchy'], $edit['relations'], $edit['tags'], $edit['weight'], isset($edit['module']) ? $edit['module'] : 'taxonomy', $edit['vid']);
Dries's avatar
   
Dries committed
286
    db_query("DELETE FROM {vocabulary_node_types} WHERE vid = %d", $edit['vid']);
287
    foreach ($edit['nodes'] as $type => $selected) {
Dries's avatar
   
Dries committed
288
289
      db_query("INSERT INTO {vocabulary_node_types} (vid, type) VALUES (%d, '%s')", $edit['vid'], $type);
    }
Dries's avatar
   
Dries committed
290
    module_invoke_all('taxonomy', 'update', 'vocabulary', $edit);
291
    $status = SAVED_UPDATED;
Dries's avatar
 
Dries committed
292
  }
Dries's avatar
   
Dries committed
293
  else if ($edit['vid']) {
294
    $status = taxonomy_del_vocabulary($edit['vid']);
Kjartan's avatar
Kjartan committed
295
296
  }
  else {
297
298
    $edit['vid'] = db_next_id('{vocabulary}_vid');
    db_query("INSERT INTO {vocabulary} (vid, name, description, help, multiple, required, hierarchy, relations, tags, weight, module) VALUES (%d, '%s', '%s', '%s', %d, %d, %d, %d, %d, %d, '%s')", $edit['vid'], $edit['name'], $edit['description'], $edit['help'], $edit['multiple'], $edit['required'], $edit['hierarchy'], $edit['relations'], $edit['tags'], $edit['weight'], isset($edit['module']) ? $edit['module'] : 'taxonomy');
299
    foreach ($edit['nodes'] as $type => $selected) {
Dries's avatar
   
Dries committed
300
301
      db_query("INSERT INTO {vocabulary_node_types} (vid, type) VALUES (%d, '%s')", $edit['vid'], $type);
    }
Dries's avatar
   
Dries committed
302
    module_invoke_all('taxonomy', 'insert', 'vocabulary', $edit);
303
    $status = SAVED_NEW;
Kjartan's avatar
Kjartan committed
304
  }
Dries's avatar
   
Dries committed
305
306

  cache_clear_all();
Dries's avatar
   
Dries committed
307

308
  return $status;
Kjartan's avatar
Kjartan committed
309
}
Dries's avatar
 
Dries committed
310

Kjartan's avatar
Kjartan committed
311
function taxonomy_del_vocabulary($vid) {
312
  $vocabulary = (array) taxonomy_get_vocabulary($vid);
Dries's avatar
   
Dries committed
313

Dries's avatar
   
Dries committed
314
  db_query('DELETE FROM {vocabulary} WHERE vid = %d', $vid);
Dries's avatar
   
Dries committed
315
  db_query('DELETE FROM {vocabulary_node_types} WHERE vid = %d', $vid);
Dries's avatar
   
Dries committed
316
  $result = db_query('SELECT tid FROM {term_data} WHERE vid = %d', $vid);
Kjartan's avatar
Kjartan committed
317
318
  while ($term = db_fetch_object($result)) {
    taxonomy_del_term($term->tid);
Dries's avatar
 
Dries committed
319
  }
Dries's avatar
   
Dries committed
320

Dries's avatar
   
Dries committed
321
  module_invoke_all('taxonomy', 'delete', 'vocabulary', $vocabulary);
Dries's avatar
   
Dries committed
322

Dries's avatar
   
Dries committed
323
324
  cache_clear_all();

325
  return SAVED_DELETED;
Dries's avatar
   
Dries committed
326
327
328
329
330
}

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

331
332
333
334
  $form['type'] = array('#type' => 'value', '#value' => 'vocabulary');
  $form['vid'] = array('#type' => 'value', '#value' => $vid);
  $form['name'] = array('#type' => 'value', '#value' => $vocabulary->name);
  return confirm_form('taxonomy_vocabulary_confirm_delete', $form,
335
336
337
                  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.'),
338
                  t('Delete'),
339
                  t('Cancel'));
Kjartan's avatar
Kjartan committed
340
}
Dries's avatar
 
Dries committed
341

342
343
344
345
346
347
function taxonomy_vocabulary_confirm_delete_submit($form_id, $form_values) {
  $status = taxonomy_del_vocabulary($form_values['vid']);
  drupal_set_message(t('Deleted vocabulary %name.', array('%name' => theme('placeholder', $form_values['name']))));
  return 'admin/taxonomy';
}

Kjartan's avatar
Kjartan committed
348
function taxonomy_form_term($edit = array()) {
Dries's avatar
   
Dries committed
349
  $vocabulary_id = isset($edit['vid']) ? $edit['vid'] : arg(4);
Kjartan's avatar
Kjartan committed
350
  $vocabulary = taxonomy_get_vocabulary($vocabulary_id);
Dries's avatar
   
Dries committed
351

352
  $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);
353

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

Kjartan's avatar
Kjartan committed
356
  if ($vocabulary->hierarchy) {
Dries's avatar
   
Dries committed
357
358
    $parent = array_keys(taxonomy_get_parents($edit['tid']));
    $children = taxonomy_get_tree($vocabulary_id, $edit['tid']);
Dries's avatar
   
Dries committed
359

Dries's avatar
   
Dries committed
360
    // A term can't be the child of itself, nor of its children.
Dries's avatar
   
Dries committed
361
362
363
    foreach ($children as $child) {
      $exclude[] = $child->tid;
    }
Dries's avatar
   
Dries committed
364
    $exclude[] = $edit['tid'];
Dries's avatar
   
Dries committed
365

Kjartan's avatar
Kjartan committed
366
    if ($vocabulary->hierarchy == 1) {
367
      $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
368
    }
Kjartan's avatar
Kjartan committed
369
    elseif ($vocabulary->hierarchy == 2) {
370
      $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
371
    }
Kjartan's avatar
Kjartan committed
372
  }
Dries's avatar
 
Dries committed
373

374
  if ($vocabulary->relations) {
375
    $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']));
376
377
  }

378
379
  $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.'));
380
381
382
383
384

  // Add extra term form elements.
  $extra = module_invoke_all('taxonomy', 'term', 'vocabulary');
  if (is_array($extra)) {
    foreach ($extra as $key => $element) {
385
      $extra[$key]['#weight'] = isset($extra[$key]['#weight']) ? $extra[$key]['#weight'] : -18;
386
387
388
389
390
    }
    $form = array_merge($form, $extra);
  }


391
  $form['vid'] = array('#type' => 'value', '#value' => $vocabulary->vid);
392
  $form['submit'] = array('#type' => 'submit', '#value' => t('Submit'));
Kjartan's avatar
Kjartan committed
393

Dries's avatar
   
Dries committed
394
  if ($edit['tid']) {
395
    $form['delete'] = array('#type' => 'submit', '#value' => t('Delete'));
396
    $form['tid'] = array('#type' => 'value', '#value' => $edit['tid']);
Dries's avatar
 
Dries committed
397
  }
398
  else {
399
    $form['destination'] = array('#type' => 'hidden', '#value' => $_GET['q']);
400
  }
Dries's avatar
 
Dries committed
401

402
  return drupal_get_form('taxonomy_form_term', $form);
Kjartan's avatar
Kjartan committed
403
}
Dries's avatar
 
Dries committed
404

405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
/**
 * Accept the form submission for a taxonomy term and save the result.
 */
function taxonomy_form_term_submit($form_id, $form_values) {
  switch (taxonomy_save_term($form_values)) {
    case SAVED_NEW:
      drupal_set_message(t('Created new term %term.', array('%term' => theme('placeholder', $form_values['name']))));
      break;
    case SAVED_UPDATED:
      drupal_set_message(t('The term %term has been updated.', array('%term' => theme('placeholder', $form_values['name']))));
      break;
  }
  return 'admin/taxonomy';
}

420
function taxonomy_save_term(&$edit) {
Dries's avatar
   
Dries committed
421
  if ($edit['tid'] && $edit['name']) {
422
    db_query("UPDATE {term_data} SET name = '%s', description = '%s', weight = %d WHERE tid = %d", $edit['name'], $edit['description'], $edit['weight'], $edit['tid']);
Dries's avatar
   
Dries committed
423
    module_invoke_all('taxonomy', 'update', 'term', $edit);
424
    $status = SAVED_UPDATED;
Kjartan's avatar
Kjartan committed
425
  }
Dries's avatar
   
Dries committed
426
427
  else if ($edit['tid']) {
    return taxonomy_del_term($edit['tid']);
Kjartan's avatar
Kjartan committed
428
429
  }
  else {
Dries's avatar
   
Dries committed
430
    $edit['tid'] = db_next_id('{term_data}_tid');
431
    db_query("INSERT INTO {term_data} (tid, name, description, vid, weight) VALUES (%d, '%s', '%s', %d, %d)", $edit['tid'], $edit['name'], $edit['description'], $edit['vid'], $edit['weight']);
Dries's avatar
   
Dries committed
432
    module_invoke_all('taxonomy', 'insert', 'term', $edit);
433
    $status = SAVED_NEW;
Kjartan's avatar
Kjartan committed
434
  }
Dries's avatar
 
Dries committed
435

Dries's avatar
   
Dries committed
436
437
438
  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
439
      if ($related_id != 0) {
Dries's avatar
   
Dries committed
440
        db_query('INSERT INTO {term_relation} (tid1, tid2) VALUES (%d, %d)', $edit['tid'], $related_id);
Dries's avatar
 
Dries committed
441
      }
Kjartan's avatar
Kjartan committed
442
    }
Kjartan's avatar
Kjartan committed
443
  }
Dries's avatar
 
Dries committed
444

Dries's avatar
   
Dries committed
445
  db_query('DELETE FROM {term_hierarchy} WHERE tid = %d', $edit['tid']);
446
  if (!isset($edit['parent']) || empty($edit['parent'])) {
447
    $edit['parent'] = array(0);
Kjartan's avatar
Kjartan committed
448
  }
Dries's avatar
   
Dries committed
449
450
  if (is_array($edit['parent'])) {
    foreach ($edit['parent'] as $parent) {
451
452
453
454
455
456
457
458
      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
459
    }
Kjartan's avatar
Kjartan committed
460
  }
461
462
463
  else {
    db_query('INSERT INTO {term_hierarchy} (tid, parent) VALUES (%d, %d)', $edit['tid'], $edit['parent']);
  }
Dries's avatar
 
Dries committed
464

Dries's avatar
   
Dries committed
465
466
467
  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
468
      if ($synonym) {
Dries's avatar
   
Dries committed
469
        db_query("INSERT INTO {term_synonym} (tid, name) VALUES (%d, '%s')", $edit['tid'], chop($synonym));
Dries's avatar
   
Dries committed
470
      }
Kjartan's avatar
Kjartan committed
471
    }
Dries's avatar
 
Dries committed
472
  }
Dries's avatar
   
Dries committed
473

Dries's avatar
   
Dries committed
474
475
  cache_clear_all();

476
  return $status;
Kjartan's avatar
Kjartan committed
477
}
Dries's avatar
 
Dries committed
478

Kjartan's avatar
Kjartan committed
479
function taxonomy_del_term($tid) {
480
481
482
483
484
485
486
487
488
489
490
491
492
493
  $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
494

495
      $term = (array) taxonomy_get_term($tid);
Dries's avatar
   
Dries committed
496

497
498
499
500
501
      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
502

503
504
      module_invoke_all('taxonomy', 'delete', 'term', $term);
    }
Dries's avatar
   
Dries committed
505

506
507
    $tids = $orphans;
  }
Dries's avatar
   
Dries committed
508

Dries's avatar
   
Dries committed
509
  cache_clear_all();
510
511

  return SAVED_DELETED;
Dries's avatar
   
Dries committed
512
513
514
515
516
}

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

517
518
519
520
  $form['type'] = array('#type' => 'value', '#value' => 'term');
  $form['name'] = array('#type' => 'value', '#value' => $term->name);
  $form['tid'] = array('#type' => 'value', '#value' => $tid);
  return confirm_form('taxonomy_term_confirm_delete', $form,
521
522
                  t('Are you sure you want to delete the term %title?',
                  array('%title' => theme('placeholder', $term->name))),
523
524
525
                  'admin/taxonomy',
                  t('Deleting a term will delete all its children if there are any. This action cannot be undone.'),
                  t('Delete'),
526
                  t('Cancel'));
Kjartan's avatar
Kjartan committed
527
}
Dries's avatar
 
Dries committed
528

529
530
531
532
function taxonomy_term_confirm_delete_submit($form_id, $form_values) {
  taxonomy_del_term($form_values['tid']);
  drupal_set_message(t('Deleted term %name.', array('%name' => theme('placeholder', $form_values['name']))));
  return 'admin/taxonomy';
Kjartan's avatar
Kjartan committed
533
534
}

Dries's avatar
   
Dries committed
535
536
537
/**
 * Generate a form element for selecting terms from a vocabulary.
 */
Dries's avatar
   
Dries committed
538
function taxonomy_form($vid, $value = 0, $help = NULL, $name = 'taxonomy') {
Dries's avatar
   
Dries committed
539
  $vocabulary = taxonomy_get_vocabulary($vid);
540
  $help = ($help) ? $help : $vocabulary->help;
Kjartan's avatar
Kjartan committed
541
542
543
544
  if ($vocabulary->required) {
    $blank = 0;
  }
  else {
Dries's avatar
   
Dries committed
545
    $blank = '<'. t('none') .'>';
Kjartan's avatar
Kjartan committed
546
  }
Dries's avatar
   
Dries committed
547

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

551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
/**
 * Generate a set of options for selecting a term from all vocabularies. Can be
 * passed to form_select.
 */
function taxonomy_form_all($free_tags = 0) {
  $vocabularies = taxonomy_get_vocabularies();
  $options = array();
  foreach ($vocabularies as $vid => $vocabulary) {
    if ($vocabulary->tags && !$free_tags) { continue; }
    $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
571
572
573
574
575
576
/**
 * 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
577
function taxonomy_get_vocabularies($type = NULL) {
Kjartan's avatar
Kjartan committed
578
  if ($type) {
579
    $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
580
581
  }
  else {
582
    $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
583
  }
Dries's avatar
   
Dries committed
584

Kjartan's avatar
Kjartan committed
585
  $vocabularies = array();
Dries's avatar
   
Dries committed
586
  $node_types = array();
Kjartan's avatar
Kjartan committed
587
  while ($voc = db_fetch_object($result)) {
Dries's avatar
   
Dries committed
588
589
590
591
    $node_types[$voc->vid][] = $voc->type;
    unset($voc->type);
    $voc->nodes = $node_types[$voc->vid];
    $vocabularies[$voc->vid] = $voc;
Dries's avatar
 
Dries committed
592
  }
Dries's avatar
   
Dries committed
593

Kjartan's avatar
Kjartan committed
594
595
  return $vocabularies;
}
Dries's avatar
 
Dries committed
596

Dries's avatar
   
Dries committed
597
598
599
/**
 * Generate a form for selecting terms to associate with a node.
 */
600
601
602
603
function taxonomy_form_alter($form_id, &$form) {
  if (isset($form['type']) && $form['type']['#value'] .'_node_form' == $form_id) {
    $node = $form['#node'];

604
    if (!isset($node->taxonomy)) {
605
606
607
608
609
610
      if ($node->nid) {
        $terms = taxonomy_node_get_terms($node->nid);
      }
      else {
        $terms = array();
      }
Kjartan's avatar
Kjartan committed
611
612
    }
    else {
613
      $terms = $node->taxonomy;
Dries's avatar
 
Dries committed
614
615
    }

616
    $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);
Dries's avatar
Dries committed
617

618
619
620
621
    while ($vocabulary = db_fetch_object($c)) {
      if ($vocabulary->tags) {
        $typed_terms = array();
        foreach ($terms as $term) {
622
          // Extract terms belonging to the vocabulary in question.
623
          if ($term->vid == $vocabulary->vid) {
Dries's avatar
Dries committed
624

625
626
627
628
629
630
631
            // 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;
          }
Dries's avatar
Dries committed
632
        }
633
        $typed_string = implode(', ', $typed_terms) . (array_key_exists('tags', $terms) ? $terms['tags'][$vocabulary->vid] : NULL);
634

635
636
637
638
        if ($vocabulary->help) {
          $help = $vocabulary->help;
        }
        else {
639
          $help = t('A comma-separated list of terms describing this content. Example: funny, bungie jumping, "Company, Inc.".');
640
        }
641
642
643
644
645
646
647
648
649
        $form['taxonomy']['tags'][$vocabulary->vid] = array('#type' => 'textfield',
          '#title' => $vocabulary->name,
          '#description' => $help,
          '#required' => $vocabulary->required,
          '#default_value' => $typed_string,
          '#autocomplete_path' => 'taxonomy/autocomplete/'. $vocabulary->vid,
          '#weight' => $vocabulary->weight,
          '#maxlength' => 100,
        );
650
651
      }
      else {
652
653
654
655
656
657
658
659
        // Extract terms belonging to the vocabulary in question.
        $default_terms = array();
        foreach ($terms as $term) {
          if ($term->vid == $vocabulary->vid) {
            $default_terms[$term->tid] = $term;
          }
        }
        $form['taxonomy'][$vocabulary->vid] = taxonomy_form($vocabulary->vid, array_keys($default_terms), $vocabulary->help);
660
        $form['taxonomy'][$vocabulary->vid]['#weight'] = $vocabulary->weight;
661
        $form['taxonomy'][$vocabulary->vid]['#required'] = $vocabulary->required;
662
      }
Dries's avatar
Dries committed
663
    }
664
    if (isset($form['taxonomy'])) {
665
      $form['taxonomy'] += array('#type' => 'fieldset', '#title' => t('Categories'), '#collapsible' => TRUE, '#collapsed' => FALSE, '#tree' => TRUE, '#weight' => -3);
Dries's avatar
Dries committed
666
    }
Dries's avatar
 
Dries committed
667
  }
Kjartan's avatar
Kjartan committed
668
}
Dries's avatar
 
Dries committed
669

Dries's avatar
   
Dries committed
670
671
672
673
/**
 * Find all terms associated to the given node, within one vocabulary.
 */
function taxonomy_node_get_terms_by_vocabulary($nid, $vid, $key = 'tid') {
674
  $result = db_query(db_rewrite_sql('SELECT t.tid, t.* FROM {term_data} t INNER JOIN {term_node} r ON r.tid = t.tid WHERE t.vid = %d AND r.nid = %d ORDER BY weight', 't', 'tid'), $vid, $nid);
Kjartan's avatar
Kjartan committed
675
676
677
  $terms = array();
  while ($term = db_fetch_object($result)) {
    $terms[$term->$key] = $term;
Dries's avatar
 
Dries committed
678
  }
Kjartan's avatar
Kjartan committed
679
680
681
  return $terms;
}

Dries's avatar
   
Dries committed
682
/**
683
 * Find all terms associated to the given node, ordered by vocabulary and term weight.
Dries's avatar
   
Dries committed
684
685
 */
function taxonomy_node_get_terms($nid, $key = 'tid') {
Kjartan's avatar
Kjartan committed
686
  static $terms;
Dries's avatar
 
Dries committed
687

Dries's avatar
   
Dries committed
688
  if (!isset($terms[$nid])) {
689
    $result = db_query(db_rewrite_sql('SELECT t.* FROM {term_node} r INNER JOIN {term_data} t ON r.tid = t.tid INNER JOIN {vocabulary} v ON t.vid = v.vid WHERE r.nid = %d ORDER BY v.weight, t.weight, t.name', 't', 'tid'), $nid);
Kjartan's avatar
Kjartan committed
690
    $terms[$nid] = array();
Dries's avatar
 
Dries committed
691
    while ($term = db_fetch_object($result)) {
Kjartan's avatar
Kjartan committed
692
      $terms[$nid][$term->$key] = $term;
Dries's avatar
 
Dries committed
693
694
    }
  }
Kjartan's avatar
Kjartan committed
695
696
  return $terms[$nid];
}
Dries's avatar
 
Dries committed
697

Dries's avatar
Dries committed
698
699
700
701
702
703
704
705
706
707
/**
 * 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) {
708
709
710
          // see form_get_error $key = implode('][', $element['#parents']);
          // on why this is the key
          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
711
712
713
714
715
716
        }
      }
    }
  }
}

Dries's avatar
   
Dries committed
717
718
719
/**
 * Save term associations for a given node.
 */
Kjartan's avatar
Kjartan committed
720
function taxonomy_node_save($nid, $terms) {
721
  taxonomy_node_delete($nid);
Dries's avatar
Dries committed
722
723
724

  // Free tagging vocabularies do not send their tids in the form,
  // so we'll detect them here and process them independently.
725
  if (isset($terms['tags'])) {
Dries's avatar
Dries committed
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
    $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) {
755
756
757
          $edit = array('vid' => $vid, 'name' => $typed_term);
          $status = taxonomy_save_term($edit);
          $typed_term_tid = $edit['tid'];
Dries's avatar
Dries committed
758
759
760
761
762
763
        }

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

765
  if (is_array($terms)) {
Dries's avatar
   
Dries committed
766
    foreach ($terms as $term) {
767
768
769
770
771
772
773
      if (is_array($term)) {
        foreach ($term as $tid) {
          if ($tid) {
            db_query('INSERT INTO {term_node} (nid, tid) VALUES (%d, %d)', $nid, $tid);
          }
        }
      }
774
775
776
      else if (is_object($term)) {
        db_query('INSERT INTO {term_node} (nid, tid) VALUES (%d, %d)', $nid, $term->tid);
      }
777
      else if ($term) {
Dries's avatar
   
Dries committed
778
        db_query('INSERT INTO {term_node} (nid, tid) VALUES (%d, %d)', $nid, $term);
779
      }
Dries's avatar
 
Dries committed
780
781
    }
  }
Kjartan's avatar
Kjartan committed
782
}
Dries's avatar
 
Dries committed
783

Dries's avatar
   
Dries committed
784
785
786
/**
 * Remove associations of a node to its terms.
 */
Kjartan's avatar
Kjartan committed
787
function taxonomy_node_delete($nid) {
Dries's avatar
   
Dries committed
788
  db_query('DELETE FROM {term_node} WHERE nid = %d', $nid);
Kjartan's avatar
Kjartan committed
789
}
Dries's avatar
 
Dries committed
790

Dries's avatar
   
Dries committed
791
792
793
794
/**
 * Find all term objects related to a given term ID.
 */
function taxonomy_get_related($tid, $key = 'tid') {
Kjartan's avatar
Kjartan committed
795
  if ($tid) {
Dries's avatar
   
Dries committed
796
    $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
797
798
799
    $related = array();
    while ($term = db_fetch_object($result)) {
      $related[$term->$key] = $term;
Dries's avatar
 
Dries committed
800
    }
Kjartan's avatar
Kjartan committed
801
    return $related;
Dries's avatar
 
Dries committed
802
  }
Kjartan's avatar
Kjartan committed
803
804
  else {
    return array();
Dries's avatar
 
Dries committed
805
  }
Kjartan's avatar
Kjartan committed
806
}
Dries's avatar
 
Dries committed
807

Dries's avatar
   
Dries committed
808
809
810
811
/**
 * Find all parents of a given term ID.
 */
function taxonomy_get_parents($tid, $key = 'tid') {
Kjartan's avatar
Kjartan committed
812
  if ($tid) {
813
    $result = db_query(db_rewrite_sql('SELECT t.tid, t.* FROM {term_data} t INNER JOIN {term_hierarchy} h ON h.parent = t.tid WHERE h.tid = %d ORDER BY weight, name', 't', 'tid'), $tid);
Kjartan's avatar
Kjartan committed
814
815
816
    $parents = array();
    while ($parent = db_fetch_object($result)) {
      $parents[$parent->$key] = $parent;
Dries's avatar
   
Dries committed
817
    }
Kjartan's avatar
Kjartan committed
818
    return $parents;
Dries's avatar
 
Dries committed
819
  }
Kjartan's avatar
Kjartan committed
820
821
822
823
  else {
    return array();
  }
}
Dries's avatar
 
Dries committed
824

Dries's avatar
   
Dries committed
825
826
827
828
/**
 * Find all ancestors of a given term ID.
 */
function taxonomy_get_parents_all($tid) {
Dries's avatar
   
Dries committed
829
830
831
832
833
834
835
836
837
838
839
840
  $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
841
842
843
844
/**
 * Find all children of a term ID.
 */
function taxonomy_get_children($tid, $vid = 0, $key = 'tid') {
Kjartan's avatar
Kjartan committed
845
  if ($vid) {
846
    $result = db_query(db_rewrite_sql('SELECT t.* FROM {term_data} t INNER JOIN {term_hierarchy} h ON h.tid = t.tid WHERE t.vid = %d AND h.parent = %d ORDER BY weight, name', 't', 'tid'), $vid, $tid);
Dries's avatar
 
Dries committed
847
  }
Kjartan's avatar
Kjartan committed
848
  else {
849
    $result = db_query(db_rewrite_sql('SELECT t.* FROM {term_data} t INNER JOIN {term_hierarchy} h ON h.tid = t.tid WHERE parent = %d ORDER BY weight, name', 't', 'tid'), $tid);
Kjartan's avatar
Kjartan committed
850
851
852
853
854
855
856
  }
  $children = array();
  while ($term = db_fetch_object($result)) {
    $children[$term->$key] = $term;
  }
  return $children;
}
Dries's avatar
 
Dries committed
857

Dries's avatar
   
Dries committed
858
859
860
861
862
863
864
865
866
867
868
869
870
/**
 * 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
871
872
873
 * @param $max_depth
 *   The number of levels of the tree to return. Leave NULL to return all levels.
 *
Dries's avatar
   
Dries committed
874
875
876
877
878
 * @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
879
  static $children, $parents, $terms;
Dries's avatar
   
Dries committed
880

Kjartan's avatar
Kjartan committed
881
  $depth++;
Dries's avatar
   
Dries committed
882

Dries's avatar
   
Dries committed
883
884
885
886
  // 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
887

888
    $result = db_query(db_rewrite_sql('SELECT t.tid, t.*, parent FROM {term_data} t INNER JOIN  {term_hierarchy} h ON t.tid = h.tid WHERE t.vid = %d ORDER BY weight, name', 't', 'tid'), $vid);
Dries's avatar
   
Dries committed
889
    while ($term = db_fetch_object($result)) {
Dries's avatar
   
Dries committed
890
891
892
      $children[$vid][$term->parent][] = $term->tid;
      $parents[$vid][$term->tid][] = $term->parent;
      $terms[$vid][$term->tid] = $term;
Dries's avatar
 
Dries committed
893
894
    }
  }
Dries's avatar
   
Dries committed
895

Dries's avatar
   
Dries committed
896
  $max_depth = (is_null($max_depth)) ? count($children[$vid]) : $max_depth;
Dries's avatar
Dries committed
897
898
899
900
901
902
903
904
905
906
907
908
  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
909
      }
Dries's avatar
   
Dries committed
910
    }
Kjartan's avatar
Kjartan committed
911
  }
Dries's avatar
   
Dries committed
912

Dries's avatar
   
Dries committed
913
  return $tree ? $tree : array();
Kjartan's avatar
Kjartan committed
914
}
Dries's avatar
 
Dries committed
915

Dries's avatar
   
Dries committed
916
917
918
/**
 * Return an array of synonyms of the given term ID.
 */
Kjartan's avatar
Kjartan committed
919
920
function taxonomy_get_synonyms($tid) {
  if ($tid) {
Dries's avatar
   
Dries committed
921
    $result = db_query('SELECT name FROM {term_synonym} WHERE tid = %d', $tid);
Kjartan's avatar
Kjartan committed
922
    while ($synonym = db_fetch_array($result)) {
Dries's avatar
   
Dries committed
923
      $synonyms[] = $synonym['name'];
Dries's avatar
 
Dries committed
924
    }
Kjartan's avatar
Kjartan committed
925
    return $synonyms ? $synonyms : array();
Dries's avatar
 
Dries committed
926
  }
Kjartan's avatar
Kjartan committed
927
928
  else {
    return array();
Dries's avatar
   
Dries committed
929
  }
Kjartan's avatar
Kjartan committed
930
}
Dries's avatar
   
Dries committed
931

Dries's avatar
   
Dries committed
932
933
934
935
936
/**
 * 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
937
}
Dries's avatar
   
Dries committed
938

Dries's avatar
   
Dries committed
939
940
941
/**
 * Given a term id, count the number of published nodes in it.
 */
Dries's avatar
   
Dries committed
942
function taxonomy_term_count_nodes($tid, $type = 0) {
Kjartan's avatar
Kjartan committed
943
  static $count;
Dries's avatar
   
Dries committed
944

Dries's avatar
   
Dries committed
945
946
947
  if (!isset($count[$type])) {
    // $type == 0 always evaluates true is $type is a string
    if (is_numeric($type)) {
948
      $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
949
950
    }
    else {
951
      $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 AND n.type = '%s' GROUP BY t.tid"), $type);
Dries's avatar
   
Dries committed
952
    }
Kjartan's avatar
Kjartan committed
953
    while ($term = db_fetch_object($result)) {
Dries's avatar
   
Dries committed
954
      $count[$type][$term->tid] = $term->c;
Dries's avatar
   
Dries committed
955
956
957
    }
  }

Kjartan's avatar
Kjartan committed
958
  foreach (_taxonomy_term_children($tid) as $c) {
Dries's avatar
   
Dries committed
959
    $children_count += taxonomy_term_count_nodes($c, $type);
Kjartan's avatar
Kjartan committed
960
  }
Dries's avatar
   
Dries committed
961
  return $count[$type][$tid] + $children_count;
Kjartan's avatar
Kjartan committed
962
963
}

Dries's avatar
   
Dries committed
964
965
966
/**
 * Helper for taxonomy_term_count_nodes().
 */
Kjartan's avatar
Kjartan committed
967
968
function _taxonomy_term_children($tid) {
  static $children;
Dries's avatar
   
Dries committed
969

Dries's avatar
   
Dries committed
970
  if (!isset($children)) {
Dries's avatar
   
Dries committed
971
    $result = db_query('SELECT tid, parent FROM {term_hierarchy}');
Kjartan's avatar
Kjartan committed
972
973
    while ($term = db_fetch_object($result)) {
      $children[$term->parent][] = $term->tid;
Dries's avatar
   
Dries committed
974
    }
Dries's avatar
 
Dries committed
975
  }
Kjartan's avatar
Kjartan committed
976
977
  return $children[$tid] ? $children[$tid] : array();
}
Dries's avatar
 
Dries committed
978

Dries's avatar
   
Dries committed
979
/**
Dries's avatar
   
Dries committed
980
 * Try to map a string to an existing term, as for glossary use.