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

4
function taxonomy_system($field){
Kjartan's avatar
Kjartan committed
5
  $system["description"] = t("Enables the organization of content into categories.");
6 7 8
  return $system[$field];
}

Kjartan's avatar
Kjartan committed
9 10
function taxonomy_feed() {
  global $id, $or, $and, $type;
Dries's avatar
 
Dries committed
11

Kjartan's avatar
Kjartan committed
12 13 14 15 16 17 18
  if ($type == "voc") {
    //TODO - vocabulary feed. How to represent an outline in XML?
  }
  else {
    if ($or) {
      foreach ((explode(",", $or)) as $t) {
        $terms[] = "'". check_query($t) ."'";
Dries's avatar
 
Dries committed
19
      }
Kjartan's avatar
Kjartan committed
20 21 22 23 24 25
      $result = db_query("SELECT DISTINCT(n.nid), type FROM node n LEFT JOIN term_node r ON n.nid = r.nid WHERE tid IN (". implode(",", $terms) .") AND status = '1' ORDER BY static DESC, created DESC LIMIT 15");
      $term = taxonomy_get_term($or);
    }
    else if ($and) {
      foreach ((explode(",", $and)) as $t) {
        $terms[] = "'". check_query($t) ."'";
Dries's avatar
 
Dries committed
26
      }
27
      $result = db_query("SELECT n.nid, type, count(*) AS c FROM node n LEFT JOIN term_node r ON n.nid = r.nid WHERE tid IN (". implode(",", $terms) .") AND status = '1' GROUP BY n.nid, n.type HAVING c = ". count($terms) ." ORDER BY static DESC, created DESC LIMIT 15");
Kjartan's avatar
Kjartan committed
28 29 30 31 32
      $term = taxonomy_get_term($and);
    }
    else {
      return node_feed();
    }
Dries's avatar
 
Dries committed
33

Kjartan's avatar
Kjartan committed
34 35 36
    $channel["title"] = variable_get("site_name", "drupal") ." - ". $term->name;
    $channel["link"] = path_uri() ."index.php?or=$or";
    $channel["description"] = $term->description;
Dries's avatar
 
Dries committed
37

Kjartan's avatar
Kjartan committed
38
    node_feed($result, $channel);
Dries's avatar
 
Dries committed
39
  }
Kjartan's avatar
Kjartan committed
40
}
Dries's avatar
 
Dries committed
41

Kjartan's avatar
Kjartan committed
42 43 44
function taxonomy_perm() {
  return array("administer taxonomy");
}
Dries's avatar
 
Dries committed
45

Kjartan's avatar
Kjartan committed
46 47 48
function taxonomy_link($type) {
  if ($type == "admin" && user_access("administer taxonomy")) {
    $links[] = la(t("taxonomy"), array("mod" => "taxonomy"));
Dries's avatar
 
Dries committed
49 50
  }

Kjartan's avatar
Kjartan committed
51 52 53
  return $links ? $links : array();
}

Dries's avatar
 
Dries committed
54 55 56 57
/*
** admin pages (form, save, overview)
*/

Kjartan's avatar
Kjartan committed
58 59 60 61
function taxonomy_form_vocabulary($edit = array()) {
  foreach (module_list() as $name) {
    if (module_hook($name, "node")) {
      $nodetypes[$name] = $name;
Dries's avatar
 
Dries committed
62
    }
Kjartan's avatar
Kjartan committed
63
  }
Dries's avatar
 
Dries committed
64

Dries's avatar
 
Dries committed
65 66 67 68 69 70 71
  $form .= form_textfield(t("Vocabulary name"), "name", $edit["name"], 50, 64, t("Required") . ". " . t("The name for this vocabulary.  Example: 'Topic'") . ".");
  $form .= form_textarea(t("Description"), "description", $edit["description"], 60, 5, t("Optional") . ". " . t("Description of the vocabulary, can be used by modules."));
  $form .= form_select(t("Types"), "types", explode(",", $edit["types"]), $nodetypes, t("Required") . ". " . t("A list of node types you want to associate this vocabulary with."), "", 1);
  $form .= form_checkbox(t("Related terms"), "relations", 1, $edit["relations"], t("Optional") . ". " . t("Allows ". la("related terms", array("mod" => "taxonomy", "op" => "help"), "relatedterms") ." in this vocabulary."));
  $form .= form_select(t("Hierarchy"), "hierarchy", $edit["hierarchy"], array(t("Disabled"), t("Single"), t("Multiple")), t("Optional") . ". ". t("Allows ". la("a tree-like hierarchy", array("mod" => "taxonomy", "op" => "help"), "hierarchy") ." between terms of this vocabulary."), "", 0);
  $form .= form_checkbox(t("Multiple select"), "multiple", 1, $edit["multiple"], t("Optional") . ". " . t("Allows nodes to have more than one term in this vocabulary."));
  $form .= form_checkbox(t("Required"), "required", 1, $edit["required"], t("If enabled every node <b>must</b> have at least one term in this vocabulary"));
Dries's avatar
 
Dries committed
72
  $form .= form_weight(t("Weight"), "weight", $edit["weight"], 10, t("Optional. In listings, the heavier vocabularies will sink and the lighter vocabularies will be positioned nearer the top."));
Dries's avatar
 
Dries committed
73
  $form .= form_submit(t("Submit"));
Dries's avatar
 
Dries committed
74

Kjartan's avatar
Kjartan committed
75
  if ($edit["vid"]) {
Dries's avatar
 
Dries committed
76
    $form .= form_submit(t("Delete"));
Kjartan's avatar
Kjartan committed
77
    $form .= form_hidden("vid", $edit["vid"]);
Dries's avatar
 
Dries committed
78 79
  }

Kjartan's avatar
Kjartan committed
80 81
  return form($form);
}
Kjartan's avatar
Kjartan committed
82

Kjartan's avatar
Kjartan committed
83 84 85 86
function taxonomy_save_vocabulary($edit) {
  $data = array("name" => $edit["name"], "types" => @implode(",", $edit["types"]), "description" => $edit["description"], "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
87
    db_query("UPDATE vocabulary SET ". _prepare_update($data) ." WHERE vid = '". check_query($edit["vid"]) ."'");
Dries's avatar
 
Dries committed
88
    return t("update vocabulary '%name'.", array("%name" => $edit["name"]));
Dries's avatar
 
Dries committed
89
  }
Kjartan's avatar
Kjartan committed
90
  else if ($edit["vid"]) {
Dries's avatar
 
Dries committed
91
    return taxonomy_del_vocabulary($edit["vid"]);
Kjartan's avatar
Kjartan committed
92 93 94
  }
  else {
    db_query("INSERT INTO vocabulary ". _prepare_insert($data, 1) ." VALUES ". _prepare_insert($data, 2));
Dries's avatar
 
Dries committed
95
    return t("created new vocabulary '%name'.", array("%name" => $edit["name"]));
Kjartan's avatar
Kjartan committed
96 97
  }
}
Dries's avatar
 
Dries committed
98

Kjartan's avatar
Kjartan committed
99
function taxonomy_del_vocabulary($vid) {
Dries's avatar
 
Dries committed
100 101
  $vocabulary = taxonomy_get_vocabulary($vid);

Dries's avatar
 
Dries committed
102 103
  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
104 105
  while ($term = db_fetch_object($result)) {
    taxonomy_del_term($term->tid);
Dries's avatar
 
Dries committed
106
  }
Dries's avatar
 
Dries committed
107 108 109 110 111 112 113 114 115 116 117 118 119 120

  return t("deleted vocabulary '%name'.", array("%name" => $vocabulary->name));
}

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

  $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"));

  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
121
}
Dries's avatar
 
Dries committed
122

Kjartan's avatar
Kjartan committed
123 124 125 126 127 128
function taxonomy_form_term($edit = array()) {
  global $vocabulary_id;
  if (!$vocabulary_id) {
    $vocabulary_id = $edit["vid"];
  }
  $vocabulary = taxonomy_get_vocabulary($vocabulary_id);
Dries's avatar
 
Dries committed
129 130
  $form = form_textfield(t("Term name"), "name", $edit["name"], 50, 64, t("Required") . ". " . t("The name for this term.  Example: 'Linux'."));
  $form .= form_textarea(t("Description"), "description", $edit["description"], 60, 5, t("Optional") . ". " . t("A description of the term."));
Dries's avatar
 
Dries committed
131

Kjartan's avatar
Kjartan committed
132
  if ($vocabulary->relations) {
Dries's avatar
 
Dries committed
133
    $form .= _taxonomy_term_select(t("Related terms"), "relations", array_keys(taxonomy_get_related($edit["tid"])), $vocabulary_id, t("Optional") . ". ", 1, "<" . t("none") . ">", array($edit["tid"]));
Kjartan's avatar
Kjartan committed
134
  }
Dries's avatar
 
Dries committed
135 136


Kjartan's avatar
Kjartan committed
137 138
  if ($vocabulary->hierarchy) {
    $parent = array_keys(taxonomy_get_parents($edit["tid"]));
Dries's avatar
 
Dries committed
139
    $children = taxonomy_get_tree($vocabulary_id, $edit["tid"]);
Kjartan's avatar
Kjartan committed
140 141 142 143
    // you can't be son of yourself or your children
    $exclude = array_keys($children);
    $exclude[] = $edit["tid"];
    if ($vocabulary->hierarchy == 1) {
Dries's avatar
 
Dries committed
144
      $form .= _taxonomy_term_select(t("Parent"), "parent", $parent, $vocabulary_id, t("Required") . ". " . la(t("Parent term"), array("mod" => "taxonomy", "op" => "help"), "parent") .".", 0, "<" . t("root") . ">", $exclude);
Dries's avatar
 
Dries committed
145
    }
Kjartan's avatar
Kjartan committed
146
    elseif ($vocabulary->hierarchy == 2) {
Dries's avatar
 
Dries committed
147
      $form .= _taxonomy_term_select(t("Parents"), "parent", $parent, $vocabulary_id, t("Required") . ". ". la(t("Parent terms"), array("mod" => "taxonomy", "op" => "help"), "parent") .".", 1, "<" . t("root") . ">", $exclude);
Dries's avatar
 
Dries committed
148
    }
Kjartan's avatar
Kjartan committed
149
  }
Dries's avatar
 
Dries committed
150

Dries's avatar
 
Dries committed
151 152
  $form .= form_textarea(t("Synonyms"), "synonyms", implode("\n", taxonomy_get_synonyms($edit["tid"])), 30, 5, t("Optional") . ". ". t(la("Synonyms", array("mod" => "taxonomy", "op" => "help"), "synonyms") ." of this term, one synonym per line."));
  $form .= form_weight(t("Weight"), "weight", $edit["weight"], 10, t("Optional. In listings, the heavier terms will sink and the lighter terms will be positioned nearer the top."));
Kjartan's avatar
Kjartan committed
153
  $form .= form_hidden("vid", $vocabulary->vid);
Dries's avatar
 
Dries committed
154
  $form .= form_submit(t("Submit"));
Kjartan's avatar
Kjartan committed
155 156

  if ($edit["tid"]) {
Dries's avatar
 
Dries committed
157
    $form .= form_submit(t("Delete"));
Kjartan's avatar
Kjartan committed
158
    $form .= form_hidden("tid", $edit["tid"]);
Dries's avatar
 
Dries committed
159 160
  }

Kjartan's avatar
Kjartan committed
161 162
  return form($form);
}
Dries's avatar
 
Dries committed
163

Kjartan's avatar
Kjartan committed
164 165 166
function taxonomy_save_term($edit) {
 if ($edit["tid"] && $edit["name"]) {
    $data = array("name" => $edit["name"], "description" => $edit["description"], "weight" => $edit["weight"]);
Dries's avatar
 
Dries committed
167

Dries's avatar
 
Dries committed
168
    db_query("UPDATE term_data SET ". _prepare_update($data) ." WHERE tid = '%d'", $edit["tid"]);
Dries's avatar
 
Dries committed
169
    $message = t("Term <b>%a</b> updated.", array("%a" => $edit["name"]));
Kjartan's avatar
Kjartan committed
170 171
  }
  else if ($edit["tid"]) {
Dries's avatar
 
Dries committed
172
    return taxonomy_del_term($edit["tid"]);
Kjartan's avatar
Kjartan committed
173 174
  }
  else {
Dries's avatar
 
Dries committed
175
    $edit["tid"] = db_next_id("term_data");
Kjartan's avatar
Kjartan committed
176 177
    $data = array("tid" => $edit["tid"], "name" => $edit["name"], "description" => $edit["description"], "vid" => $edit["vid"], "weight" => $edit["weight"]);
    db_query("INSERT INTO term_data ". _prepare_insert($data, 1) ." VALUES ". _prepare_insert($data, 2));
Dries's avatar
 
Dries committed
178 179

    $message = t("created new term '%name'.", array("%name" => $edit["name"]));
Kjartan's avatar
Kjartan committed
180
  }
Dries's avatar
 
Dries committed
181

Kjartan's avatar
Kjartan committed
182
  // relations (seem very powerful, but I have to understand it completely)
Dries's avatar
 
Dries committed
183
  db_query("DELETE FROM term_relation WHERE tid1 = '%d' OR tid2 = '%d'", $edit["tid"], $edit["tid"]);
Kjartan's avatar
Kjartan committed
184 185 186
  if ($edit["relations"]) {
    foreach ($edit["relations"] as $related_id) {
      if ($related_id != 0) {
Dries's avatar
 
Dries committed
187
        db_query("INSERT INTO term_relation (tid1, tid2) VALUES ('%d', '%d')", $edit["tid"], $related_id);
Dries's avatar
 
Dries committed
188
      }
Kjartan's avatar
Kjartan committed
189
    }
Kjartan's avatar
Kjartan committed
190
  }
Dries's avatar
 
Dries committed
191

Kjartan's avatar
Kjartan committed
192
  // hierarchy
Dries's avatar
 
Dries committed
193
  db_query("DELETE FROM term_hierarchy WHERE tid = '%d'", $edit["tid"]);
Kjartan's avatar
Kjartan committed
194 195 196 197 198
  if (!isset($edit["parent"])) {
    $edit["parent"] = 0;
  }
  if (is_array($edit["parent"])) {
    foreach ($edit["parent"] as $parent) {
Dries's avatar
 
Dries committed
199
      db_query("INSERT INTO term_hierarchy (tid, parent) VALUES ('%d', '%d')", $edit["tid"], $parent);
Dries's avatar
 
Dries committed
200
    }
Kjartan's avatar
Kjartan committed
201 202
  }
  else {
Dries's avatar
 
Dries committed
203
    db_query("INSERT INTO term_hierarchy (tid, parent) VALUES ('%d', '%d')", $edit["tid"], $edit["parent"][0]);
Dries's avatar
 
Dries committed
204 205
  }

Kjartan's avatar
Kjartan committed
206
  // synonyms (very cool idea indeed)
Dries's avatar
 
Dries committed
207
  db_query("DELETE FROM term_synonym WHERE tid = '%d'", $edit["tid"]);
Kjartan's avatar
Kjartan committed
208
  if ($edit["synonyms"]) {
Dries's avatar
 
Dries committed
209 210 211 212
    foreach (explode ("\n", str_replace("\r", "", $edit["synonyms"])) as $synonym) {
      if ($synonym) {
        db_query("INSERT INTO term_synonym (tid, name) VALUES ('%d', '%s')", $edit["tid"], chop($synonym));
      }
Kjartan's avatar
Kjartan committed
213
    }
Dries's avatar
 
Dries committed
214
  }
Dries's avatar
 
Dries committed
215 216

  return $message;
Kjartan's avatar
Kjartan committed
217
}
Dries's avatar
 
Dries committed
218

Kjartan's avatar
Kjartan committed
219
function taxonomy_del_term($tid) {
Dries's avatar
 
Dries committed
220 221
  $term = taxonomy_get_term($tid);

Dries's avatar
 
Dries committed
222 223 224 225 226
  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
227 228 229 230 231 232 233 234 235 236 237 238 239 240

  return t("deleted term '%name'.", array("%name" => $term->name));
}

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

  $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"));

  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
241
}
Dries's avatar
 
Dries committed
242

Kjartan's avatar
Kjartan committed
243 244
function taxonomy_overview() {
  global $tree;
Dries's avatar
 
Dries committed
245

Dries's avatar
 
Dries committed
246
  $output .= "<h3>" . t("Vocabularies overview") . "</h3>";
Kjartan's avatar
Kjartan committed
247
  $output .= "<table border=\"1\" cellpadding=\"2\" cellspacing=\"2\">\n";
Dries's avatar
 
Dries committed
248
  $output .= " <tr><th>" . t("name") . "</th><th>" . t("node types") . "</th><th>" . t("operations") . "</th></tr>\n";
Dries's avatar
 
Dries committed
249

Kjartan's avatar
Kjartan committed
250 251 252 253 254 255
  $vocabularies = taxonomy_get_vocabularies();
  foreach ($vocabularies as $vocabulary) {
    $links = array();
    $links[] = la(t("edit vocabulary"), array("mod" => "taxonomy", "type" => "vocabulary", "op" => "edit", "id" => $vocabulary->vid));
    $links[] = la(t("add term"), array("mod" => "taxonomy", "op" => "add", "type" => "leaf", "vocabulary_id" => $vocabulary->vid));
    $links[] = la(t("preview form"), array("mod" => "taxonomy", "type" => "vocabulary", "op" => "preview", "id" => $vocabulary->vid));
Dries's avatar
 
Dries committed
256

Dries's avatar
 
Dries committed
257
    $output .= " <tr><td>". check_output($vocabulary->name) ."</td><td align=\"center\">". check_output($vocabulary->types) ."</td><td>". implode(" | ", $links) ."</td></tr>\n";
Kjartan's avatar
Kjartan committed
258

Dries's avatar
 
Dries committed
259
    $tree = taxonomy_get_tree($vocabulary->vid);
Kjartan's avatar
Kjartan committed
260 261 262 263
    if ($tree) {
      $output .= "<tr><td colspan=\"3\"><table><tr><td>";
      foreach ($tree as $term) {
        $output .= "<tr><td>". la(_taxonomy_depth($term->depth) . check_output($term->name), array("mod" => "taxonomy", "op" => "edit", "type" => "term", "id" => check_output($term->tid))) ."</td></tr>";
Dries's avatar
 
Dries committed
264
      }
Kjartan's avatar
Kjartan committed
265
      $output .= "</td></tr></table></td></tr>\n";
Dries's avatar
 
Dries committed
266 267
    }
  }
Kjartan's avatar
Kjartan committed
268
  $output .= "</table>\n";
Dries's avatar
 
Dries committed
269

Kjartan's avatar
Kjartan committed
270 271 272 273 274 275 276 277 278 279 280
  return $output;
}

function taxonomy_form($vocabulary_id, $value = 0) {
  $vocabulary = taxonomy_get_vocabulary($vocabulary_id);
  if ($vocabulary->required) {
    $verb = "must";
    $blank = 0;
  }
  else {
    $verb = "can";
Dries's avatar
 
Dries committed
281
    $blank = "<" . t("none") . ">";
Kjartan's avatar
Kjartan committed
282
  }
Dries's avatar
 
Dries committed
283

Kjartan's avatar
Kjartan committed
284
  if ($vocabulary->multiple) {
Dries's avatar
 
Dries committed
285
    $description = t("You $verb choose one or more terms for this node.");
Kjartan's avatar
Kjartan committed
286
    $multiple = 1;
Dries's avatar
 
Dries committed
287
  }
Kjartan's avatar
Kjartan committed
288
  else {
Dries's avatar
 
Dries committed
289
    $description = t("You $verb choose one term for this node.");
Kjartan's avatar
Kjartan committed
290 291 292 293
    $multiple = 0;
  }
  return _taxonomy_term_select($vocabulary->name, "taxonomy", $value, $vocabulary_id, $description, $multiple, $blank);
}
Dries's avatar
 
Dries committed
294 295 296 297 298

/*
** API functions
*/

Kjartan's avatar
Kjartan committed
299 300 301 302 303 304 305 306 307 308 309
// return array of vocabularies, as objects
function taxonomy_get_vocabularies($type = '', $key = "vid") {
  if ($type) {
    $result = db_query("SELECT * FROM vocabulary WHERE types LIKE '%%%s%%' ORDER BY weight, name", $type);
  }
  else {
    $result = db_query("SELECT * FROM vocabulary ORDER BY weight, name");
  }
  $vocabularies = array();
  while ($voc = db_fetch_object($result)) {
    $vocabularies[$voc->$key] = $voc;
Dries's avatar
 
Dries committed
310
  }
Kjartan's avatar
Kjartan committed
311 312
  return $vocabularies;
}
Dries's avatar
 
Dries committed
313

Kjartan's avatar
Kjartan committed
314 315 316 317 318
// return form with current term
function taxonomy_node_form($type, $node = '') {
  if (!$node->taxonomy) {
    if ($node->nid) {
      $terms = array_keys(taxonomy_node_get_terms($node->nid));
Kjartan's avatar
Kjartan committed
319 320
    }
    else {
Kjartan's avatar
Kjartan committed
321
      $terms = 0;
Dries's avatar
 
Dries committed
322
    }
Kjartan's avatar
Kjartan committed
323 324 325 326
  }
  else {
    $terms = $node->taxonomy;
  }
Dries's avatar
 
Dries committed
327

Kjartan's avatar
Kjartan committed
328 329 330
  $c = db_query("SELECT * FROM vocabulary WHERE types LIKE '%%%s%%' ORDER BY weight, name", $type);
  while ($vocabulary = db_fetch_object($c)) {
    $result[] .= taxonomy_form($vocabulary->vid, $terms);
Dries's avatar
 
Dries committed
331
  }
Kjartan's avatar
Kjartan committed
332 333
  return $result ? $result : array();
}
Dries's avatar
 
Dries committed
334

Kjartan's avatar
Kjartan committed
335 336 337
// return 1 if node identified by $nid contains a taxonomy term identified by $tid in his body or title
function taxonomy_node_has_term($nid, $tid) {
  $term_name = db_result(db_query("SELECT name FROM term_data WHERE tid = '%s'", $tid));
Dries's avatar
 
Dries committed
338

Dries's avatar
 
Dries committed
339
  return db_result(db_query("SELECT COUNT(n.nid) FROM node n WHERE n.nid = '%d' AND ((n.body LIKE '%%%s%%') OR (n.body LIKE '%%%s%%'))", $nid, $term_name, $term_name));
Kjartan's avatar
Kjartan committed
340 341 342 343
}

// return array of terms of a node beloging to a particular vocabulary identified by $vid
function taxonomy_node_get_terms_by_vocabulary($nid, $vid, $key = "tid") {
Dries's avatar
 
Dries committed
344
  $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
345 346 347
  $terms = array();
  while ($term = db_fetch_object($result)) {
    $terms[$term->$key] = $term;
Dries's avatar
 
Dries committed
348
  }
Kjartan's avatar
Kjartan committed
349 350 351 352 353 354
  return $terms;
}

// return array of terms of a node
function taxonomy_node_get_terms($nid, $key = "tid") {
  static $terms;
Dries's avatar
 
Dries committed
355

Dries's avatar
 
Dries committed
356
  if (!isset($terms[$nid])) {
Dries's avatar
 
Dries committed
357
    $result = db_query("SELECT t.* FROM term_data t, term_node r WHERE r.tid = t.tid AND r.nid = '%d' ORDER BY weight", $nid);
Kjartan's avatar
Kjartan committed
358
    $terms[$nid] = array();
Dries's avatar
 
Dries committed
359
    while ($term = db_fetch_object($result)) {
Kjartan's avatar
Kjartan committed
360
      $terms[$nid][$term->$key] = $term;
Dries's avatar
 
Dries committed
361 362
    }
  }
Kjartan's avatar
Kjartan committed
363 364
  return $terms[$nid];
}
Dries's avatar
 
Dries committed
365

Kjartan's avatar
Kjartan committed
366 367 368
// save terms of a node
function taxonomy_node_save($nid, $terms) {
  taxonomy_node_delete($nid);
Dries's avatar
 
Dries committed
369

Kjartan's avatar
Kjartan committed
370
  if ($terms) {
Dries's avatar
 
Dries committed
371 372
    foreach ($terms as $term) {
      db_query("INSERT INTO term_node (nid, tid) VALUES ('%d', '%d')", $nid, $term);
Dries's avatar
 
Dries committed
373 374
    }
  }
Kjartan's avatar
Kjartan committed
375
}
Dries's avatar
 
Dries committed
376

Kjartan's avatar
Kjartan committed
377 378
// clean up terms
function taxonomy_node_delete($nid) {
Dries's avatar
 
Dries committed
379
  db_query("DELETE FROM term_node WHERE nid = '%d'", $nid);
Kjartan's avatar
Kjartan committed
380
}
Dries's avatar
 
Dries committed
381

Kjartan's avatar
Kjartan committed
382 383 384
// relations: return array of related terms
function taxonomy_get_related($tid, $key = "tid") {
  if ($tid) {
385
    $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", $tid, $tid, $tid);
Kjartan's avatar
Kjartan committed
386 387 388
    $related = array();
    while ($term = db_fetch_object($result)) {
      $related[$term->$key] = $term;
Dries's avatar
 
Dries committed
389
    }
Kjartan's avatar
Kjartan committed
390
    return $related;
Dries's avatar
 
Dries committed
391
  }
Kjartan's avatar
Kjartan committed
392 393
  else {
    return array();
Dries's avatar
 
Dries committed
394
  }
Kjartan's avatar
Kjartan committed
395
}
Dries's avatar
 
Dries committed
396

Kjartan's avatar
Kjartan committed
397 398 399
// hierarchy: get parent terms
function taxonomy_get_parents($tid, $key = "tid") {
  if ($tid) {
Dries's avatar
 
Dries committed
400
    $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
401 402 403
    $parents = array();
    while ($parent = db_fetch_object($result)) {
      $parents[$parent->$key] = $parent;
Dries's avatar
 
Dries committed
404
    }
Kjartan's avatar
Kjartan committed
405
    return $parents;
Dries's avatar
 
Dries committed
406
  }
Kjartan's avatar
Kjartan committed
407 408 409 410
  else {
    return array();
  }
}
Dries's avatar
 
Dries committed
411

Kjartan's avatar
Kjartan committed
412 413 414
// hierarchy: get children
function taxonomy_get_children($tid, $vid = 0, $key = "tid") {
  if ($vid) {
Dries's avatar
 
Dries committed
415
    $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
416
  }
Kjartan's avatar
Kjartan committed
417
  else {
Dries's avatar
 
Dries committed
418
    $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
419 420 421 422 423 424 425
  }
  $children = array();
  while ($term = db_fetch_object($result)) {
    $children[$term->$key] = $term;
  }
  return $children;
}
Dries's avatar
 
Dries committed
426

Kjartan's avatar
Kjartan committed
427
// hierarchy: get whole family, with tid, parent and depth; useful to show
Dries's avatar
 
Dries committed
428 429
function taxonomy_get_tree($vocabulary_id, $parent = 0, $depth = -1, $key = "tid") {
  static $children, $parents, $terms, $tree;
Kjartan's avatar
Kjartan committed
430
  if ($depth == -1) {
Dries's avatar
 
Dries committed
431
    $children = array();
Dries's avatar
 
Dries committed
432 433
    $parents = array();
    $terms = array();
Kjartan's avatar
Kjartan committed
434
    $tree = array();
Dries's avatar
 
Dries committed
435
  }
Dries's avatar
 
Dries committed
436

Kjartan's avatar
Kjartan committed
437
  $depth++;
Dries's avatar
 
Dries committed
438 439 440 441 442 443 444

  if (!count($children)) {
    $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", $vocabulary_id);
    while ($term = db_fetch_object($result)) {
      $children[$term->parent][] = $term->tid;
      $parents[$term->tid][] = $term->parent;
      $terms[$term->tid] = $term;
Dries's avatar
 
Dries committed
445 446
    }
  }
Dries's avatar
 
Dries committed
447 448 449 450 451 452 453 454 455 456

  if ($children[$parent]) {
    foreach ($children[$parent] as $child) {
      $terms[$child]->depth = $depth;
      unset($terms[$child]->parent); // this would show just one parent
      $terms[$child]->parents = $parents[$child];
      $tree[] = $terms[$child];

      taxonomy_get_tree($vocabulary_id, $child, $depth, $key);
    }
Kjartan's avatar
Kjartan committed
457
  }
Dries's avatar
 
Dries committed
458 459

  return $tree;
Kjartan's avatar
Kjartan committed
460
}
Dries's avatar
 
Dries committed
461

Kjartan's avatar
Kjartan committed
462 463 464
// synonyms: return array of synonyms
function taxonomy_get_synonyms($tid) {
  if ($tid) {
Dries's avatar
 
Dries committed
465
    $result = db_query("SELECT name FROM term_synonym WHERE tid = '%d'", $tid);
Kjartan's avatar
Kjartan committed
466 467
    while ($synonym = db_fetch_array($result)) {
      $synonyms[] = $synonym["name"];
Dries's avatar
 
Dries committed
468
    }
Kjartan's avatar
Kjartan committed
469
    return $synonyms ? $synonyms : array();
Dries's avatar
 
Dries committed
470
  }
Kjartan's avatar
Kjartan committed
471 472
  else {
    return array();
Dries's avatar
 
Dries committed
473
  }
Kjartan's avatar
Kjartan committed
474
}
Dries's avatar
 
Dries committed
475

Kjartan's avatar
Kjartan committed
476 477 478 479
// synonyms: return original term
function taxonomy_get_synonym_root($term) {
  return db_fetch_object(db_query("SELECT * FROM term_synonym s, term_data t WHERE t.tid = s.tid AND s.name = '%s'", $term));
}
Dries's avatar
 
Dries committed
480

Kjartan's avatar
Kjartan committed
481
// given a term id, count number of nodes in it
Dries's avatar
 
Dries committed
482
function taxonomy_term_count_nodes($tid, $type = 0) {
Kjartan's avatar
Kjartan committed
483
  static $count;
Dries's avatar
 
Dries committed
484

Dries's avatar
 
Dries committed
485 486 487
  if (!isset($count[$type])) {
    // $type == 0 always evaluates true is $type is a string
    if (is_numeric($type)) {
Dries's avatar
 
Dries committed
488
      $result = db_query("SELECT t.tid, COUNT(*) AS c FROM term_node t GROUP BY t.tid");
Dries's avatar
 
Dries committed
489 490
    }
    else {
Dries's avatar
 
Dries committed
491
      $result = db_query("SELECT t.tid, COUNT(*) AS c FROM term_node t, node n WHERE t.nid = n.nid AND n.type = '%s' GROUP BY t.tid", $type);
Dries's avatar
 
Dries committed
492
    }
Kjartan's avatar
Kjartan committed
493
    while ($term = db_fetch_object($result)) {
Dries's avatar
 
Dries committed
494
      $count[$type][$term->tid] = $term->c;
Dries's avatar
 
Dries committed
495 496 497
    }
  }

Kjartan's avatar
Kjartan committed
498
  foreach (_taxonomy_term_children($tid) as $c) {
Dries's avatar
 
Dries committed
499
    $children_count += taxonomy_term_count_nodes($c, $type);
Kjartan's avatar
Kjartan committed
500
  }
Dries's avatar
 
Dries committed
501
  return $count[$type][$tid] + $children_count;
Kjartan's avatar
Kjartan committed
502 503 504 505 506
}

// helper for above function
function _taxonomy_term_children($tid) {
  static $children;
Dries's avatar
 
Dries committed
507

Dries's avatar
 
Dries committed
508
  if (!isset($children)) {
Kjartan's avatar
Kjartan committed
509 510 511
    $result = db_query("SELECT tid, parent FROM term_hierarchy");
    while ($term = db_fetch_object($result)) {
      $children[$term->parent][] = $term->tid;
Dries's avatar
 
Dries committed
512
    }
Dries's avatar
 
Dries committed
513
  }
Kjartan's avatar
Kjartan committed
514 515
  return $children[$tid] ? $children[$tid] : array();
}
Dries's avatar
 
Dries committed
516

Kjartan's avatar
Kjartan committed
517 518
function taxonomy_get_vocabulary($vid) {
  // simple cache using a static var?
Dries's avatar
 
Dries committed
519
  return db_fetch_object(db_query("SELECT * FROM vocabulary WHERE vid = '%d'", $vid));
Kjartan's avatar
Kjartan committed
520
}
Dries's avatar
 
Dries committed
521

Kjartan's avatar
Kjartan committed
522 523
function taxonomy_get_term($tid) {
  // simple cache using a static var?
Dries's avatar
 
Dries committed
524
  return db_fetch_object(db_query("SELECT * FROM term_data WHERE tid = '%d'", $tid));
Kjartan's avatar
Kjartan committed
525
}
Dries's avatar
 
Dries committed
526 527 528 529 530

/*
** service functions
*/

Kjartan's avatar
Kjartan committed
531
function _taxonomy_term_select($title, $name, $value, $vocabulary_id, $description, $multiple, $blank, $exclude = array()) {
Dries's avatar
 
Dries committed
532
  $tree = taxonomy_get_tree($vocabulary_id);
Dries's avatar
 
Dries committed
533

Kjartan's avatar
Kjartan committed
534 535 536
  if ($blank) {
    $options[0] = $blank;
  }
Dries's avatar
 
Dries committed
537

Kjartan's avatar
Kjartan committed
538 539 540 541
  if ($tree) {
    foreach ($tree as $term) {
      if (!in_array($term->tid, $exclude)) {
        $options[$term->tid] = _taxonomy_depth($term->depth, '-').$term->name;
Dries's avatar
 
Dries committed
542 543
      }
    }
Kjartan's avatar
Kjartan committed
544 545 546 547 548
    if (!$blank && !$value) {
      // required but without a predefined value, so set first as predefined
      $value = $tree[0]->tid;
    }
  }
Dries's avatar
 
Dries committed
549

Kjartan's avatar
Kjartan committed
550 551 552 553
  if (count($options) > 0) {
    foreach ($options as $key=>$choice) {
      $select .= "<option value=\"$key\"". (is_array($value) ? (in_array($key, $value) ? " selected=\"selected\"" : "") : ($key == $value ? " selected=\"selected\"" : "")) .">". check_form($choice) ."</option>";
    }
Dries's avatar
 
Dries committed
554

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

Kjartan's avatar
Kjartan committed
557
    return form_item($title, "<select name=\"edit[$name][]\"". ($multiple ? " multiple size=\"$size\"" : "") . ($extra ? " $extra" : "") .">$select</select>", $description);
Dries's avatar
 
Dries committed
558
  }
Kjartan's avatar
Kjartan committed
559
}
Dries's avatar
 
Dries committed
560

Kjartan's avatar
Kjartan committed
561 562 563
function _taxonomy_depth($depth, $graphic = '--') {
  for ($n = 0; $n < $depth; $n++) {
    $result .= $graphic;
Dries's avatar
 
Dries committed
564
  }
Kjartan's avatar
Kjartan committed
565 566
  return $result;
}
Dries's avatar
 
Dries committed
567

Kjartan's avatar
Kjartan committed
568 569 570
function _prepare_update($data) {
  foreach ($data as $key => $value) {
    $q[] = "$key = '". check_query($value) ."'";
Dries's avatar
 
Dries committed
571
  }
Kjartan's avatar
Kjartan committed
572 573 574
  $result = implode(", ", $q);
  return $result;
}
Dries's avatar
 
Dries committed
575

Kjartan's avatar
Kjartan committed
576 577 578 579 580 581 582
function _prepare_insert($data, $stage) {
  if ($stage == 1) {
    $result = implode(", ", array_keys($data));
  }
  else {
    foreach (array_values($data) as $value) {
      $q[] = "'". check_query($value) ."'";
Dries's avatar
 
Dries committed
583
    }
Kjartan's avatar
Kjartan committed
584
    $result = implode(", ", $q);
Dries's avatar
 
Dries committed
585
  }
Kjartan's avatar
Kjartan committed
586 587
  return "($result)";
}
Dries's avatar
 
Dries committed
588

Kjartan's avatar
Kjartan committed
589 590
function taxonomy_page() {
  global $op;
Dries's avatar
 
Dries committed
591

Kjartan's avatar
Kjartan committed
592 593 594 595 596 597
  switch ($op) {
    case "feed":
      taxonomy_feed();
      break;
    default:
       // TODO: pretty display of all vocabularies
Dries's avatar
 
Dries committed
598
  }
Kjartan's avatar
Kjartan committed
599
}
Dries's avatar
 
Dries committed
600

Kjartan's avatar
Kjartan committed
601
/*
Dries's avatar
 
Dries committed
602 603 604
** admin
*/

Kjartan's avatar
Kjartan committed
605
function taxonomy_admin() {
Dries's avatar
 
Dries committed
606
  global $edit, $type, $op, $id, $theme;
Kjartan's avatar
Kjartan committed
607 608 609 610 611 612 613

  if (user_access("administer taxonomy")) {
    $links[] = la(t("add new vocabulary"), array("mod" => "taxonomy", "op" => "add", "type" => "vocabulary"));
    $links[] = la(t("overview"), array("mod" => "taxonomy"));
    $links[] = la(t("help"), array("mod" => "taxonomy", "op" => "help"));

    print "<small>". implode(" | ", $links) ."</small><hr>\n";
Dries's avatar
 
Dries committed
614

Kjartan's avatar
Kjartan committed
615 616
    switch ($op) {
      case "add":
Kjartan's avatar
Kjartan committed
617
        if ($type == "vocabulary") {
Kjartan's avatar
Kjartan committed
618
          print taxonomy_form_vocabulary();
Kjartan's avatar
Kjartan committed
619 620
        }
        else {
Kjartan's avatar
Kjartan committed
621
          print taxonomy_form_term();
Kjartan's avatar
Kjartan committed
622
        }
Kjartan's avatar
Kjartan committed
623 624
        break;
      case "edit":
Kjartan's avatar
Kjartan committed
625
        if ($type == "vocabulary") {
Kjartan's avatar
Kjartan committed
626
          print taxonomy_form_vocabulary(object2array(taxonomy_get_vocabulary($id)));
Kjartan's avatar
Kjartan committed
627 628
        }
        else {
Kjartan's avatar
Kjartan committed
629
          print taxonomy_form_term(object2array(taxonomy_get_term($id)));
Kjartan's avatar
Kjartan committed
630
        }
Kjartan's avatar
Kjartan committed
631 632
        break;
      case "preview":
Kjartan's avatar
Kjartan committed
633
        print taxonomy_form($id);
Kjartan's avatar
Kjartan committed
634 635 636 637
        break;
      case "help":
        print taxonomy_help();
        break;
Dries's avatar
 
Dries committed
638
      case t("Delete"):
Dries's avatar
 
Dries committed
639 640 641 642 643 644 645 646 647 648 649 650 651
        if (!$edit["confirm"]) {
          if ($type == "vocabulary") {
            echo _taxonomy_confirm_del_vocabulary($edit["vid"]);
          }
          else {
            echo _taxonomy_confirm_del_term($edit["tid"]);
          }
          break;
        }
        else {
          $edit["name"] = 0;
          // fall through:
        }
Dries's avatar
 
Dries committed
652
      case t("Submit"):
Kjartan's avatar
Kjartan committed
653
        if ($type == "vocabulary") {
Kjartan's avatar
Kjartan committed
654
          print status(taxonomy_save_vocabulary($edit));
Kjartan's avatar
Kjartan committed
655 656
        }
        else {
Kjartan's avatar
Kjartan committed
657
          print status(taxonomy_save_term($edit));
Dries's avatar
 
Dries committed
658 659 660 661 662 663
          if (!$edit["tid"]) {
            // if INSERT show form again
            print taxonomy_form_term();
            break;
          }
          // else (UPDATE or DELETE) fall through
Kjartan's avatar
Kjartan committed
664
        }
Kjartan's avatar
Kjartan committed
665 666 667 668 669 670 671 672 673 674 675 676
        // fall through:
      default:
        print taxonomy_overview();
    }
  }
  else {
    print message_access();
  }
}

function taxonomy_help() {
  ?>
Dries's avatar
 
Dries committed
677 678 679 680 681 682

  <h3>Background</h3>
  <p>Classifying nodes allows for the organization of content into categories and subcategories of description. These categories can be used to organize and retrieve similarly described content. Drupal's <i>taxonomy.module</i> is an extremely flexible classification system that allows for multiple lists of categories for classification (controlled vocabularies) and offers the possibility of creating thesauri (controlled vocabularies that indicate the relationship of terms) and taxonomies (controlled vocabularies where relationships are indicated hierarchically). For details about <a href="http://www.eleganthack.com/archives/002165.html#002165">classification types</a> and insight into the development of <i>taxonomy.module</i>, see this <a href="http://www.drupal.org/node.php?id=55">drupal.org discussion</a>.</p>

  <h3>An example taxonomy: food</h3>
  <p>Dairy <br />
Kjartan's avatar
Kjartan committed
683 684 685 686 687 688 689 690 691 692 693
  --Milk <br />
  Drink <br />
  --Alchohol <br />
  --Pop <br />
  --Milk<br />
  Meat <br />
  --Beef <br />
  --Chicken <br />
  --Lamb <br />
  Spices <br />
  --Sugar</p>
Dries's avatar
 
Dries committed
694 695 696 697 698 699
  <p><b>Notes</b></p>
   <ul>
   <li>The term <i>Milk</i> appears within both <i>Dairy</i> and <i>Drink</i>.  This is an example of <i>nmultiple parents</i> for a term.</li>
   <li>The order of siblings (e.g. <i>Beef</i>, <i>Chicken</i>, <i>Lamb</i>) in the taxonomy may be controlled with the <i>weight</i> parameter. </li>
  </ul>

Kjartan's avatar
Kjartan committed
700
  <h3>Vocabularies</h3>
Dries's avatar
 
Dries committed
701
  <p>When you create a controlled vocabulary you are creating a set of terms to use for describing content (known as descriptors in indexing lingo). Drupal allows you to describe each node of content (blog, story, etc.) using one or many of these terms. For simple implementations, you might create a set of categories without subcategories, similar to <a href="http://www.slashdot.com/">Slashdot's</a> sections.  For more complex implementations, you might create a hierarchical list of categories such as the example <i>Food</i> taxonomy above.</p>
Kjartan's avatar
Kjartan committed
702 703

  <h4>Setting up a vocabulary</h4>
Dries's avatar
 
Dries committed
704 705 706
  <p>When you set up a controlled vocabulary, you will be asked to enter some descriptive data and define the attributes of this vocabulary. For example, if you select the <i>hierarchy</i> option, you will be defining a taxonomy or a thesaurus. If you select <i>related terms</i> option, you are allowing the definition of related terms as in a thesaurus. Selecting <i>multiple select</i> will allow you to describe a node using more than one term. That node will then appear in each term's page, thus increasing the chance that a user will find it.</p>

  <i>Vocabulary name</i><br />Required. The name for this vocabulary. Example: <i>Dairy</i>.<br />
Kjartan's avatar
Kjartan committed
707
  <br />
Dries's avatar
 
Dries committed
708
  <i>Description</i><br />Optional. Description of the vocabulary, can be used by modules and feeds.<br />
Kjartan's avatar
Kjartan committed
709
  <br />
Dries's avatar
 
Dries committed
710
  <i>Types</i><br />Required. The list of node types you want to associate this vocabulary with. Some available types are: blog, book, forum, page, story.<br />
Kjartan's avatar
Kjartan committed
711
  <br />
Dries's avatar
 
Dries committed
712
  <i><a name="relatedterms"></a>Related terms</i><br />Allows relationships between terms within this vocabulary. Think of these as <i>see also</i>-references.<br />
Kjartan's avatar
Kjartan committed
713
  <br />
Dries's avatar
 
Dries committed
714
  <i><a name="hierarchy"></a>Hierarchy</i><br />Allows a tree-like taxonomy, as in our <i>Foods</i> example above<br />
Kjartan's avatar
Kjartan committed
715
  <br />
Dries's avatar
 
Dries committed
716 717
  <i>Multiple select</i><br />Allows nodes to be described using more than one term. Nodes may then appear on multiple taxonomy pages.<br />

Kjartan's avatar
Kjartan committed
718
  <h4>Adding terms to a vocabulary</h4>
Dries's avatar
 
Dries committed
719 720 721
<p>The options you see when adding a term to a vocabulary will depend on what you selected for <i>related terms</i>, <i>hierarchy </i>and <i>multiple select</i> when you created the corrosponding vocabulary.</p>

  <i>Term name</i><br />Required. The name for this term. Example: <i>Milk</i><br />
Kjartan's avatar
Kjartan committed
722
  <br />
Dries's avatar
 
Dries committed
723
  <i>Description</i><br />Optional. Description of the term that may be used by modules and RSS feeds.  This is synonymous with a 'scope note'.<br />
Kjartan's avatar
Kjartan committed
724
  <br />
Dries's avatar
 
Dries committed
725
  <i><a name="parent"></a>Parent</i><br />Required. Select the term under which this term is a subset -- the branch of the hierarchy that this term belongs under. This is also known as the "Broader term" indicator used in thesauri.<br />
Kjartan's avatar
Kjartan committed
726
  <br />
Dries's avatar
 
Dries committed
727 728 729
  <i><a name="synonyms"></a>Synonyms</i><br />Optional. Enter synonyms for this term, one synonym per line. Synonyms can be used for variant spellings, acronyms, and other terms that have the same meaning as the added term, but which are not explicitly listed in this thesaurus (i.e. <i>unauthorized terms</i>).<br />

  <h3>Displaying nodes organized by term(s)</h3>
Dries's avatar
 
Dries committed
730
  <p>In order to view the nodes associated with a term or a collection of terms, you should browse to a properly formed URL. For example, see <a href="<?php print path_uri().drupal_url(array("mod" => "node", "or" => "1,2"), "module"); ?>"><?php print path_uri().drupal_url(array("mod" => "node", "or" => "1,2"), "module"); ?></a>.  Taxonomy URLs always contain  a term ID or list of term IDs at the end of the URL (aka <i>querystring</i>). You may learn the term ID for a given term by hovering over that term in the <?php echo la("taxonomy overview", array("mod" => "taxonomy")) ?> page in the Admin and noting the number after the querystring parameter called <i>tid</i>.  If you wish to see nodes from a collection of term IDs, separate each term ID with a comma.  Also, the name of the querystring parameter may be <i>or</i> or <i>and</i>: <i>or</i> shows nodes which appear in <b>any</b> of the term IDs while <i>and</i> shows nodes in <b>all</b> the specified term IDs.  Thus, <i>or</i> is less specific than <i>and</i>.</p>
Dries's avatar
 
Dries committed
731 732 733 734

  <h3>RSS feeds</h3>
  <p>Every term, or collection of terms, provides an <a href="http://backend.userland.com/stories/rss091">RSS</a> feed to which interested users may subscribe. The URL format for an sample RSS feed is <a href="<?php print path_uri().drupal_url(array("mod" => "node", "op" => "feed", "or" => "1,2"), "module"); ?>"><?php print path_uri().drupal_url(array("mod" => "node", "op" => "feed", "or" => "1,2"), "module"); ?></a>.</p>
 <?php
Kjartan's avatar
Kjartan committed
735
}
Dries's avatar
 
Dries committed
736
?>