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

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

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

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

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

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

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

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

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

66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
    $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/preview/vocabulary', 'title' => t('preview 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
86
87
88
89
90
91
    $items[] = array('path' => 'taxonomy/term', 'title' => t('taxonomy term'),
      'callback' => 'taxonomy_term_page',
      'access' => user_access('access content'),
      'type' => MENU_CALLBACK);
  }

Dries's avatar
   
Dries committed
92
93
  return $items;
}
Dries's avatar
 
Dries committed
94

95
96
97
98
99
100
101
102
103
104
105
/**
 * Implementation of hook_block().
 *
 * Generates a block with all categories.
 */
function taxonomy_block($op = 'list', $delta = 0) {
  if ($op == 'list') {
    $blocks[0]['info'] = t('Categories');
    return $blocks;
  }
  else if (user_access('access content')) {
Dries's avatar
   
Dries committed
106
    $result = db_query("SELECT d.tid, d.name, MAX(n.created) AS updated, COUNT(*) AS count FROM {term_data} d INNER JOIN {term_node} USING (tid) INNER JOIN {node} n USING (nid) WHERE n.status = 1 GROUP BY d.tid, d.name ORDER BY updated DESC, d.name");
107
108
    $items = array();
    while ($category = db_fetch_object($result)) {
Dries's avatar
   
Dries committed
109
      $items[] = l("$category->name ($category->count)", 'taxonomy/term/'. $category->tid) .'<br />'. format_interval(time() - $category->updated) .' '. t('ago');
110
111
112
113
114
115
116
117
    }

    $block['subject'] = t('Categories');
    $block['content'] = theme('item_list', $items);
    return $block;
  }
}

Kjartan's avatar
Kjartan committed
118
function taxonomy_form_vocabulary($edit = array()) {
Dries's avatar
   
Dries committed
119
  foreach (node_list() as $type) {
Dries's avatar
   
Dries committed
120
    $nodetypes[$type] = node_invoke($type, 'node_name');
Kjartan's avatar
Kjartan committed
121
  }
Dries's avatar
   
Dries committed
122

Dries's avatar
   
Dries committed
123
124
125
126
  $form .= form_textfield(t('Vocabulary name'), 'name', $edit['name'], 50, 64, t('The name for this vocabulary.  Example: "Topic".'), NULL, TRUE);
  $form .= form_textarea(t('Description'), 'description', $edit['description'], 60, 5, t('Description of the vocabulary; can be used by modules.'));
  $form .= form_textfield(t('Help text'), 'help', $edit['help'], 50, 255, t('Instructions to present to the user when choosing a term.'));
  $form .= form_checkboxes(t('Types'), 'nodes', explode(',', $edit['nodes']), $nodetypes, t('A list of node types you want to associate with this vocabulary.'), NULL, TRUE);
127
128
  $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_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
129
  $form .= form_checkbox(t('Multiple select'), 'multiple', 1, $edit['multiple'], t('Allows nodes to have more than one term in this vocabulary.'));
Dries's avatar
   
Dries committed
130
  $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
131
  $form .= form_weight(t('Weight'), 'weight', $edit['weight'], 10, t('In listings, the heavier vocabularies will sink and the lighter vocabularies will be positioned nearer the top.'));
Dries's avatar
   
Dries committed
132
  $form .= form_submit(t('Submit'));
Dries's avatar
 
Dries committed
133

Dries's avatar
   
Dries committed
134
135
136
  if ($edit['vid']) {
    $form .= form_submit(t('Delete'));
    $form .= form_hidden('vid', $edit['vid']);
Dries's avatar
 
Dries committed
137
138
  }

Kjartan's avatar
Kjartan committed
139
140
  return form($form);
}
Kjartan's avatar
Kjartan committed
141

Kjartan's avatar
Kjartan committed
142
function taxonomy_save_vocabulary($edit) {
Dries's avatar
   
Dries committed
143
144
  if (!$edit['nodes']) {
    $edit['nodes'] = array();
Dries's avatar
   
Dries committed
145
146
  }

Dries's avatar
   
Dries committed
147
148
  $data = array('name' => $edit['name'], 'nodes' => implode(',', $edit['nodes']), 'description' => $edit['description'], 'help' => $edit['help'], 'multiple' => $edit['multiple'], 'required' => $edit['required'], 'hierarchy' => $edit['hierarchy'], 'relations' => $edit['relations'], 'weight' => $edit['weight']);
  if ($edit['vid'] && $edit['name']) {
Dries's avatar
   
Dries committed
149
    db_query('UPDATE {vocabulary} SET '. _taxonomy_prepare_update($data) .' WHERE vid = %d', $edit['vid']);
Dries's avatar
   
Dries committed
150
    module_invoke_all('taxonomy', 'update', 'vocabulary', $edit);
Dries's avatar
   
Dries committed
151
    $message = t('Updated vocabulary %name.', array('%name' => '<em>'. $edit['name'] .'</em>'));
Dries's avatar
 
Dries committed
152
  }
Dries's avatar
   
Dries committed
153
154
  else if ($edit['vid']) {
    $message = taxonomy_del_vocabulary($edit['vid']);
Kjartan's avatar
Kjartan committed
155
156
  }
  else {
Dries's avatar
   
Dries committed
157
    $data['vid'] = $edit['vid'] = db_next_id('{vocabulary}_vid');
Dries's avatar
   
Dries committed
158
    db_query('INSERT INTO {vocabulary} '. _taxonomy_prepare_insert($data, 1) .' VALUES '. _taxonomy_prepare_insert($data, 2));
Dries's avatar
   
Dries committed
159
    module_invoke_all('taxonomy', 'insert', 'vocabulary', $edit);
Dries's avatar
   
Dries committed
160
    $message = t('Created new vocabulary %name.', array('%name' => '<em>'. $edit['name'] .'</em>'));
Kjartan's avatar
Kjartan committed
161
  }
Dries's avatar
   
Dries committed
162
163

  cache_clear_all();
Dries's avatar
   
Dries committed
164

Dries's avatar
   
Dries committed
165
  drupal_set_message($message);
166

Dries's avatar
   
Dries committed
167
  return $edit;
Kjartan's avatar
Kjartan committed
168
}
Dries's avatar
 
Dries committed
169

Kjartan's avatar
Kjartan committed
170
function taxonomy_del_vocabulary($vid) {
Dries's avatar
   
Dries committed
171
172
  $vocabulary = taxonomy_get_vocabulary($vid);

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

Dries's avatar
   
Dries committed
179
  module_invoke_all('taxonomy', 'delete', 'vocabulary', $vocabulary);
Dries's avatar
   
Dries committed
180

Dries's avatar
   
Dries committed
181
182
  cache_clear_all();

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

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

Dries's avatar
   
Dries committed
189
190
191
192
193
  $form .= form_hidden('confirm', 1);
  $form .= form_hidden('type', 'vocabulary');
  $form .= form_hidden('vid', $vid);
  $form .= form_submit(t('Delete'));
  $form .= form_submit(t('Cancel'));
Dries's avatar
   
Dries committed
194

Dries's avatar
   
Dries committed
195
  return form(form_item(t('Delete vocabulary "%name"', array('%name' => $vocabulary->name)), $form, t('Are you sure you want to delete the vocabulary and all its terms?')));
Kjartan's avatar
Kjartan committed
196
}
Dries's avatar
 
Dries committed
197

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

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

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

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

Kjartan's avatar
Kjartan committed
215
    if ($vocabulary->hierarchy == 1) {
216
      $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
217
    }
Kjartan's avatar
Kjartan committed
218
    elseif ($vocabulary->hierarchy == 2) {
219
      $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
220
    }
Kjartan's avatar
Kjartan committed
221
  }
Dries's avatar
 
Dries committed
222

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

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

Dries's avatar
   
Dries committed
232
233
234
  if ($edit['tid']) {
    $form .= form_submit(t('Delete'));
    $form .= form_hidden('tid', $edit['tid']);
Dries's avatar
 
Dries committed
235
236
  }

Kjartan's avatar
Kjartan committed
237
238
  return form($form);
}
Dries's avatar
 
Dries committed
239

Kjartan's avatar
Kjartan committed
240
function taxonomy_save_term($edit) {
Dries's avatar
   
Dries committed
241
242
  if ($edit['tid'] && $edit['name']) {
    $data = array('name' => $edit['name'], 'description' => $edit['description'], 'weight' => $edit['weight']);
Dries's avatar
 
Dries committed
243

Dries's avatar
   
Dries committed
244
    db_query('UPDATE {term_data} SET '. _taxonomy_prepare_update($data) .' WHERE tid = %d', $edit['tid']);
Dries's avatar
   
Dries committed
245
    module_invoke_all('taxonomy', 'update', 'term', $edit);
Dries's avatar
   
Dries committed
246
    $message = t('The term %term has been updated.', array('%term' => '<em>'. $edit['name'] .'</em>'));
Kjartan's avatar
Kjartan committed
247
  }
Dries's avatar
   
Dries committed
248
249
  else if ($edit['tid']) {
    return taxonomy_del_term($edit['tid']);
Kjartan's avatar
Kjartan committed
250
251
  }
  else {
Dries's avatar
   
Dries committed
252
253
    $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
254
    db_query('INSERT INTO {term_data} '. _taxonomy_prepare_insert($data, 1) .' VALUES '. _taxonomy_prepare_insert($data, 2));
Dries's avatar
   
Dries committed
255
    module_invoke_all('taxonomy', 'insert', 'term', $edit);
Dries's avatar
   
Dries committed
256
    $message = t('Created new term %term.', array('%term' => '<em>'. $edit['name'] .'</em>'));
Kjartan's avatar
Kjartan committed
257
  }
Dries's avatar
 
Dries committed
258

Dries's avatar
   
Dries committed
259
260
261
  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
262
      if ($related_id != 0) {
Dries's avatar
   
Dries committed
263
        db_query('INSERT INTO {term_relation} (tid1, tid2) VALUES (%d, %d)', $edit['tid'], $related_id);
Dries's avatar
 
Dries committed
264
      }
Kjartan's avatar
Kjartan committed
265
    }
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_hierarchy} WHERE tid = %d', $edit['tid']);
  if (!isset($edit['parent'])) {
    $edit['parent'] = 0;
Kjartan's avatar
Kjartan committed
271
  }
Dries's avatar
   
Dries committed
272
273
274
  if (is_array($edit['parent'])) {
    foreach ($edit['parent'] as $parent) {
      db_query('INSERT INTO {term_hierarchy} (tid, parent) VALUES (%d, %d)', $edit['tid'], $parent);
Dries's avatar
 
Dries committed
275
    }
Kjartan's avatar
Kjartan committed
276
277
  }
  else {
Dries's avatar
   
Dries committed
278
    db_query('INSERT INTO {term_hierarchy} (tid, parent) VALUES (%d, %d)', $edit['tid'], $edit['parent'][0]);
Dries's avatar
 
Dries committed
279
280
  }

Dries's avatar
   
Dries committed
281
282
283
  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
284
      if ($synonym) {
Dries's avatar
   
Dries committed
285
        db_query("INSERT INTO {term_synonym} (tid, name) VALUES (%d, '%s')", $edit['tid'], chop($synonym));
Dries's avatar
   
Dries committed
286
      }
Kjartan's avatar
Kjartan committed
287
    }
Dries's avatar
 
Dries committed
288
  }
Dries's avatar
   
Dries committed
289

Dries's avatar
   
Dries committed
290
291
  cache_clear_all();

Dries's avatar
   
Dries committed
292
  drupal_set_message($message);
Dries's avatar
   
Dries committed
293
  return $edit;
Kjartan's avatar
Kjartan committed
294
}
Dries's avatar
 
Dries committed
295

Kjartan's avatar
Kjartan committed
296
function taxonomy_del_term($tid) {
Dries's avatar
   
Dries committed
297
298
  $term = taxonomy_get_term($tid);

Dries's avatar
   
Dries committed
299
300
301
302
303
  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
304

Dries's avatar
   
Dries committed
305
  module_invoke_all('taxonomy', 'delete', 'term', $term);
Dries's avatar
   
Dries committed
306

Dries's avatar
   
Dries committed
307
308
  cache_clear_all();

Dries's avatar
   
Dries committed
309
  return t('deleted term "%name".', array('%name' => $term->name));
Dries's avatar
   
Dries committed
310
311
312
313
314
}

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

Dries's avatar
   
Dries committed
315
316
317
318
319
  $form .= form_hidden('confirm', 1);
  $form .= form_hidden('type', 'term');
  $form .= form_hidden('tid', $tid);
  $form .= form_submit(t('Delete'));
  $form .= form_submit(t('Cancel'));
Dries's avatar
   
Dries committed
320

Dries's avatar
   
Dries committed
321
  return form(form_item(t('Delete term "%name"', array('%name' => $term->name)), $form, t('Are you sure you want to delete the term?')));
Kjartan's avatar
Kjartan committed
322
}
Dries's avatar
 
Dries committed
323

Dries's avatar
   
Dries committed
324
325
326
/**
 * Generate a tabular listing of administrative functions for vocabularies.
 */
Kjartan's avatar
Kjartan committed
327
function taxonomy_overview() {
Dries's avatar
   
Dries committed
328
  $header = array(t('Name'), t('Node types'), array('data' => t('Operations'), 'colspan' => 3));
Dries's avatar
   
Dries committed
329

Kjartan's avatar
Kjartan committed
330
  $vocabularies = taxonomy_get_vocabularies();
Dries's avatar
   
Dries committed
331

Kjartan's avatar
Kjartan committed
332
333
  foreach ($vocabularies as $vocabulary) {
    $links = array();
Dries's avatar
   
Dries committed
334
    $types = array();
Dries's avatar
   
Dries committed
335
336
    foreach(explode(',', $vocabulary->nodes) as $type) {
      $types[] = node_invoke($type, 'node_name');
Dries's avatar
   
Dries committed
337
    }
Dries's avatar
   
Dries committed
338
    $rows[] = array($vocabulary->name, array('data' => implode(', ', $types), 'align' => 'center'), l(t('edit vocabulary'), "admin/taxonomy/edit/vocabulary/$vocabulary->vid"), l(t('add term'), "admin/taxonomy/add/term/$vocabulary->vid"), l(t('preview form'), "admin/taxonomy/preview/vocabulary/$vocabulary->vid"));
Kjartan's avatar
Kjartan committed
339

Dries's avatar
   
Dries committed
340
    $tree = taxonomy_get_tree($vocabulary->vid);
Kjartan's avatar
Kjartan committed
341
    if ($tree) {
Dries's avatar
   
Dries committed
342
      unset($data);
Kjartan's avatar
Kjartan committed
343
      foreach ($tree as $term) {
Dries's avatar
   
Dries committed
344
        $data .= _taxonomy_depth($term->depth) .' '. $term->name .' ('. l(t('edit term'), "admin/taxonomy/edit/term/$term->tid") .')<br />';
Dries's avatar
 
Dries committed
345
      }
Dries's avatar
   
Dries committed
346
      $rows[] = array(array('data' => $data, 'colspan' => 5));
Dries's avatar
 
Dries committed
347
348
349
    }
  }

Dries's avatar
   
Dries committed
350
  return theme('table', $header, $rows);
Kjartan's avatar
Kjartan committed
351
352
}

Dries's avatar
   
Dries committed
353
354
355
/**
 * Generate a form element for selecting terms from a vocabulary.
 */
Dries's avatar
   
Dries committed
356
function taxonomy_form($vid, $value = 0, $help = NULL, $name = 'taxonomy') {
Dries's avatar
   
Dries committed
357
  $vocabulary = taxonomy_get_vocabulary($vid);
358
  $help = ($help) ? $help : $vocabulary->help;
Kjartan's avatar
Kjartan committed
359
360
361
362
  if ($vocabulary->required) {
    $blank = 0;
  }
  else {
Dries's avatar
   
Dries committed
363
    $blank = '<'. t('none') .'>';
Kjartan's avatar
Kjartan committed
364
  }
Dries's avatar
   
Dries committed
365

Dries's avatar
   
Dries committed
366
  return _taxonomy_term_select($vocabulary->name, $name, $value, $vid, $help, intval($vocabulary->multiple), $blank);
Kjartan's avatar
Kjartan committed
367
}
Dries's avatar
 
Dries committed
368

Dries's avatar
   
Dries committed
369
370
371
372
373
374
375
/**
 * Return an array of all vocabulary objects.
 *
 * @param $type
 *   If set, return only those vocabularies associated with this node type.
 */
function taxonomy_get_vocabularies($type = '', $key = 'vid') {
Kjartan's avatar
Kjartan committed
376
  if ($type) {
Dries's avatar
   
Dries committed
377
    $result = db_query("SELECT * FROM {vocabulary} WHERE nodes LIKE '%%%s%%' ORDER BY weight, name", $type);
Kjartan's avatar
Kjartan committed
378
379
  }
  else {
Dries's avatar
   
Dries committed
380
    $result = db_query('SELECT * FROM {vocabulary} ORDER BY weight, name');
Kjartan's avatar
Kjartan committed
381
382
383
384
  }
  $vocabularies = array();
  while ($voc = db_fetch_object($result)) {
    $vocabularies[$voc->$key] = $voc;
Dries's avatar
 
Dries committed
385
  }
Dries's avatar
   
Dries committed
386

Kjartan's avatar
Kjartan committed
387
388
  return $vocabularies;
}
Dries's avatar
 
Dries committed
389

Dries's avatar
   
Dries committed
390
391
392
/**
 * Generate a form for selecting terms to associate with a node.
 */
Dries's avatar
   
Dries committed
393
function taxonomy_node_form($type, $node = '', $help = NULL, $name = 'taxonomy') {
Kjartan's avatar
Kjartan committed
394
395
396
  if (!$node->taxonomy) {
    if ($node->nid) {
      $terms = array_keys(taxonomy_node_get_terms($node->nid));
Kjartan's avatar
Kjartan committed
397
398
    }
    else {
Kjartan's avatar
Kjartan committed
399
      $terms = 0;
Dries's avatar
 
Dries committed
400
    }
Kjartan's avatar
Kjartan committed
401
402
403
404
  }
  else {
    $terms = $node->taxonomy;
  }
Dries's avatar
 
Dries committed
405

Dries's avatar
   
Dries committed
406
  $c = db_query("SELECT * FROM {vocabulary} WHERE nodes LIKE '%%%s%%' ORDER BY weight, name", $type);
Kjartan's avatar
Kjartan committed
407
  while ($vocabulary = db_fetch_object($c)) {
Dries's avatar
   
Dries committed
408
    $result[] = taxonomy_form($vocabulary->vid, $terms, $help, $name);
Dries's avatar
 
Dries committed
409
  }
Kjartan's avatar
Kjartan committed
410
411
  return $result ? $result : array();
}
Dries's avatar
 
Dries committed
412

Dries's avatar
   
Dries committed
413
414
415
/**
 * Determine whether a node mentions the name of a term.
 */
Kjartan's avatar
Kjartan committed
416
function taxonomy_node_has_term($nid, $tid) {
Dries's avatar
   
Dries committed
417
  $term_name = db_result(db_query('SELECT name FROM {term_data} WHERE tid = %d', $tid));
Dries's avatar
 
Dries committed
418

419
  return db_result(db_query("SELECT COUNT(n.nid) FROM {node} n WHERE n.nid = %d AND ((n.title LIKE '%%%s%%') OR (n.body LIKE '%%%s%%'))", $nid, $term_name, $term_name));
Kjartan's avatar
Kjartan committed
420
421
}

Dries's avatar
   
Dries committed
422
423
424
425
426
/**
 * 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
427
428
429
  $terms = array();
  while ($term = db_fetch_object($result)) {
    $terms[$term->$key] = $term;
Dries's avatar
 
Dries committed
430
  }
Kjartan's avatar
Kjartan committed
431
432
433
  return $terms;
}

Dries's avatar
   
Dries committed
434
435
436
437
/**
 * Find all terms associated to the given node.
 */
function taxonomy_node_get_terms($nid, $key = 'tid') {
Kjartan's avatar
Kjartan committed
438
  static $terms;
Dries's avatar
 
Dries committed
439

Dries's avatar
   
Dries committed
440
  if (!isset($terms[$nid])) {
Dries's avatar
   
Dries committed
441
    $result = db_query('SELECT t.* FROM {term_data} t, {term_node} r WHERE r.tid = t.tid AND r.nid = %d ORDER BY weight, name', $nid);
Kjartan's avatar
Kjartan committed
442
    $terms[$nid] = array();
Dries's avatar
 
Dries committed
443
    while ($term = db_fetch_object($result)) {
Kjartan's avatar
Kjartan committed
444
      $terms[$nid][$term->$key] = $term;
Dries's avatar
 
Dries committed
445
446
    }
  }
Kjartan's avatar
Kjartan committed
447
448
  return $terms[$nid];
}
Dries's avatar
 
Dries committed
449

Dries's avatar
   
Dries committed
450
451
452
/**
 * Save term associations for a given node.
 */
Kjartan's avatar
Kjartan committed
453
454
function taxonomy_node_save($nid, $terms) {
  taxonomy_node_delete($nid);
Dries's avatar
 
Dries committed
455

Kjartan's avatar
Kjartan committed
456
  if ($terms) {
Dries's avatar
   
Dries committed
457
    foreach ($terms as $term) {
458
      if ($term) {
Dries's avatar
   
Dries committed
459
        db_query('INSERT INTO {term_node} (nid, tid) VALUES (%d, %d)', $nid, $term);
460
      }
Dries's avatar
 
Dries committed
461
462
    }
  }
Kjartan's avatar
Kjartan committed
463
}
Dries's avatar
 
Dries committed
464

Dries's avatar
   
Dries committed
465
466
467
/**
 * Remove associations of a node to its terms.
 */
Kjartan's avatar
Kjartan committed
468
function taxonomy_node_delete($nid) {
Dries's avatar
   
Dries committed
469
  db_query('DELETE FROM {term_node} WHERE nid = %d', $nid);
Kjartan's avatar
Kjartan committed
470
}
Dries's avatar
 
Dries committed
471

Dries's avatar
   
Dries committed
472
473
474
475
/**
 * Find all term objects related to a given term ID.
 */
function taxonomy_get_related($tid, $key = 'tid') {
Kjartan's avatar
Kjartan committed
476
  if ($tid) {
Dries's avatar
   
Dries committed
477
    $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
478
479
480
    $related = array();
    while ($term = db_fetch_object($result)) {
      $related[$term->$key] = $term;
Dries's avatar
 
Dries committed
481
    }
Kjartan's avatar
Kjartan committed
482
    return $related;
Dries's avatar
 
Dries committed
483
  }
Kjartan's avatar
Kjartan committed
484
485
  else {
    return array();
Dries's avatar
 
Dries committed
486
  }
Kjartan's avatar
Kjartan committed
487
}
Dries's avatar
 
Dries committed
488

Dries's avatar
   
Dries committed
489
490
491
492
/**
 * Find all parents of a given term ID.
 */
function taxonomy_get_parents($tid, $key = 'tid') {
Kjartan's avatar
Kjartan committed
493
  if ($tid) {
Dries's avatar
   
Dries committed
494
    $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
495
496
497
    $parents = array();
    while ($parent = db_fetch_object($result)) {
      $parents[$parent->$key] = $parent;
Dries's avatar
   
Dries committed
498
    }
Kjartan's avatar
Kjartan committed
499
    return $parents;
Dries's avatar
 
Dries committed
500
  }
Kjartan's avatar
Kjartan committed
501
502
503
504
  else {
    return array();
  }
}
Dries's avatar
 
Dries committed
505

Dries's avatar
   
Dries committed
506
507
508
509
/**
 * Find all ancestors of a given term ID.
 */
function taxonomy_get_parents_all($tid) {
Dries's avatar
   
Dries committed
510
511
512
513
514
515
516
517
518
519
520
521
  $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
522
523
524
525
/**
 * Find all children of a term ID.
 */
function taxonomy_get_children($tid, $vid = 0, $key = 'tid') {
Kjartan's avatar
Kjartan committed
526
  if ($vid) {
Dries's avatar
   
Dries committed
527
    $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
528
  }
Kjartan's avatar
Kjartan committed
529
  else {
Dries's avatar
   
Dries committed
530
    $result = db_query('SELECT t.* FROM {term_hierarchy} h, {term_data} t WHERE h.tid = t.tid AND parent = %d ORDER BY weight', $tid);
Kjartan's avatar
Kjartan committed
531
532
533
534
535
536
537
  }
  $children = array();
  while ($term = db_fetch_object($result)) {
    $children[$term->$key] = $term;
  }
  return $children;
}
Dries's avatar
 
Dries committed
538

Dries's avatar
   
Dries committed
539
540
541
542
543
544
545
546
547
548
549
550
551
/**
 * 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
552
553
554
 * @param $max_depth
 *   The number of levels of the tree to return. Leave NULL to return all levels.
 *
Dries's avatar
   
Dries committed
555
556
557
558
559
 * @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
560
  static $children, $parents, $terms;
Dries's avatar
   
Dries committed
561

Kjartan's avatar
Kjartan committed
562
  $depth++;
Dries's avatar
   
Dries committed
563

Dries's avatar
   
Dries committed
564
565
566
567
  // 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
568

Dries's avatar
   
Dries committed
569
    $result = db_query('SELECT t.*, parent FROM {term_data} t, {term_hierarchy} h WHERE t.tid = h.tid AND t.vid = %d ORDER BY weight, name', $vid);
Dries's avatar
   
Dries committed
570
    while ($term = db_fetch_object($result)) {
Dries's avatar
   
Dries committed
571
572
573
      $children[$vid][$term->parent][] = $term->tid;
      $parents[$vid][$term->tid][] = $term->parent;
      $terms[$vid][$term->tid] = $term;
Dries's avatar
 
Dries committed
574
575
    }
  }
Dries's avatar
   
Dries committed
576

Dries's avatar
   
Dries committed
577
  $max_depth = (is_null($max_depth)) ? count($children[$vid]) : $max_depth;
Dries's avatar
   
Dries committed
578
579
  if ($children[$vid][$parent]) {
    foreach ($children[$vid][$parent] as $child) {
Dries's avatar
   
Dries committed
580
      if ($max_depth > $depth) {
Dries's avatar
   
Dries committed
581
582
583
584
585
        $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];
Dries's avatar
   
Dries committed
586

Dries's avatar
   
Dries committed
587
        $tree = array_merge($tree, taxonomy_get_tree($vid, $child, $depth, $max_depth));
Dries's avatar
   
Dries committed
588
      }
Dries's avatar
   
Dries committed
589
    }
Kjartan's avatar
Kjartan committed
590
  }
Dries's avatar
   
Dries committed
591

Dries's avatar
   
Dries committed
592
  return $tree ? $tree : array();
Kjartan's avatar
Kjartan committed
593
}
Dries's avatar
 
Dries committed
594

Dries's avatar
   
Dries committed
595
596
597
/**
 * Return an array of synonyms of the given term ID.
 */
Kjartan's avatar
Kjartan committed
598
599
function taxonomy_get_synonyms($tid) {
  if ($tid) {
Dries's avatar
   
Dries committed
600
    $result = db_query('SELECT name FROM {term_synonym} WHERE tid = %d', $tid);
Kjartan's avatar
Kjartan committed
601
    while ($synonym = db_fetch_array($result)) {
Dries's avatar
   
Dries committed
602
      $synonyms[] = $synonym['name'];
Dries's avatar
 
Dries committed
603
    }
Kjartan's avatar
Kjartan committed
604
    return $synonyms ? $synonyms : array();
Dries's avatar
 
Dries committed
605
  }
Kjartan's avatar
Kjartan committed
606
607
  else {
    return array();
Dries's avatar
   
Dries committed
608
  }
Kjartan's avatar
Kjartan committed
609
}
Dries's avatar
   
Dries committed
610

Dries's avatar
   
Dries committed
611
612
613
614
615
/**
 * 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
616
}
Dries's avatar
   
Dries committed
617

Dries's avatar
   
Dries committed
618
619
620
/**
 * Given a term id, count the number of published nodes in it.
 */
Dries's avatar
   
Dries committed
621
function taxonomy_term_count_nodes($tid, $type = 0) {
Kjartan's avatar
Kjartan committed
622
  static $count;
Dries's avatar
   
Dries committed
623

Dries's avatar
   
Dries committed
624
625
626
  if (!isset($count[$type])) {
    // $type == 0 always evaluates true is $type is a string
    if (is_numeric($type)) {
Dries's avatar
   
Dries committed
627
      $result = db_query('SELECT t.tid, COUNT(*) 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
628
629
    }
    else {
Dries's avatar
   
Dries committed
630
      $result = db_query("SELECT t.tid, COUNT(*) 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
631
    }
Kjartan's avatar
Kjartan committed
632
    while ($term = db_fetch_object($result)) {
Dries's avatar
   
Dries committed
633
      $count[$type][$term->tid] = $term->c;
Dries's avatar
   
Dries committed
634
635
636
    }
  }

Kjartan's avatar
Kjartan committed
637
  foreach (_taxonomy_term_children($tid) as $c) {
Dries's avatar
   
Dries committed
638
    $children_count += taxonomy_term_count_nodes($c, $type);
Kjartan's avatar
Kjartan committed
639
  }
Dries's avatar
   
Dries committed
640
  return $count[$type][$tid] + $children_count;
Kjartan's avatar
Kjartan committed
641
642
}

Dries's avatar
   
Dries committed
643
644
645
/**
 * Helper for taxonomy_term_count_nodes().
 */
Kjartan's avatar
Kjartan committed
646
647
function _taxonomy_term_children($tid) {
  static $children;
Dries's avatar
   
Dries committed
648

Dries's avatar
   
Dries committed
649
  if (!isset($children)) {
Dries's avatar
   
Dries committed
650
    $result = db_query('SELECT tid, parent FROM {term_hierarchy}');
Kjartan's avatar
Kjartan committed
651
652
    while ($term = db_fetch_object($result)) {
      $children[$term->parent][] = $term->tid;
Dries's avatar
   
Dries committed
653
    }
Dries's avatar
 
Dries committed
654
  }
Kjartan's avatar
Kjartan committed
655
656
  return $children[$tid] ? $children[$tid] : array();
}
Dries's avatar
 
Dries committed
657

Dries's avatar
   
Dries committed
658
/**
Dries's avatar
   
Dries committed
659
660
661
662
663
664
665
 * Try to map a string to an existing vocabulary.
 *
 * Provides a case-insensitive and trimmed mapping, to maximize the
 * likelihood of a successful match.
 *
 * @param name
 *   Name of the vocabulary to search for.
Dries's avatar
   
Dries committed
666
 *
Dries's avatar
   
Dries committed
667
668
 * @return
 *   An array of matching vocabulary objects.
Dries's avatar
   
Dries committed
669
670
 */
function taxonomy_get_vocabulary_by_name($name) {
Dries's avatar
   
Dries committed
671
  $db_result = db_query("SELECT * FROM {vocabulary} WHERE LOWER('%s') LIKE LOWER(name)", trim($name));
Dries's avatar
   
Dries committed
672
673
674
675
676
677
678
679
680
  $result = array();
  while ($vocabulary = db_fetch_object($db_result)) {
    $result[] = $vocabulary;
  }

  return $result;
}

/**
Dries's avatar
   
Dries committed
681
 * Try to map a string to an existing term, as for glossary use.
Dries's avatar
   
Dries committed
682
 *
Dries's avatar
   
Dries committed
683
684
685
686
687
688
689
690
 * Provides a case-insensitive and trimmed mapping, to maximize the
 * likelihood of a successful match.
 *
 * @param name
 *   Name of the term to search for.
 *
 * @return
 *   An array of matching term objects.
Dries's avatar
   
Dries committed
691
692
 */
function taxonomy_get_term_by_name($name) {
Dries's avatar
   
Dries committed
693
  $db_result = db_query("SELECT * FROM {term_data} WHERE LOWER('%s') LIKE LOWER(name)", trim($name));
Dries's avatar
   
Dries committed
694
695
696
697
698
699
700
701
  $result = array();
  while ($term = db_fetch_object($db_result)) {
    $result[] = $term;
  }

  return $result;
}

Dries's avatar
   
Dries committed
702
703
704
/**
 * Return the vocabulary object matching a vocabulary ID.
 */
Kjartan's avatar
Kjartan committed
705
function taxonomy_get_vocabulary($vid) {
Dries's avatar
   
Dries committed
706
  return db_fetch_object(db_query('SELECT * FROM {vocabulary} WHERE vid = %d', $vid));
Kjartan's avatar
Kjartan committed
707
}
Dries's avatar
 
Dries committed
708

Dries's avatar
   
Dries committed
709
710
711
/**
 * Return the term object matching a term ID.
 */
Kjartan's avatar
Kjartan committed
712
713
function taxonomy_get_term($tid) {
  // simple cache using a static var?
Dries's avatar
   
Dries committed
714
  return db_fetch_object(db_query('SELECT * FROM {term_data} WHERE tid = %d', $tid));
Kjartan's avatar
Kjartan committed
715
}
Dries's avatar
 
Dries committed
716

Kjartan's avatar
Kjartan committed
717
function _taxonomy_term_select($title, $name, $value, $vocabulary_id, $description, $multiple, $blank, $exclude = array()) {
Dries's avatar
   
Dries committed
718
  $tree = taxonomy_get_tree($vocabulary_id);
Dries's avatar
Dries committed
719
720
721
  if ($blank) {
    $options[] = array('tid' => 0, 'name' => $blank);
  }
Kjartan's avatar
Kjartan committed
722
723
724
  if ($tree) {
    foreach ($tree as $term) {
      if (!in_array($term->tid, $exclude)) {
Dries's avatar
   
Dries committed
725
        $options[] = array('tid' => $term->tid, 'name' => _taxonomy_depth($term->depth, '-').$term->name);
Dries's avatar
 
Dries committed
726
727
      }
    }
Kjartan's avatar
Kjartan committed
728
729
730
731
732
    if (!$blank && !$value) {
      // required but without a predefined value, so set first as predefined
      $value = $tree[0]->tid;
    }
  }
Dries's avatar
 
Dries committed
733

Kjartan's avatar
Kjartan committed
734
  if (count($options) > 0) {
Dries's avatar
   
Dries committed
735
    foreach ($options as $option) {
Dries's avatar
   
Dries committed
736
      $select .= '<option value="'. $option['tid'] .'"'. (is_array($value) ? (in_array($option['tid'], $value) ? ' selected="selected"' : '') : ($option['tid'] == $value ? ' selected="selected"' : '')) .'>'. check_form($option['name']) .'</option>';
Kjartan's avatar
Kjartan committed
737
    }
Dries's avatar
 
Dries committed
738

Dries's avatar
   
Dries committed
739
    $size = min(12, count($options));
Dries's avatar
 
Dries committed
740

Dries's avatar
   
Dries committed
741
    return form_item($title, "<select name=\"edit[$name][]\"". ($multiple ? " multiple=\"multiple\" size=\"$size\"" : '') . ($extra ? " $extra" : '') .' class="'. _form_get_class('', false, _form_get_error($name)) ."\">$select</select>", $description, NULL, false, _form_get_error($name));
Dries's avatar
 
Dries committed
742
  }
Kjartan's avatar
Kjartan committed
743
}
Dries's avatar
 
Dries committed
744

Kjartan's avatar
Kjartan committed
745
746
747
function _taxonomy_depth($depth, $graphic = '--') {
  for ($n = 0; $n < $depth; $n++) {
    $result .= $graphic;
Dries's avatar
 
Dries committed
748
  }
Kjartan's avatar
Kjartan committed
749
750
  return $result;
}
Dries's avatar
 
Dries committed
751

Dries's avatar
   
Dries committed
752
function _taxonomy_prepare_update($data) {
Kjartan's avatar
Kjartan committed
753
  foreach ($data as $key => $value) {
754
    $q[] = "$key = '". str_replace('%', '%%', check_query($value)) ."'";
Dries's avatar
 
Dries committed
755
  }
Dries's avatar
   
Dries committed
756
  $result = implode(', ', $q);
Kjartan's avatar
Kjartan committed
757
758
  return $result;
}
Dries's avatar
 
Dries committed
759

Dries's avatar
   
Dries committed
760
function _taxonomy_prepare_insert($data, $stage) {
Kjartan's avatar
Kjartan committed
761
  if ($stage == 1) {
Dries's avatar
   
Dries committed
762
    $result = implode(', ', array_keys($data));
Kjartan's avatar
Kjartan committed
763
764
765
  }
  else {
    foreach (array_values($data) as $value) {
766
      $q[] = "'". str_replace('%', '%%', check_query($value)) ."'";
Dries's avatar
 
Dries committed
767
    }
Dries's avatar
   
Dries committed
768
    $result = implode(', ', $q);
Dries's avatar
 
Dries committed
769
  }
Kjartan's avatar
Kjartan committed
770
771
  return "($result)";
}
Dries's avatar
   
Dries committed
772

Dries's avatar
   
Dries committed
773
774
775
/**
 * Finds all nodes that match selected taxonomy conditions.
 *
Dries's avatar
   
Dries committed
776
777
778
779
780
781
782
 * @param $tids
 *   An array of term IDs to match.
 * @param $operator
 *   How to interpret multiple IDs in the array. Can be "or" or "and".
 * @param $depth
 *   How many levels deep to traverse the taxonomy tree. Can be a nonnegative
 *   integer or "all".
Dries's avatar
   
Dries committed
783
784
785
786
787
788
 * @param $pager
 *   Whether the nodes are to be used with a pager (the case on most Drupal
 *   pages) or not (in an XML feed, for example).
 * @return
 *   A resource identifier pointing to the query results.
 */
Dries's avatar
   
Dries committed
789
790
791
792
793
794
795
796
797
798
function taxonomy_select_nodes($tids = array(), $operator = 'or', $depth = 0, $pager = TRUE) {
  if (count($tids) > 0) {
    // For each term ID, generate an array of descendant term IDs to the right depth.
    $descendant_tids = array();
    if ($depth === 'all') {
      $depth = NULL;
    }
    foreach ($tids as $index => $tid) {
      $term = taxonomy_get_term($tid);
      $tree = taxonomy_get_tree($term->vid, $tid, -1, $depth);
Steven Wittens's avatar
Steven Wittens committed
799
      $descendant_tids[] = array_merge(array($tid), array_map('_taxonomy_get_tid_from_term', $tree));
800
    }
Dries's avatar
   
Dries committed
801

Dries's avatar
   
Dries committed
802
803
804
805
806
807
808
809
810
811
812
813
814
815
    if ($operator == 'or') {
      $str_tids = implode(',', call_user_func_array('array_merge', $descendant_tids));
      $sql = 'SELECT DISTINCT(n.nid) FROM {node} n '. node_access_join_sql() .' INNER JOIN {term_node} tn ON n.nid = tn.nid WHERE tn.tid IN ('. $str_tids .') AND n.status = 1 AND '. node_access_where_sql() .' ORDER BY n.sticky DESC, n.created DESC';
      $sql_count = 'SELECT COUNT(DISTINCT(n.nid)) FROM {node} n '. node_access_join_sql() .' INNER JOIN {term_node} tn ON n.nid = tn.nid WHERE tn.tid IN ('. $str_tids .') AND n.status = 1 AND '. node_access_where_sql();
    }
    else {
      $joins = '';
      $wheres = '';
      foreach ($descendant_tids as $index => $tids) {
        $joins .= ' INNER JOIN {term_node} tn'. $index .' ON n.nid = tn'. $index .'.nid';
        $wheres .= ' AND tn'. $index .'.tid IN ('. implode(',', $tids) .')';
      }
      $sql = 'SELECT DISTINCT(n.nid) FROM {node} n '. node_access_join_sql() . $joins .' WHERE n.status = 1 AND '. node_access_where_sql() . $wheres .' ORDER BY n.sticky DESC, n.created DESC';
      $sql_count = 'SELECT COUNT(DISTINCT(n.nid)) FROM {node} n '. node_access_join_sql() . $joins .' WHERE n.status = 1 AND '. node_access_where_sql() . $wheres;
816
    }
Dries's avatar
   
Dries committed
817

818
    if ($pager) {
Dries's avatar
   
Dries committed
819
      $result = pager_query($sql, variable_get('default_nodes_main', 10) , 0, $sql_count);
820
821
822
823
    }
    else {
      $result = db_query_range($sql, 0, 15);
    }
Dries's avatar
   
Dries committed
824
825
826
827
828
  }

  return $result;
}

Dries's avatar
   
Dries committed
829
830
831
/**
 * Accepts the result of a pager_query() call, such as that performed by
 * taxonomy_select_nodes(), and formats each node along with a pager.
Dries's avatar
   
Dries committed
832
833
*/
function taxonomy_render_nodes($result) {
834
835
836
837
838
839
840
841
  if (db_num_rows($result) > 0) {
    while ($node = db_fetch_object($result)) {
      $output .= node_view(node_load(array('nid' => $node->nid)), 1);
    }
    $output .= theme('pager', NULL, variable_get('default_nodes_main', 10), 0);
  }
  else {
    $output .= t('There are currently no posts in this category.');
Dries's avatar
   
Dries committed
842
  }
Dries's avatar
   
Dries committed
843
  return $output;
Dries's avatar
   
Dries committed
844
845
}

Dries's avatar
   
Dries committed
846
847
848
/**
 * Implementation of hook_nodeapi().
 */
Dries's avatar
   
Dries committed
849
850
function taxonomy_nodeapi($node, $op, $arg = 0) {
  switch ($op) {
Dries's avatar
   
Dries committed
851
    case 'insert':
Dries's avatar
   
Dries committed
852
853
      taxonomy_node_save($node->nid, $node->taxonomy);
      break;
Dries's avatar
   
Dries committed
854
    case 'update':
Dries's avatar
   
Dries committed
855
856
      taxonomy_node_save($node->nid, $node->taxonomy);
      break;
Dries's avatar
   
Dries committed
857
    case 'delete':
Dries's avatar
   
Dries committed
858
859
860
861
862
      taxonomy_node_delete($node->nid);
      break;
  }
}

Dries's avatar
   
Dries committed
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
/**
 * Menu callback; displays all nodes associated with a term.
 */
function taxonomy_term_page($str_tids = '', $depth = 0, $op = 'page') {
  if (preg_match('/^([0-9]+[+ ])+[0-9]+$/', $str_tids)) {
    $operator = 'or';
    // The '+' character in a query string may be parsed as ' '.
    $tids = preg_split('/[+ ]/', $str_tids);
  }
  else if (preg_match('/^([0-9]+,)*[0-9]+$/', $str_tids)) {
    $operator = 'and';
    $tids = explode(',', $str_tids);
  }
  else {
    drupal_not_found();
  }
Dries's avatar
   
Dries committed
879

Dries's avatar
   
Dries committed
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
  if ($tids) {
    // Build title:
    $result = db_query('SELECT name FROM {term_data} WHERE tid IN (%s)', implode(',', $tids));
    $names = array();
    while ($term = db_fetch_object($result)) {
      $names[] = $term->name;
    }
    $title = implode(', ', $names);

    switch ($op) {
      case 'page':
        // Build breadcrumb based on first hierarchy of first term:
        $current->tid = $tids[0];
        $breadcrumbs = array(array('path' => $_GET['q']));
        while ($parents = taxonomy_get_parents($current->tid)) {
          $current = array_shift($parents);
          $breadcrumbs[] = array('path' => 'taxonomy/term/'. $current->tid, 'title' => $current->name);
        }
        $breadcrumbs = array_reverse($breadcrumbs);
        menu_set_location($breadcrumbs);

        drupal_set_html_head('<link rel="alternate" type="application/rss+xml" title="RSS - '. $title .'" href="'. url('taxonomy/term/'. $str_tids .'/'. $depth .'/feed') .'" />');

        $output = taxonomy_render_nodes(taxonomy_select_nodes($tids, $operator, $depth, TRUE));
        print theme('page', $output, $title);
        break;

      case 'feed':
        $term = taxonomy_get_term($tids[0]);
        $channel['link'] = url('taxonomy/term/'. $str_tids .'/'. $depth, NULL, NULL, TRUE);
        $channel['title'] = variable_get('site_name', 'drupal') .' - '. $title;
        $channel['description'] = $term->description;

        $result = taxonomy_select_nodes($tids, $operator, $depth, FALSE);
        node_feed($result, $channel);
        break;
      default:
        drupal_not_found();
    }
Dries's avatar
   
Dries committed
919
  }
Kjartan's avatar
Kjartan committed
920
}
Dries's avatar
   
Dries committed
921

Dries's avatar
   
Dries committed
922
923
924
/**
 * Menu callback; dispatches to the proper taxonomy administration function.
 */
Kjartan's avatar
Kjartan committed
925
function taxonomy_admin() {
Dries's avatar
   
Dries committed
926
927
  $op = $_POST['op'];
  $edit = $_POST['edit'];
Kjartan's avatar
Kjartan committed
928

Dries's avatar
   
Dries committed