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

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

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

Dries Buytaert's avatar
   
Dries Buytaert 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 Buytaert's avatar
   
Dries Buytaert committed
27
function taxonomy_link($type, $node = NULL) {
Dries Buytaert's avatar
   
Dries Buytaert committed
28
  if ($type == 'taxonomy terms' && $node != NULL) {
Kjartan Mannes's avatar
   
Kjartan Mannes committed
29
    $links = array();
Dries Buytaert's avatar
   
Dries Buytaert committed
30
    if (array_key_exists('taxonomy', $node)) {
Dries Buytaert's avatar
   
Dries Buytaert committed
31
32
      foreach ($node->taxonomy as $tid) {
        $term = taxonomy_get_term($tid);
33
        $links[] = l($term->name, 'taxonomy/term/'. $term->tid, $term->description ? array ('title' => check_output($term->description)) : array());
Dries Buytaert's avatar
   
Dries Buytaert committed
34
35
36
37
38
      }
    }
    else {
      $links = array();
      foreach (taxonomy_node_get_terms($node->nid) as $term) {
39
        $links[] = l($term->name, 'taxonomy/term/'. $term->tid, $term->description ? array ('title' => check_output($term->description)) : array());
Dries Buytaert's avatar
   
Dries Buytaert committed
40
      }
Dries Buytaert's avatar
   
Dries Buytaert committed
41
42
43
44

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

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

Dries Buytaert's avatar
   
Dries Buytaert committed
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
  if ($may_cache) {
    $items[] = array('path' => 'admin/taxonomy', 'title' => t('categories'),
      'callback' => 'taxonomy_admin',
      'access' => user_access('administer taxonomy'));
    $items[] = array('path' => 'admin/taxonomy/list', 'title' => t('list'),
      'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10);
    $items[] = array('path' => 'admin/taxonomy/add/vocabulary', 'title' => t('add vocabulary'),
      'callback' => 'taxonomy_admin',
      'access' => user_access('administer taxonomy'),
      'type' => MENU_LOCAL_TASK);

    $items[] = array('path' => 'taxonomy/term', 'title' => t('taxonomy term'),
      'callback' => 'taxonomy_term_page',
      'access' => user_access('access content'),
      'type' => MENU_CALLBACK);
  }

Dries Buytaert's avatar
   
Dries Buytaert committed
70
71
  return $items;
}
Dries Buytaert's avatar
 
Dries Buytaert committed
72

73
74
75
76
77
78
79
80
81
82
83
/**
 * 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 Buytaert's avatar
   
Dries Buytaert committed
84
    $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");
85
86
    $items = array();
    while ($category = db_fetch_object($result)) {
Dries Buytaert's avatar
   
Dries Buytaert committed
87
      $items[] = l("$category->name ($category->count)", 'taxonomy/term/'. $category->tid) .'<br />'. format_interval(time() - $category->updated) .' '. t('ago');
88
89
90
91
92
93
94
95
    }

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

Kjartan Mannes's avatar
Kjartan Mannes committed
96
function taxonomy_form_vocabulary($edit = array()) {
Dries Buytaert's avatar
   
Dries Buytaert committed
97
  foreach (node_list() as $type) {
Dries Buytaert's avatar
   
Dries Buytaert committed
98
    $nodetypes[$type] = node_invoke($type, 'node_name');
Kjartan Mannes's avatar
Kjartan Mannes committed
99
  }
Dries Buytaert's avatar
   
Dries Buytaert committed
100

Dries Buytaert's avatar
   
Dries Buytaert committed
101
102
103
104
105
106
107
  $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);
  $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/taxonomy/help', 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/taxonomy/help', NULL, NULL, 'hierarchy'))));
  $form .= form_checkbox(t('Multiple select'), 'multiple', 1, $edit['multiple'], t('Allows nodes to have more than one term in this vocabulary.'));
Dries Buytaert's avatar
   
Dries Buytaert committed
108
  $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 Buytaert's avatar
   
Dries Buytaert committed
109
  $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 Buytaert's avatar
   
Dries Buytaert committed
110
  $form .= form_submit(t('Submit'));
Dries Buytaert's avatar
 
Dries Buytaert committed
111

Dries Buytaert's avatar
   
Dries Buytaert committed
112
113
114
  if ($edit['vid']) {
    $form .= form_submit(t('Delete'));
    $form .= form_hidden('vid', $edit['vid']);
Dries Buytaert's avatar
 
Dries Buytaert committed
115
116
  }

Kjartan Mannes's avatar
Kjartan Mannes committed
117
118
  return form($form);
}
Kjartan Mannes's avatar
Kjartan Mannes committed
119

Kjartan Mannes's avatar
Kjartan Mannes committed
120
function taxonomy_save_vocabulary($edit) {
Dries Buytaert's avatar
   
Dries Buytaert committed
121
122
  if (!$edit['nodes']) {
    $edit['nodes'] = array();
Dries Buytaert's avatar
   
Dries Buytaert committed
123
124
  }

Dries Buytaert's avatar
   
Dries Buytaert committed
125
126
  $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 Buytaert's avatar
   
Dries Buytaert committed
127
    db_query('UPDATE {vocabulary} SET '. _taxonomy_prepare_update($data) .' WHERE vid = %d', $edit['vid']);
Dries Buytaert's avatar
   
Dries Buytaert committed
128
    module_invoke_all('taxonomy', 'update', 'vocabulary', $edit);
Dries Buytaert's avatar
   
Dries Buytaert committed
129
    $message = t('Updated vocabulary %name.', array('%name' => '<em>'. $edit['name'] .'</em>'));
Dries Buytaert's avatar
 
Dries Buytaert committed
130
  }
Dries Buytaert's avatar
   
Dries Buytaert committed
131
132
  else if ($edit['vid']) {
    $message = taxonomy_del_vocabulary($edit['vid']);
Kjartan Mannes's avatar
Kjartan Mannes committed
133
134
  }
  else {
Dries Buytaert's avatar
   
Dries Buytaert committed
135
    $data['vid'] = $edit['vid'] = db_next_id('{vocabulary}_vid');
Dries Buytaert's avatar
   
Dries Buytaert committed
136
    db_query('INSERT INTO {vocabulary} '. _taxonomy_prepare_insert($data, 1) .' VALUES '. _taxonomy_prepare_insert($data, 2));
Dries Buytaert's avatar
   
Dries Buytaert committed
137
    module_invoke_all('taxonomy', 'insert', 'vocabulary', $edit);
Dries Buytaert's avatar
   
Dries Buytaert committed
138
    $message = t('Created new vocabulary %name.', array('%name' => '<em>'. $edit['name'] .'</em>'));
Kjartan Mannes's avatar
Kjartan Mannes committed
139
  }
Dries Buytaert's avatar
   
Dries Buytaert committed
140
141

  cache_clear_all();
Dries Buytaert's avatar
   
Dries Buytaert committed
142

Dries Buytaert's avatar
   
Dries Buytaert committed
143
  drupal_set_message($message);
144

Dries Buytaert's avatar
   
Dries Buytaert committed
145
  return $edit;
Kjartan Mannes's avatar
Kjartan Mannes committed
146
}
Dries Buytaert's avatar
 
Dries Buytaert committed
147

Kjartan Mannes's avatar
Kjartan Mannes committed
148
function taxonomy_del_vocabulary($vid) {
Dries Buytaert's avatar
   
Dries Buytaert committed
149
150
  $vocabulary = taxonomy_get_vocabulary($vid);

Dries Buytaert's avatar
   
Dries Buytaert committed
151
152
  db_query('DELETE FROM {vocabulary} WHERE vid = %d', $vid);
  $result = db_query('SELECT tid FROM {term_data} WHERE vid = %d', $vid);
Kjartan Mannes's avatar
Kjartan Mannes committed
153
154
  while ($term = db_fetch_object($result)) {
    taxonomy_del_term($term->tid);
Dries Buytaert's avatar
 
Dries Buytaert committed
155
  }
Dries Buytaert's avatar
   
Dries Buytaert committed
156

Dries Buytaert's avatar
   
Dries Buytaert committed
157
  module_invoke_all('taxonomy', 'delete', 'vocabulary', $vocabulary);
Dries Buytaert's avatar
   
Dries Buytaert committed
158

Dries Buytaert's avatar
   
Dries Buytaert committed
159
160
  cache_clear_all();

Dries Buytaert's avatar
   
Dries Buytaert committed
161
  return t('deleted vocabulary "%name".', array('%name' => $vocabulary->name));
Dries Buytaert's avatar
   
Dries Buytaert committed
162
163
164
165
166
}

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

Dries Buytaert's avatar
   
Dries Buytaert committed
167
168
169
170
171
  $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 Buytaert's avatar
   
Dries Buytaert committed
172

Dries Buytaert's avatar
   
Dries Buytaert committed
173
  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 Mannes's avatar
Kjartan Mannes committed
174
}
Dries Buytaert's avatar
 
Dries Buytaert committed
175

Kjartan Mannes's avatar
Kjartan Mannes committed
176
function taxonomy_form_term($edit = array()) {
Dries Buytaert's avatar
   
Dries Buytaert committed
177
  $vocabulary_id = isset($edit['vid']) ? $edit['vid'] : arg(4);
Kjartan Mannes's avatar
Kjartan Mannes committed
178
  $vocabulary = taxonomy_get_vocabulary($vocabulary_id);
Dries Buytaert's avatar
   
Dries Buytaert committed
179

Dries Buytaert's avatar
   
Dries Buytaert committed
180
181
  $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 Buytaert's avatar
 
Dries Buytaert committed
182

Kjartan Mannes's avatar
Kjartan Mannes committed
183
  if ($vocabulary->hierarchy) {
Dries Buytaert's avatar
   
Dries Buytaert committed
184
185
    $parent = array_keys(taxonomy_get_parents($edit['tid']));
    $children = taxonomy_get_tree($vocabulary_id, $edit['tid']);
Dries Buytaert's avatar
   
Dries Buytaert committed
186

Dries Buytaert's avatar
   
Dries Buytaert committed
187
    // A term can't be the child of itself, nor of its children.
Dries Buytaert's avatar
   
Dries Buytaert committed
188
189
190
    foreach ($children as $child) {
      $exclude[] = $child->tid;
    }
Dries Buytaert's avatar
   
Dries Buytaert committed
191
    $exclude[] = $edit['tid'];
Dries Buytaert's avatar
   
Dries Buytaert committed
192

Kjartan Mannes's avatar
Kjartan Mannes committed
193
    if ($vocabulary->hierarchy == 1) {
Dries Buytaert's avatar
   
Dries Buytaert committed
194
      $form .= _taxonomy_term_select(t('Parent'), 'parent', $parent, $vocabulary_id, l(t('Parent term'), 'admin/taxonomy/help', NULL, NULL, 'parent') .'.', 0, '<'. t('root') .'>', $exclude);
Dries Buytaert's avatar
 
Dries Buytaert committed
195
    }
Kjartan Mannes's avatar
Kjartan Mannes committed
196
    elseif ($vocabulary->hierarchy == 2) {
Dries Buytaert's avatar
   
Dries Buytaert committed
197
      $form .= _taxonomy_term_select(t('Parents'), 'parent', $parent, $vocabulary_id, l(t('Parent terms'), 'admin/taxonomy/help', NULL, NULL, 'parent') .'.', 1, '<'. t('root') .'>', $exclude);
Dries Buytaert's avatar
 
Dries Buytaert committed
198
    }
Kjartan Mannes's avatar
Kjartan Mannes committed
199
  }
Dries Buytaert's avatar
 
Dries Buytaert committed
200

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

Dries Buytaert's avatar
   
Dries Buytaert committed
205
206
  $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/taxonomy/help', NULL, NULL, 'synonyms'))));
  $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 Buytaert's avatar
   
Dries Buytaert committed
207
208
  $form .= form_hidden('vid', $vocabulary->vid);
  $form .= form_submit(t('Submit'));
Kjartan Mannes's avatar
Kjartan Mannes committed
209

Dries Buytaert's avatar
   
Dries Buytaert committed
210
211
212
  if ($edit['tid']) {
    $form .= form_submit(t('Delete'));
    $form .= form_hidden('tid', $edit['tid']);
Dries Buytaert's avatar
 
Dries Buytaert committed
213
214
  }

Kjartan Mannes's avatar
Kjartan Mannes committed
215
216
  return form($form);
}
Dries Buytaert's avatar
 
Dries Buytaert committed
217

Kjartan Mannes's avatar
Kjartan Mannes committed
218
function taxonomy_save_term($edit) {
Dries Buytaert's avatar
   
Dries Buytaert committed
219
220
  if ($edit['tid'] && $edit['name']) {
    $data = array('name' => $edit['name'], 'description' => $edit['description'], 'weight' => $edit['weight']);
Dries Buytaert's avatar
 
Dries Buytaert committed
221

Dries Buytaert's avatar
   
Dries Buytaert committed
222
    db_query('UPDATE {term_data} SET '. _taxonomy_prepare_update($data) .' WHERE tid = %d', $edit['tid']);
Dries Buytaert's avatar
   
Dries Buytaert committed
223
    module_invoke_all('taxonomy', 'update', 'term', $edit);
Dries Buytaert's avatar
   
Dries Buytaert committed
224
    $message = t('The term %term has been updated.', array('%term' => '<em>'. $edit['name'] .'</em>'));
Kjartan Mannes's avatar
Kjartan Mannes committed
225
  }
Dries Buytaert's avatar
   
Dries Buytaert committed
226
227
  else if ($edit['tid']) {
    return taxonomy_del_term($edit['tid']);
Kjartan Mannes's avatar
Kjartan Mannes committed
228
229
  }
  else {
Dries Buytaert's avatar
   
Dries Buytaert committed
230
231
    $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 Buytaert's avatar
   
Dries Buytaert committed
232
    db_query('INSERT INTO {term_data} '. _taxonomy_prepare_insert($data, 1) .' VALUES '. _taxonomy_prepare_insert($data, 2));
Dries Buytaert's avatar
   
Dries Buytaert committed
233
    module_invoke_all('taxonomy', 'insert', 'term', $edit);
Dries Buytaert's avatar
   
Dries Buytaert committed
234
    $message = t('Created new term %term.', array('%term' => '<em>'. $edit['name'] .'</em>'));
Kjartan Mannes's avatar
Kjartan Mannes committed
235
  }
Dries Buytaert's avatar
 
Dries Buytaert committed
236

Dries Buytaert's avatar
   
Dries Buytaert committed
237
238
239
  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 Mannes's avatar
Kjartan Mannes committed
240
      if ($related_id != 0) {
Dries Buytaert's avatar
   
Dries Buytaert committed
241
        db_query('INSERT INTO {term_relation} (tid1, tid2) VALUES (%d, %d)', $edit['tid'], $related_id);
Dries Buytaert's avatar
 
Dries Buytaert committed
242
      }
Kjartan Mannes's avatar
Kjartan Mannes committed
243
    }
Kjartan Mannes's avatar
Kjartan Mannes committed
244
  }
Dries Buytaert's avatar
 
Dries Buytaert committed
245

Dries Buytaert's avatar
   
Dries Buytaert committed
246
247
248
  db_query('DELETE FROM {term_hierarchy} WHERE tid = %d', $edit['tid']);
  if (!isset($edit['parent'])) {
    $edit['parent'] = 0;
Kjartan Mannes's avatar
Kjartan Mannes committed
249
  }
Dries Buytaert's avatar
   
Dries Buytaert committed
250
251
252
  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 Buytaert's avatar
 
Dries Buytaert committed
253
    }
Kjartan Mannes's avatar
Kjartan Mannes committed
254
255
  }
  else {
Dries Buytaert's avatar
   
Dries Buytaert committed
256
    db_query('INSERT INTO {term_hierarchy} (tid, parent) VALUES (%d, %d)', $edit['tid'], $edit['parent'][0]);
Dries Buytaert's avatar
 
Dries Buytaert committed
257
258
  }

Dries Buytaert's avatar
   
Dries Buytaert committed
259
260
261
  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 Buytaert's avatar
   
Dries Buytaert committed
262
      if ($synonym) {
Dries Buytaert's avatar
   
Dries Buytaert committed
263
        db_query("INSERT INTO {term_synonym} (tid, name) VALUES (%d, '%s')", $edit['tid'], chop($synonym));
Dries Buytaert's avatar
   
Dries Buytaert committed
264
      }
Kjartan Mannes's avatar
Kjartan Mannes committed
265
    }
Dries Buytaert's avatar
 
Dries Buytaert committed
266
  }
Dries Buytaert's avatar
   
Dries Buytaert committed
267

Dries Buytaert's avatar
   
Dries Buytaert committed
268
269
  cache_clear_all();

Dries Buytaert's avatar
   
Dries Buytaert committed
270
  drupal_set_message($message);
Dries Buytaert's avatar
   
Dries Buytaert committed
271
  return $edit;
Kjartan Mannes's avatar
Kjartan Mannes committed
272
}
Dries Buytaert's avatar
 
Dries Buytaert committed
273

Kjartan Mannes's avatar
Kjartan Mannes committed
274
function taxonomy_del_term($tid) {
Dries Buytaert's avatar
   
Dries Buytaert committed
275
276
  $term = taxonomy_get_term($tid);

Dries Buytaert's avatar
   
Dries Buytaert committed
277
278
279
280
281
  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 Buytaert's avatar
   
Dries Buytaert committed
282

Dries Buytaert's avatar
   
Dries Buytaert committed
283
  module_invoke_all('taxonomy', 'delete', 'term', $term);
Dries Buytaert's avatar
   
Dries Buytaert committed
284

Dries Buytaert's avatar
   
Dries Buytaert committed
285
286
  cache_clear_all();

Dries Buytaert's avatar
   
Dries Buytaert committed
287
  return t('deleted term "%name".', array('%name' => $term->name));
Dries Buytaert's avatar
   
Dries Buytaert committed
288
289
290
291
292
}

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

Dries Buytaert's avatar
   
Dries Buytaert committed
293
294
295
296
297
  $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 Buytaert's avatar
   
Dries Buytaert committed
298

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

Dries Buytaert's avatar
   
Dries Buytaert committed
302
303
304
/**
 * Generate a tabular listing of administrative functions for vocabularies.
 */
Kjartan Mannes's avatar
Kjartan Mannes committed
305
function taxonomy_overview() {
Dries Buytaert's avatar
   
Dries Buytaert committed
306
  $header = array(t('Name'), t('Node types'), array('data' => t('Operations'), 'colspan' => 3));
Dries Buytaert's avatar
   
Dries Buytaert committed
307

Kjartan Mannes's avatar
Kjartan Mannes committed
308
  $vocabularies = taxonomy_get_vocabularies();
Dries Buytaert's avatar
   
Dries Buytaert committed
309

Kjartan Mannes's avatar
Kjartan Mannes committed
310
311
  foreach ($vocabularies as $vocabulary) {
    $links = array();
Dries Buytaert's avatar
   
Dries Buytaert committed
312
    $types = array();
Dries Buytaert's avatar
   
Dries Buytaert committed
313
314
    foreach(explode(',', $vocabulary->nodes) as $type) {
      $types[] = node_invoke($type, 'node_name');
Dries Buytaert's avatar
   
Dries Buytaert committed
315
    }
Dries Buytaert's avatar
   
Dries Buytaert committed
316
    $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 Mannes's avatar
Kjartan Mannes committed
317

Dries Buytaert's avatar
   
Dries Buytaert committed
318
    $tree = taxonomy_get_tree($vocabulary->vid);
Kjartan Mannes's avatar
Kjartan Mannes committed
319
    if ($tree) {
Dries Buytaert's avatar
   
Dries Buytaert committed
320
      unset($data);
Kjartan Mannes's avatar
Kjartan Mannes committed
321
      foreach ($tree as $term) {
Dries Buytaert's avatar
   
Dries Buytaert committed
322
        $data .= _taxonomy_depth($term->depth) .' '. $term->name .' ('. l(t('edit term'), "admin/taxonomy/edit/term/$term->tid") .')<br />';
Dries Buytaert's avatar
 
Dries Buytaert committed
323
      }
Dries Buytaert's avatar
   
Dries Buytaert committed
324
      $rows[] = array(array('data' => $data, 'colspan' => 5));
Dries Buytaert's avatar
 
Dries Buytaert committed
325
326
327
    }
  }

Dries Buytaert's avatar
   
Dries Buytaert committed
328
  return theme('table', $header, $rows);
Kjartan Mannes's avatar
Kjartan Mannes committed
329
330
}

Dries Buytaert's avatar
   
Dries Buytaert committed
331
332
333
/**
 * Generate a form element for selecting terms from a vocabulary.
 */
Dries Buytaert's avatar
   
Dries Buytaert committed
334
function taxonomy_form($vid, $value = 0, $help = NULL, $name = 'taxonomy') {
Dries Buytaert's avatar
   
Dries Buytaert committed
335
  $vocabulary = taxonomy_get_vocabulary($vid);
336
  $help = ($help) ? $help : $vocabulary->help;
Kjartan Mannes's avatar
Kjartan Mannes committed
337
338
339
340
  if ($vocabulary->required) {
    $blank = 0;
  }
  else {
Dries Buytaert's avatar
   
Dries Buytaert committed
341
    $blank = '<'. t('none') .'>';
Kjartan Mannes's avatar
Kjartan Mannes committed
342
  }
Dries Buytaert's avatar
   
Dries Buytaert committed
343

Dries Buytaert's avatar
   
Dries Buytaert committed
344
  return _taxonomy_term_select($vocabulary->name, $name, $value, $vid, $help, intval($vocabulary->multiple), $blank);
Kjartan Mannes's avatar
Kjartan Mannes committed
345
}
Dries Buytaert's avatar
 
Dries Buytaert committed
346

Dries Buytaert's avatar
   
Dries Buytaert committed
347
348
349
350
351
352
353
/**
 * 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 Mannes's avatar
Kjartan Mannes committed
354
  if ($type) {
Dries Buytaert's avatar
   
Dries Buytaert committed
355
    $result = db_query("SELECT * FROM {vocabulary} WHERE nodes LIKE '%%%s%%' ORDER BY weight, name", $type);
Kjartan Mannes's avatar
Kjartan Mannes committed
356
357
  }
  else {
Dries Buytaert's avatar
   
Dries Buytaert committed
358
    $result = db_query('SELECT * FROM {vocabulary} ORDER BY weight, name');
Kjartan Mannes's avatar
Kjartan Mannes committed
359
360
361
362
  }
  $vocabularies = array();
  while ($voc = db_fetch_object($result)) {
    $vocabularies[$voc->$key] = $voc;
Dries Buytaert's avatar
 
Dries Buytaert committed
363
  }
Dries Buytaert's avatar
   
Dries Buytaert committed
364

Kjartan Mannes's avatar
Kjartan Mannes committed
365
366
  return $vocabularies;
}
Dries Buytaert's avatar
 
Dries Buytaert committed
367

Dries Buytaert's avatar
   
Dries Buytaert committed
368
369
370
/**
 * Generate a form for selecting terms to associate with a node.
 */
Dries Buytaert's avatar
   
Dries Buytaert committed
371
function taxonomy_node_form($type, $node = '', $help = NULL, $name = 'taxonomy') {
Kjartan Mannes's avatar
Kjartan Mannes committed
372
373
374
  if (!$node->taxonomy) {
    if ($node->nid) {
      $terms = array_keys(taxonomy_node_get_terms($node->nid));
Kjartan Mannes's avatar
Kjartan Mannes committed
375
376
    }
    else {
Kjartan Mannes's avatar
Kjartan Mannes committed
377
      $terms = 0;
Dries Buytaert's avatar
 
Dries Buytaert committed
378
    }
Kjartan Mannes's avatar
Kjartan Mannes committed
379
380
381
382
  }
  else {
    $terms = $node->taxonomy;
  }
Dries Buytaert's avatar
 
Dries Buytaert committed
383

Dries Buytaert's avatar
   
Dries Buytaert committed
384
  $c = db_query("SELECT * FROM {vocabulary} WHERE nodes LIKE '%%%s%%' ORDER BY weight, name", $type);
Kjartan Mannes's avatar
Kjartan Mannes committed
385
  while ($vocabulary = db_fetch_object($c)) {
Dries Buytaert's avatar
   
Dries Buytaert committed
386
    $result[] = taxonomy_form($vocabulary->vid, $terms, $help, $name);
Dries Buytaert's avatar
 
Dries Buytaert committed
387
  }
Kjartan Mannes's avatar
Kjartan Mannes committed
388
389
  return $result ? $result : array();
}
Dries Buytaert's avatar
 
Dries Buytaert committed
390

Dries Buytaert's avatar
   
Dries Buytaert committed
391
392
393
/**
 * Determine whether a node mentions the name of a term.
 */
Kjartan Mannes's avatar
Kjartan Mannes committed
394
function taxonomy_node_has_term($nid, $tid) {
Dries Buytaert's avatar
   
Dries Buytaert committed
395
  $term_name = db_result(db_query('SELECT name FROM {term_data} WHERE tid = %d', $tid));
Dries Buytaert's avatar
 
Dries Buytaert committed
396

397
  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 Mannes's avatar
Kjartan Mannes committed
398
399
}

Dries Buytaert's avatar
   
Dries Buytaert committed
400
401
402
403
404
/**
 * 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 Mannes's avatar
Kjartan Mannes committed
405
406
407
  $terms = array();
  while ($term = db_fetch_object($result)) {
    $terms[$term->$key] = $term;
Dries Buytaert's avatar
 
Dries Buytaert committed
408
  }
Kjartan Mannes's avatar
Kjartan Mannes committed
409
410
411
  return $terms;
}

Dries Buytaert's avatar
   
Dries Buytaert committed
412
413
414
415
/**
 * Find all terms associated to the given node.
 */
function taxonomy_node_get_terms($nid, $key = 'tid') {
Kjartan Mannes's avatar
Kjartan Mannes committed
416
  static $terms;
Dries Buytaert's avatar
 
Dries Buytaert committed
417

Dries Buytaert's avatar
   
Dries Buytaert committed
418
  if (!isset($terms[$nid])) {
Dries Buytaert's avatar
   
Dries Buytaert committed
419
    $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 Mannes's avatar
Kjartan Mannes committed
420
    $terms[$nid] = array();
Dries Buytaert's avatar
 
Dries Buytaert committed
421
    while ($term = db_fetch_object($result)) {
Kjartan Mannes's avatar
Kjartan Mannes committed
422
      $terms[$nid][$term->$key] = $term;
Dries Buytaert's avatar
 
Dries Buytaert committed
423
424
    }
  }
Kjartan Mannes's avatar
Kjartan Mannes committed
425
426
  return $terms[$nid];
}
Dries Buytaert's avatar
 
Dries Buytaert committed
427

Dries Buytaert's avatar
   
Dries Buytaert committed
428
429
430
/**
 * Save term associations for a given node.
 */
Kjartan Mannes's avatar
Kjartan Mannes committed
431
432
function taxonomy_node_save($nid, $terms) {
  taxonomy_node_delete($nid);
Dries Buytaert's avatar
 
Dries Buytaert committed
433

Kjartan Mannes's avatar
Kjartan Mannes committed
434
  if ($terms) {
Dries Buytaert's avatar
   
Dries Buytaert committed
435
    foreach ($terms as $term) {
436
      if ($term) {
Dries Buytaert's avatar
   
Dries Buytaert committed
437
        db_query('INSERT INTO {term_node} (nid, tid) VALUES (%d, %d)', $nid, $term);
438
      }
Dries Buytaert's avatar
 
Dries Buytaert committed
439
440
    }
  }
Kjartan Mannes's avatar
Kjartan Mannes committed
441
}
Dries Buytaert's avatar
 
Dries Buytaert committed
442

Dries Buytaert's avatar
   
Dries Buytaert committed
443
444
445
/**
 * Remove associations of a node to its terms.
 */
Kjartan Mannes's avatar
Kjartan Mannes committed
446
function taxonomy_node_delete($nid) {
Dries Buytaert's avatar
   
Dries Buytaert committed
447
  db_query('DELETE FROM {term_node} WHERE nid = %d', $nid);
Kjartan Mannes's avatar
Kjartan Mannes committed
448
}
Dries Buytaert's avatar
 
Dries Buytaert committed
449

Dries Buytaert's avatar
   
Dries Buytaert committed
450
451
452
453
/**
 * Find all term objects related to a given term ID.
 */
function taxonomy_get_related($tid, $key = 'tid') {
Kjartan Mannes's avatar
Kjartan Mannes committed
454
  if ($tid) {
Dries Buytaert's avatar
   
Dries Buytaert committed
455
    $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 Mannes's avatar
Kjartan Mannes committed
456
457
458
    $related = array();
    while ($term = db_fetch_object($result)) {
      $related[$term->$key] = $term;
Dries Buytaert's avatar
 
Dries Buytaert committed
459
    }
Kjartan Mannes's avatar
Kjartan Mannes committed
460
    return $related;
Dries Buytaert's avatar
 
Dries Buytaert committed
461
  }
Kjartan Mannes's avatar
Kjartan Mannes committed
462
463
  else {
    return array();
Dries Buytaert's avatar
 
Dries Buytaert committed
464
  }
Kjartan Mannes's avatar
Kjartan Mannes committed
465
}
Dries Buytaert's avatar
 
Dries Buytaert committed
466

Dries Buytaert's avatar
   
Dries Buytaert committed
467
468
469
470
/**
 * Find all parents of a given term ID.
 */
function taxonomy_get_parents($tid, $key = 'tid') {
Kjartan Mannes's avatar
Kjartan Mannes committed
471
  if ($tid) {
Dries Buytaert's avatar
   
Dries Buytaert committed
472
    $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 Mannes's avatar
Kjartan Mannes committed
473
474
475
    $parents = array();
    while ($parent = db_fetch_object($result)) {
      $parents[$parent->$key] = $parent;
Dries Buytaert's avatar
   
Dries Buytaert committed
476
    }
Kjartan Mannes's avatar
Kjartan Mannes committed
477
    return $parents;
Dries Buytaert's avatar
 
Dries Buytaert committed
478
  }
Kjartan Mannes's avatar
Kjartan Mannes committed
479
480
481
482
  else {
    return array();
  }
}
Dries Buytaert's avatar
 
Dries Buytaert committed
483

Dries Buytaert's avatar
   
Dries Buytaert committed
484
485
486
487
/**
 * Find all ancestors of a given term ID.
 */
function taxonomy_get_parents_all($tid) {
Dries Buytaert's avatar
   
Dries Buytaert committed
488
489
490
491
492
493
494
495
496
497
498
499
  $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 Buytaert's avatar
   
Dries Buytaert committed
500
501
502
503
/**
 * Find all children of a term ID.
 */
function taxonomy_get_children($tid, $vid = 0, $key = 'tid') {
Kjartan Mannes's avatar
Kjartan Mannes committed
504
  if ($vid) {
Dries Buytaert's avatar
   
Dries Buytaert committed
505
    $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 Buytaert's avatar
 
Dries Buytaert committed
506
  }
Kjartan Mannes's avatar
Kjartan Mannes committed
507
  else {
Dries Buytaert's avatar
   
Dries Buytaert committed
508
    $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 Mannes's avatar
Kjartan Mannes committed
509
510
511
512
513
514
515
  }
  $children = array();
  while ($term = db_fetch_object($result)) {
    $children[$term->$key] = $term;
  }
  return $children;
}
Dries Buytaert's avatar
 
Dries Buytaert committed
516

Dries Buytaert's avatar
   
Dries Buytaert committed
517
518
519
520
521
522
523
524
525
526
527
528
529
/**
 * 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 Buytaert's avatar
   
Dries Buytaert committed
530
531
532
 * @param $max_depth
 *   The number of levels of the tree to return. Leave NULL to return all levels.
 *
Dries Buytaert's avatar
   
Dries Buytaert committed
533
534
535
536
537
 * @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 Buytaert's avatar
   
Dries Buytaert committed
538
  static $children, $parents, $terms;
Dries Buytaert's avatar
   
Dries Buytaert committed
539

Kjartan Mannes's avatar
Kjartan Mannes committed
540
  $depth++;
Dries Buytaert's avatar
   
Dries Buytaert committed
541

Dries Buytaert's avatar
   
Dries Buytaert committed
542
543
544
545
  // 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 Buytaert's avatar
   
Dries Buytaert committed
546

Dries Buytaert's avatar
   
Dries Buytaert committed
547
    $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 Buytaert's avatar
   
Dries Buytaert committed
548
    while ($term = db_fetch_object($result)) {
Dries Buytaert's avatar
   
Dries Buytaert committed
549
550
551
      $children[$vid][$term->parent][] = $term->tid;
      $parents[$vid][$term->tid][] = $term->parent;
      $terms[$vid][$term->tid] = $term;
Dries Buytaert's avatar
 
Dries Buytaert committed
552
553
    }
  }
Dries Buytaert's avatar
   
Dries Buytaert committed
554

Dries Buytaert's avatar
   
Dries Buytaert committed
555
  $max_depth = (is_null($max_depth)) ? count($children[$vid]) : $max_depth;
Dries Buytaert's avatar
   
Dries Buytaert committed
556
557
  if ($children[$vid][$parent]) {
    foreach ($children[$vid][$parent] as $child) {
Dries Buytaert's avatar
   
Dries Buytaert committed
558
      if ($max_depth > $depth) {
Dries Buytaert's avatar
   
Dries Buytaert committed
559
560
561
562
563
        $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 Buytaert's avatar
   
Dries Buytaert committed
564

Dries Buytaert's avatar
   
Dries Buytaert committed
565
        $tree = array_merge($tree, taxonomy_get_tree($vid, $child, $depth, $max_depth));
Dries Buytaert's avatar
   
Dries Buytaert committed
566
      }
Dries Buytaert's avatar
   
Dries Buytaert committed
567
    }
Kjartan Mannes's avatar
Kjartan Mannes committed
568
  }
Dries Buytaert's avatar
   
Dries Buytaert committed
569

Dries Buytaert's avatar
   
Dries Buytaert committed
570
  return $tree ? $tree : array();
Kjartan Mannes's avatar
Kjartan Mannes committed
571
}
Dries Buytaert's avatar
 
Dries Buytaert committed
572

Dries Buytaert's avatar
   
Dries Buytaert committed
573
574
575
/**
 * Return an array of synonyms of the given term ID.
 */
Kjartan Mannes's avatar
Kjartan Mannes committed
576
577
function taxonomy_get_synonyms($tid) {
  if ($tid) {
Dries Buytaert's avatar
   
Dries Buytaert committed
578
    $result = db_query('SELECT name FROM {term_synonym} WHERE tid = %d', $tid);
Kjartan Mannes's avatar
Kjartan Mannes committed
579
    while ($synonym = db_fetch_array($result)) {
Dries Buytaert's avatar
   
Dries Buytaert committed
580
      $synonyms[] = $synonym['name'];
Dries Buytaert's avatar
 
Dries Buytaert committed
581
    }
Kjartan Mannes's avatar
Kjartan Mannes committed
582
    return $synonyms ? $synonyms : array();
Dries Buytaert's avatar
 
Dries Buytaert committed
583
  }
Kjartan Mannes's avatar
Kjartan Mannes committed
584
585
  else {
    return array();
Dries Buytaert's avatar
   
Dries Buytaert committed
586
  }
Kjartan Mannes's avatar
Kjartan Mannes committed
587
}
Dries Buytaert's avatar
   
Dries Buytaert committed
588

Dries Buytaert's avatar
   
Dries Buytaert committed
589
590
591
592
593
/**
 * 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 Mannes's avatar
Kjartan Mannes committed
594
}
Dries Buytaert's avatar
   
Dries Buytaert committed
595

Dries Buytaert's avatar
   
Dries Buytaert committed
596
597
598
/**
 * Given a term id, count the number of published nodes in it.
 */
Dries Buytaert's avatar
   
Dries Buytaert committed
599
function taxonomy_term_count_nodes($tid, $type = 0) {
Kjartan Mannes's avatar
Kjartan Mannes committed
600
  static $count;
Dries Buytaert's avatar
   
Dries Buytaert committed
601

Dries Buytaert's avatar
   
Dries Buytaert committed
602
603
604
  if (!isset($count[$type])) {
    // $type == 0 always evaluates true is $type is a string
    if (is_numeric($type)) {
Dries Buytaert's avatar
   
Dries Buytaert committed
605
      $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 Buytaert's avatar
   
Dries Buytaert committed
606
607
    }
    else {
Dries Buytaert's avatar
   
Dries Buytaert committed
608
      $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 Buytaert's avatar
   
Dries Buytaert committed
609
    }
Kjartan Mannes's avatar
Kjartan Mannes committed
610
    while ($term = db_fetch_object($result)) {
Dries Buytaert's avatar
   
Dries Buytaert committed
611
      $count[$type][$term->tid] = $term->c;
Dries Buytaert's avatar
   
Dries Buytaert committed
612
613
614
    }
  }

Kjartan Mannes's avatar
Kjartan Mannes committed
615
  foreach (_taxonomy_term_children($tid) as $c) {
Dries Buytaert's avatar
   
Dries Buytaert committed
616
    $children_count += taxonomy_term_count_nodes($c, $type);
Kjartan Mannes's avatar
Kjartan Mannes committed
617
  }
Dries Buytaert's avatar
   
Dries Buytaert committed
618
  return $count[$type][$tid] + $children_count;
Kjartan Mannes's avatar
Kjartan Mannes committed
619
620
}

Dries Buytaert's avatar
   
Dries Buytaert committed
621
622
623
/**
 * Helper for taxonomy_term_count_nodes().
 */
Kjartan Mannes's avatar
Kjartan Mannes committed
624
625
function _taxonomy_term_children($tid) {
  static $children;
Dries Buytaert's avatar
   
Dries Buytaert committed
626

Dries Buytaert's avatar
   
Dries Buytaert committed
627
  if (!isset($children)) {
Dries Buytaert's avatar
   
Dries Buytaert committed
628
    $result = db_query('SELECT tid, parent FROM {term_hierarchy}');
Kjartan Mannes's avatar
Kjartan Mannes committed
629
630
    while ($term = db_fetch_object($result)) {
      $children[$term->parent][] = $term->tid;
Dries Buytaert's avatar
   
Dries Buytaert committed
631
    }
Dries Buytaert's avatar
 
Dries Buytaert committed
632
  }
Kjartan Mannes's avatar
Kjartan Mannes committed
633
634
  return $children[$tid] ? $children[$tid] : array();
}
Dries Buytaert's avatar
 
Dries Buytaert committed
635

Dries Buytaert's avatar
   
Dries Buytaert committed
636
/**
Dries Buytaert's avatar
   
Dries Buytaert committed
637
638
639
640
641
642
643
 * 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 Buytaert's avatar
   
Dries Buytaert committed
644
 *
Dries Buytaert's avatar
   
Dries Buytaert committed
645
646
 * @return
 *   An array of matching vocabulary objects.
Dries Buytaert's avatar
   
Dries Buytaert committed
647
648
 */
function taxonomy_get_vocabulary_by_name($name) {
Dries Buytaert's avatar
   
Dries Buytaert committed
649
  $db_result = db_query("SELECT * FROM {vocabulary} WHERE LOWER('%s') LIKE LOWER(name)", trim($name));
Dries Buytaert's avatar
   
Dries Buytaert committed
650
651
652
653
654
655
656
657
658
  $result = array();
  while ($vocabulary = db_fetch_object($db_result)) {
    $result[] = $vocabulary;
  }

  return $result;
}

/**
Dries Buytaert's avatar
   
Dries Buytaert committed
659
 * Try to map a string to an existing term, as for glossary use.
Dries Buytaert's avatar
   
Dries Buytaert committed
660
 *
Dries Buytaert's avatar
   
Dries Buytaert committed
661
662
663
664
665
666
667
668
 * 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 Buytaert's avatar
   
Dries Buytaert committed
669
670
 */
function taxonomy_get_term_by_name($name) {
Dries Buytaert's avatar
   
Dries Buytaert committed
671
  $db_result = db_query("SELECT * FROM {term_data} WHERE LOWER('%s') LIKE LOWER(name)", trim($name));
Dries Buytaert's avatar
   
Dries Buytaert committed
672
673
674
675
676
677
678
679
  $result = array();
  while ($term = db_fetch_object($db_result)) {
    $result[] = $term;
  }

  return $result;
}

Dries Buytaert's avatar
   
Dries Buytaert committed
680
681
682
/**
 * Return the vocabulary object matching a vocabulary ID.
 */
Kjartan Mannes's avatar
Kjartan Mannes committed
683
function taxonomy_get_vocabulary($vid) {
Dries Buytaert's avatar
   
Dries Buytaert committed
684
  return db_fetch_object(db_query('SELECT * FROM {vocabulary} WHERE vid = %d', $vid));
Kjartan Mannes's avatar
Kjartan Mannes committed
685
}
Dries Buytaert's avatar
 
Dries Buytaert committed
686

Dries Buytaert's avatar
   
Dries Buytaert committed
687
688
689
/**
 * Return the term object matching a term ID.
 */
Kjartan Mannes's avatar
Kjartan Mannes committed
690
691
function taxonomy_get_term($tid) {
  // simple cache using a static var?
Dries Buytaert's avatar
   
Dries Buytaert committed
692
  return db_fetch_object(db_query('SELECT * FROM {term_data} WHERE tid = %d', $tid));
Kjartan Mannes's avatar
Kjartan Mannes committed
693
}
Dries Buytaert's avatar
 
Dries Buytaert committed
694

Kjartan Mannes's avatar
Kjartan Mannes committed
695
function _taxonomy_term_select($title, $name, $value, $vocabulary_id, $description, $multiple, $blank, $exclude = array()) {
Dries Buytaert's avatar
   
Dries Buytaert committed
696
  $tree = taxonomy_get_tree($vocabulary_id);
Dries Buytaert's avatar
Dries Buytaert committed
697
698
699
  if ($blank) {
    $options[] = array('tid' => 0, 'name' => $blank);
  }
Kjartan Mannes's avatar
Kjartan Mannes committed
700
701
702
  if ($tree) {
    foreach ($tree as $term) {
      if (!in_array($term->tid, $exclude)) {
Dries Buytaert's avatar
   
Dries Buytaert committed
703
        $options[] = array('tid' => $term->tid, 'name' => _taxonomy_depth($term->depth, '-').$term->name);
Dries Buytaert's avatar
 
Dries Buytaert committed
704
705
      }
    }
Kjartan Mannes's avatar
Kjartan Mannes committed
706
707
708
709
710
    if (!$blank && !$value) {
      // required but without a predefined value, so set first as predefined
      $value = $tree[0]->tid;
    }
  }
Dries Buytaert's avatar
 
Dries Buytaert committed
711

Kjartan Mannes's avatar
Kjartan Mannes committed
712
  if (count($options) > 0) {
Dries Buytaert's avatar
   
Dries Buytaert committed
713
    foreach ($options as $option) {
Dries Buytaert's avatar
   
Dries Buytaert committed
714
      $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 Mannes's avatar
Kjartan Mannes committed
715
    }
Dries Buytaert's avatar
 
Dries Buytaert committed
716

Dries Buytaert's avatar
   
Dries Buytaert committed
717
    $size = min(12, count($options));
Dries Buytaert's avatar
 
Dries Buytaert committed
718

Dries Buytaert's avatar
   
Dries Buytaert committed
719
    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 Buytaert's avatar
 
Dries Buytaert committed
720
  }
Kjartan Mannes's avatar
Kjartan Mannes committed
721
}
Dries Buytaert's avatar
 
Dries Buytaert committed
722

Kjartan Mannes's avatar
Kjartan Mannes committed
723
724
725
function _taxonomy_depth($depth, $graphic = '--') {
  for ($n = 0; $n < $depth; $n++) {
    $result .= $graphic;
Dries Buytaert's avatar
 
Dries Buytaert committed
726
  }
Kjartan Mannes's avatar
Kjartan Mannes committed
727
728
  return $result;
}
Dries Buytaert's avatar
 
Dries Buytaert committed
729

Dries Buytaert's avatar
   
Dries Buytaert committed
730
function _taxonomy_prepare_update($data) {
Kjartan Mannes's avatar
Kjartan Mannes committed
731
  foreach ($data as $key => $value) {
732
    $q[] = "$key = '". str_replace('%', '%%', check_query($value)) ."'";
Dries Buytaert's avatar
 
Dries Buytaert committed
733
  }
Dries Buytaert's avatar
   
Dries Buytaert committed
734
  $result = implode(', ', $q);
Kjartan Mannes's avatar
Kjartan Mannes committed
735
736
  return $result;
}
Dries Buytaert's avatar
 
Dries Buytaert committed
737

Dries Buytaert's avatar
   
Dries Buytaert committed
738
function _taxonomy_prepare_insert($data, $stage) {
Kjartan Mannes's avatar
Kjartan Mannes committed
739
  if ($stage == 1) {
Dries Buytaert's avatar
   
Dries Buytaert committed
740
    $result = implode(', ', array_keys($data));
Kjartan Mannes's avatar
Kjartan Mannes committed
741
742
743
  }
  else {
    foreach (array_values($data) as $value) {
744
      $q[] = "'". str_replace('%', '%%', check_query($value)) ."'";
Dries Buytaert's avatar
 
Dries Buytaert committed
745
    }
Dries Buytaert's avatar
   
Dries Buytaert committed
746
    $result = implode(', ', $q);
Dries Buytaert's avatar
 
Dries Buytaert committed
747
  }
Kjartan Mannes's avatar
Kjartan Mannes committed
748
749
  return "($result)";
}
Dries Buytaert's avatar
   
Dries Buytaert committed
750

Dries Buytaert's avatar
   
Dries Buytaert committed
751
752
753
/**
 * Finds all nodes that match selected taxonomy conditions.
 *
Dries Buytaert's avatar
   
Dries Buytaert committed
754
755
756
757
758
759
760
 * @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 Buytaert's avatar
   
Dries Buytaert committed
761
762
763
764
765
766
 * @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 Buytaert's avatar
   
Dries Buytaert committed
767
768
769
770
771
772
773
774
775
776
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
777
      $descendant_tids[] = array_merge(array($tid), array_map('_taxonomy_get_tid_from_term', $tree));
778
    }
Dries Buytaert's avatar
   
Dries Buytaert committed
779

Dries Buytaert's avatar
   
Dries Buytaert committed
780
781
782
783
784
785
786
787
788
789
790
791
792
793
    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;
794
    }
Dries Buytaert's avatar
   
Dries Buytaert committed
795

796
    if ($pager) {
Dries Buytaert's avatar
   
Dries Buytaert committed
797
      $result = pager_query($sql, variable_get('default_nodes_main', 10) , 0, $sql_count);
798
799
800
801
    }
    else {
      $result = db_query_range($sql, 0, 15);
    }
Dries Buytaert's avatar
   
Dries Buytaert committed
802
803
804
805
806
  }

  return $result;
}

Dries Buytaert's avatar
   
Dries Buytaert committed
807
808
809
/**
 * 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 Buytaert's avatar
   
Dries Buytaert committed
810
811
*/
function taxonomy_render_nodes($result) {
812
813
814
815
816
817
818
819
  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 Buytaert's avatar
   
Dries Buytaert committed
820
  }
Dries Buytaert's avatar
   
Dries Buytaert committed
821
  return $output;
Dries Buytaert's avatar
   
Dries Buytaert committed
822
823
}

Dries Buytaert's avatar
   
Dries Buytaert committed
824
825
826
/**
 * Implementation of hook_nodeapi().
 */
Dries Buytaert's avatar
   
Dries Buytaert committed
827
828
function taxonomy_nodeapi($node, $op, $arg = 0) {
  switch ($op) {
Dries Buytaert's avatar
   
Dries Buytaert committed
829
    case 'insert':
Dries Buytaert's avatar
   
Dries Buytaert committed
830
831
      taxonomy_node_save($node->nid, $node->taxonomy);
      break;
Dries Buytaert's avatar
   
Dries Buytaert committed
832
    case 'update':
Dries Buytaert's avatar
   
Dries Buytaert committed
833
834
      taxonomy_node_save($node->nid, $node->taxonomy);
      break;
Dries Buytaert's avatar
   
Dries Buytaert committed
835
    case 'delete':
Dries Buytaert's avatar
   
Dries Buytaert committed
836
837
838
839
840
      taxonomy_node_delete($node->nid);
      break;
  }
}

Dries Buytaert's avatar
   
Dries Buytaert committed
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
/**
 * 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 Buytaert's avatar
   
Dries Buytaert committed
857

Dries Buytaert's avatar
   
Dries Buytaert committed
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
  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 Buytaert's avatar
   
Dries Buytaert committed
897
  }
Kjartan Mannes's avatar
Kjartan Mannes committed
898
}
Dries Buytaert's avatar
   
Dries Buytaert committed
899

Dries Buytaert's avatar
   
Dries Buytaert committed
900
901
902
/**
 * Menu callback; dispatches to the proper taxonomy administration function.
 */
Kjartan Mannes's avatar
Kjartan Mannes committed
903
function taxonomy_admin() {
Dries Buytaert's avatar
   
Dries Buytaert committed
904
905
  $op = $_POST['op'];
  $edit = $_POST['edit'];
Kjartan Mannes's avatar
Kjartan Mannes committed
906

Dries Buytaert's avatar
   
Dries Buytaert committed
907
908
909
  if (empty($op)) {
    $op = arg(2);
  }
Dries Buytaert's avatar
   
Dries Buytaert committed
910

Dries Buytaert's avatar
   
Dries Buytaert committed
911
  switch ($op) {
Dries Buytaert's avatar
   
Dries Buytaert committed
912
913
    case 'add':
      if (arg(3) == 'vocabulary') {
914
        $output = taxonomy_form_vocabulary();
Dries Buytaert's avatar
   
Dries Buytaert committed
915
      }