taxonomy.module
<?php
function taxonomy_perm() {
return array('administer taxonomy');
}
function taxonomy_link($type, $node = NULL) {
if ($type == 'taxonomy terms' && $node != NULL) {
$links = array();
if (array_key_exists('taxonomy', $node)) {
foreach ($node->taxonomy as $tid) {
$term = taxonomy_get_term($tid);
$links[] = l($term->name, 'taxonomy/term/'. $term->tid);
}
}
else {
$links = array();
foreach (taxonomy_node_get_terms($node->nid) as $term) {
$links[] = l($term->name, 'taxonomy/term/'. $term->tid);
}
}
return $links;
}
}
function taxonomy_menu($may_cache) {
$items = array();
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' => 'admin/taxonomy/edit/vocabulary', 'title' => t('edit vocabulary'),
'callback' => 'taxonomy_admin',
'access' => user_access('administer taxonomy'),
'type' => MENU_CALLBACK);
$items[] = array('path' => 'admin/taxonomy/preview/vocabulary', 'title' => t('preview vocabulary'),
'callback' => 'taxonomy_admin',
'access' => user_access('administer taxonomy'),
'type' => MENU_CALLBACK);
$items[] = array('path' => 'admin/taxonomy/add/term', 'title' => t('add term'),
'callback' => 'taxonomy_admin',
'access' => user_access('administer taxonomy'),
'type' => MENU_CALLBACK);
$items[] = array('path' => 'admin/taxonomy/edit/term', 'title' => t('edit term'),
'callback' => 'taxonomy_admin',
'access' => user_access('administer taxonomy'),
'type' => MENU_CALLBACK);
$items[] = array('path' => 'taxonomy/term', 'title' => t('taxonomy term'),
'callback' => 'taxonomy_term_page',
'access' => user_access('access content'),
'type' => MENU_CALLBACK);
}
return $items;
}
function taxonomy_form_vocabulary($edit = array()) {
foreach (node_list() as $type) {
$node_type = node_invoke($type, 'node_name');
$nodes[$type] = $node_type ? $node_type : $type;
}
$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', $edit['nodes'], $nodes, 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/help/taxonomy', NULL, NULL, 'related-terms'))));
$form .= form_radios(t('Hierarchy'), 'hierarchy', $edit['hierarchy'], array(t('Disabled'), t('Single'), t('Multiple')), t('Allows <a href="%help-url">a tree-like hierarchy</a> between terms of this vocabulary.', array('%help-url' => url('admin/help/taxonomy', NULL, NULL, 'hierarchy'))));
$form .= form_checkbox(t('Multiple select'), 'multiple', 1, $edit['multiple'], 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 <strong>must</strong> have at least one term in this vocabulary.'));
$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.'));
$form .= form_submit(t('Submit'));
if ($edit['vid']) {
$form .= form_submit(t('Delete'));
$form .= form_hidden('vid', $edit['vid']);
}
return form($form);
}
function taxonomy_save_vocabulary($edit) {
$edit['nodes'] = ($edit['nodes']) ? $edit['nodes'] : array();
$edit['weight'] = ($edit['weight']) ? $edit['weight'] : 0;
$data = array('name' => $edit['name'], 'description' => $edit['description'], 'help' => $edit['help'], 'multiple' => $edit['multiple'], 'required' => $edit['required'], 'hierarchy' => $edit['hierarchy'], 'relations' => $edit['relations'], 'weight' => $edit['weight'], 'module' => isset($edit['module']) ? $edit['module'] : 'taxonomy');
if ($edit['vid'] && $edit['name']) {
db_query('UPDATE {vocabulary} SET '. _taxonomy_prepare_update($data) .' WHERE vid = %d', $edit['vid']);
db_query("DELETE FROM {vocabulary_node_types} WHERE vid = %d", $edit['vid']);
foreach ($edit['nodes'] as $type) {
db_query("INSERT INTO {vocabulary_node_types} (vid, type) VALUES (%d, '%s')", $edit['vid'], $type);
}
module_invoke_all('taxonomy', 'update', 'vocabulary', $edit);
$message = t('Updated vocabulary %name.', array('%name' => theme('placeholder', $edit['name'])));
}
else if ($edit['vid']) {
$message = taxonomy_del_vocabulary($edit['vid']);
}
else {
$data['vid'] = $edit['vid'] = db_next_id('{vocabulary}_vid');
db_query('INSERT INTO {vocabulary} '. _taxonomy_prepare_insert($data, 1) .' VALUES '. _taxonomy_prepare_insert($data, 2));
foreach ($edit['nodes'] as $type) {
db_query("INSERT INTO {vocabulary_node_types} (vid, type) VALUES (%d, '%s')", $edit['vid'], $type);
}
module_invoke_all('taxonomy', 'insert', 'vocabulary', $edit);
$message = t('Created new vocabulary %name.', array('%name' => theme('placeholder', $edit['name'])));
}
cache_clear_all();
drupal_set_message($message);
return $edit;
}
function taxonomy_del_vocabulary($vid) {
$vocabulary = taxonomy_get_vocabulary($vid);
db_query('DELETE FROM {vocabulary} WHERE vid = %d', $vid);
db_query('DELETE FROM {vocabulary_node_types} WHERE vid = %d', $vid);
$result = db_query('SELECT tid FROM {term_data} WHERE vid = %d', $vid);
while ($term = db_fetch_object($result)) {
taxonomy_del_term($term->tid);
}
module_invoke_all('taxonomy', 'delete', 'vocabulary', $vocabulary);
cache_clear_all();
return t('deleted vocabulary "%name".', array('%name' => theme('placeholder', $vocabulary->name)));
}
function _taxonomy_confirm_del_vocabulary($vid) {
$vocabulary = taxonomy_get_vocabulary($vid);
$extra = form_hidden('type', 'vocabulary');
$extra .= form_hidden('vid', $vid);
$output = theme('confirm',
t('Are you sure you want to delete the vocabulary %title?', array('%title' => theme('placeholder', $vocabulary->name))),
'admin/taxonomy',
t('Deleting a vocabulary will delete all the terms in it. This action cannot be undone.'),
t('Delete'),
t('Cancel'),
$extra);
return $output;
}
function taxonomy_form_term($edit = array()) {
$vocabulary_id = isset($edit['vid']) ? $edit['vid'] : arg(4);
$vocabulary = taxonomy_get_vocabulary($vocabulary_id);
$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.'));
if ($vocabulary->hierarchy) {
$parent = array_keys(taxonomy_get_parents($edit['tid']));
$children = taxonomy_get_tree($vocabulary_id, $edit['tid']);
foreach ($children as $child) {
$exclude[] = $child->tid;
}
$exclude[] = $edit['tid'];
if ($vocabulary->hierarchy == 1) {
$form .= _taxonomy_term_select(t('Parent'), 'parent', $parent, $vocabulary_id, l(t('Parent term'), 'admin/help/taxonomy', NULL, NULL, 'parent') .'.', 0, '<'. t('root') .'>', $exclude);
}
elseif ($vocabulary->hierarchy == 2) {
$form .= _taxonomy_term_select(t('Parents'), 'parent', $parent, $vocabulary_id, l(t('Parent terms'), 'admin/help/taxonomy', NULL, NULL, 'parent') .'.', 1, '<'. t('root') .'>', $exclude);
}
}
if ($vocabulary->relations) {
$form .= _taxonomy_term_select(t('Related terms'), 'relations', array_keys(taxonomy_get_related($edit['tid'])), $vocabulary_id, NULL, 1, '<'. t('none') .'>', array($edit['tid']));
}
$form .= form_textarea(t('Synonyms'), 'synonyms', implode("\n", taxonomy_get_synonyms($edit['tid'])), 30, 5, t('<a href="%help-url">Synonyms</a> of this term, one synonym per line.', array('%help-url' => url('admin/help/taxonomy', NULL, NULL, 'synonyms'))));
$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.'));
$form .= form_hidden('vid', $vocabulary->vid);
$form .= form_submit(t('Submit'));
if ($edit['tid']) {
$form .= form_submit(t('Delete'));
$form .= form_hidden('tid', $edit['tid']);
}
else {
$form .= form_hidden('destination', $_GET['q']);
}
return form($form);
}
function taxonomy_save_term($edit) {
if ($edit['tid'] && $edit['name']) {
$data = array('name' => $edit['name'], 'description' => $edit['description'], 'weight' => $edit['weight']);
db_query('UPDATE {term_data} SET '. _taxonomy_prepare_update($data) .' WHERE tid = %d', $edit['tid']);
module_invoke_all('taxonomy', 'update', 'term', $edit);
$message = t('The term %term has been updated.', array('%term' => theme('placeholder', $edit['name'])));
}
else if ($edit['tid']) {
return taxonomy_del_term($edit['tid']);
}
else {
$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']);
db_query('INSERT INTO {term_data} '. _taxonomy_prepare_insert($data, 1) .' VALUES '. _taxonomy_prepare_insert($data, 2));
module_invoke_all('taxonomy', 'insert', 'term', $edit);
$message = t('Created new term %term.', array('%term' => theme('placeholder', $edit['name'])));
}
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) {
if ($related_id != 0) {
db_query('INSERT INTO {term_relation} (tid1, tid2) VALUES (%d, %d)', $edit['tid'], $related_id);
}
}
}
db_query('DELETE FROM {term_hierarchy} WHERE tid = %d', $edit['tid']);
if (!isset($edit['parent'])) {
$edit['parent'] = array(0);
}
if (is_array($edit['parent'])) {
foreach ($edit['parent'] as $parent) {
if (is_array($parent)) {
foreach ($parent as $tid) {
db_query('INSERT INTO {term_hierarchy} (tid, parent) VALUES (%d, %d)', $edit['tid'], $tid);
}
}
else {
db_query('INSERT INTO {term_hierarchy} (tid, parent) VALUES (%d, %d)', $edit['tid'], $parent);
}
}
}
db_query('DELETE FROM {term_synonym} WHERE tid = %d', $edit['tid']);
if ($edit['synonyms']) {
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));
}
}
}
cache_clear_all();
drupal_set_message($message);
return $edit;
}
function taxonomy_del_term($tid) {
$tids = array($tid);
while ($tids) {
$children_tids = $orphans = array();
foreach ($tids as $tid) {
if ($children = taxonomy_get_children($tid)) {
foreach ($children as $child) {
$parents = taxonomy_get_parents($child->tid);
if (count($parents) == 1) {
$orphans[] = $child->tid;
}
}
}
$term = taxonomy_get_term($tid);
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);
module_invoke_all('taxonomy', 'delete', 'term', $term);
drupal_set_message(t('Deleted term %name.', array('%name' => theme('placeholder', $term->name))));
}
$tids = $orphans;
}
cache_clear_all();
}
function _taxonomy_confirm_del_term($tid) {
$term = taxonomy_get_term($tid);
$extra = form_hidden('type', 'term');
$extra .= form_hidden('tid', $tid);
$output = theme('confirm',
t('Are you sure you want to delete the term %title?', array('%title' => theme('placeholder', $term->name))),
'admin/taxonomy',
t('Deleting a term will delete all its children if there are any. This action cannot be undone.'),
t('Delete'),
t('Cancel'),
$extra);
return $output;
}
function taxonomy_overview() {
$header = array(t('Name'), t('Type'), array('data' => t('Operations'), 'colspan' => '3'));
$vocabularies = taxonomy_get_vocabularies();
foreach ($vocabularies as $vocabulary) {
$types = array();
foreach($vocabulary->nodes as $type) {
$node_type = node_invoke($type, 'node_name');
$types[] = $node_type ? $node_type : $type;
}
$rows[] = array(check_plain($vocabulary->name), implode(', ', $types), 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"));
$tree = taxonomy_get_tree($vocabulary->vid);
if ($tree) {
unset($data);
foreach ($tree as $term) {
$data .= _taxonomy_depth($term->depth) .' '. check_plain($term->name) .' ('. l(t('edit term'), "admin/taxonomy/edit/term/$term->tid") .')<br />';
}
$rows[] = array(array('data' => $data, 'colspan' => '5'));
}
}
if (!$rows) {
$rows[] = array(array('data' => t('No categories available.'), 'colspan' => '5'));
}
return theme('table', $header, $rows);
}
function taxonomy_form($vid, $value = 0, $help = NULL, $name = 'taxonomy') {
$vocabulary = taxonomy_get_vocabulary($vid);
$help = ($help) ? $help : $vocabulary->help;
if ($vocabulary->required) {
$blank = 0;
}
else {
$blank = '<'. t('none') .'>';
}
return _taxonomy_term_select(check_plain($vocabulary->name), $name, $value, $vid, $help, intval($vocabulary->multiple), $blank);
}
function taxonomy_form_all($value = 0, $help = NULL, $name = 'taxonomy') {
$vocabularies = taxonomy_get_vocabularies();
$options = array();
foreach ($vocabularies as $vid => $vocabulary) {
$tree = taxonomy_get_tree($vid);
$options[$vocabulary->name] = array();
if ($tree) {
foreach ($tree as $term) {
$options[$vocabulary->name][$term->tid] = _taxonomy_depth($term->depth, '-') . $term->name;
}
}
}
return $options;
}
function taxonomy_get_vocabularies($type = NULL) {
if ($type) {
$result = db_query("SELECT v.*, n.type FROM {vocabulary} v LEFT JOIN {vocabulary_node_types} n ON v.vid = n.vid WHERE n.type = '%s' ORDER BY v.weight, v.name", $type);
}
else {
$result = db_query('SELECT v.*, n.type FROM {vocabulary} v LEFT JOIN {vocabulary_node_types} n ON v.vid = n.vid ORDER BY v.weight, v.name');
}
$vocabularies = array();
$node_types = array();
while ($voc = db_fetch_object($result)) {
$node_types[$voc->vid][] = $voc->type;
unset($voc->type);
$voc->nodes = $node_types[$voc->vid];
$vocabularies[$voc->vid] = $voc;
}
return $vocabularies;
}
function taxonomy_node_form($type, $node = '', $help = NULL, $name = 'taxonomy') {
if (!$node->taxonomy) {
if ($node->nid) {
$terms = array_keys(taxonomy_node_get_terms($node->nid));
}
else {
$terms = 0;
}
}
else {
$terms = $node->taxonomy;
}
$c = db_query("SELECT v.*, n.type FROM {vocabulary} v INNER JOIN {vocabulary_node_types} n ON v.vid = n.vid WHERE n.type = '%s' ORDER BY v.weight, v.name", $type);
while ($vocabulary = db_fetch_object($c)) {
$result[] = taxonomy_form($vocabulary->vid, $terms, $help, $name);
}
return $result ? $result : array();
}
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);
$terms = array();
while ($term = db_fetch_object($result)) {
$terms[$term->$key] = $term;
}
return $terms;
}
function taxonomy_node_get_terms($nid, $key = 'tid') {
static $terms;
if (!isset($terms[$nid])) {
$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);
$terms[$nid] = array();
while ($term = db_fetch_object($result)) {
$terms[$nid][$term->$key] = $term;
}
}
return $terms[$nid];
}
function taxonomy_node_save($nid, $terms) {
taxonomy_node_delete($nid);
if (is_array($terms)) {
foreach ($terms as $term) {
if (is_array($term)) {
foreach ($term as $tid) {
if ($tid) {
db_query('INSERT INTO {term_node} (nid, tid) VALUES (%d, %d)', $nid, $tid);
}
}
}
else if ($term) {
db_query('INSERT INTO {term_node} (nid, tid) VALUES (%d, %d)', $nid, $term);
}
}
}
}
function taxonomy_node_delete($nid) {
db_query('DELETE FROM {term_node} WHERE nid = %d', $nid);
}
function taxonomy_get_related($tid, $key = 'tid') {
if ($tid) {
$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);
$related = array();
while ($term = db_fetch_object($result)) {
$related[$term->$key] = $term;
}
return $related;
}
else {
return array();
}
}
function taxonomy_get_parents($tid, $key = 'tid') {
if ($tid) {
$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);
$parents = array();
while ($parent = db_fetch_object($result)) {
$parents[$parent->$key] = $parent;
}
return $parents;
}
else {
return array();
}
}
function taxonomy_get_parents_all($tid) {
$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;
}
function taxonomy_get_children($tid, $vid = 0, $key = 'tid') {
if ($vid) {
$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);
}
else {
$result = db_query('SELECT t.* FROM {term_hierarchy} h, {term_data} t WHERE h.tid = t.tid AND parent = %d ORDER BY weight', $tid);
}
$children = array();
while ($term = db_fetch_object($result)) {
$children[$term->$key] = $term;
}
return $children;
}
function taxonomy_get_tree($vid, $parent = 0, $depth = -1, $max_depth = NULL) {
static $children, $parents, $terms;
$depth++;
if (!isset($children[$vid])) {
$children[$vid] = array();
$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);
while ($term = db_fetch_object($result)) {
$children[$vid][$term->parent][] = $term->tid;
$parents[$vid][$term->tid][] = $term->parent;
$terms[$vid][$term->tid] = $term;
}
}
$max_depth = (is_null($max_depth)) ? count($children[$vid]) : $max_depth;
if ($children[$vid][$parent]) {
foreach ($children[$vid][$parent] as $child) {
if ($max_depth > $depth) {
$terms[$vid][$child]->depth = $depth;
unset($terms[$vid][$child]->parent);
$terms[$vid][$child]->parents = $parents[$vid][$child];
$tree[] = $terms[$vid][$child];
if ($children[$vid][$child]) {
$tree = array_merge($tree, taxonomy_get_tree($vid, $child, $depth, $max_depth));
}
}
}
}
return $tree ? $tree : array();
}
function taxonomy_get_synonyms($tid) {
if ($tid) {
$result = db_query('SELECT name FROM {term_synonym} WHERE tid = %d', $tid);
while ($synonym = db_fetch_array($result)) {
$synonyms[] = $synonym['name'];
}
return $synonyms ? $synonyms : array();
}
else {
return array();
}
}
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));
}
function taxonomy_term_count_nodes($tid, $type = 0) {
static $count;
if (!isset($count[$type])) {
if (is_numeric($type)) {
$result = db_query(db_rewrite_sql('SELECT t.tid, COUNT(n.nid) AS c FROM {term_node} t INNER JOIN {node} n ON t.nid = n.nid WHERE n.status = 1 GROUP BY t.tid'));
}
else {
$result = db_query(db_rewrite_sql("SELECT t.tid, COUNT(n.nid) AS c FROM {term_node} t, {node} n WHERE t.nid = n.nid AND n.status = 1 AND n.type = '%s' GROUP BY t.tid"), $type);
}
while ($term = db_fetch_object($result)) {
$count[$type][$term->tid] = $term->c;
}
}
foreach (_taxonomy_term_children($tid) as $c) {
$children_count += taxonomy_term_count_nodes($c, $type);
}
return $count[$type][$tid] + $children_count;
}
function _taxonomy_term_children($tid) {
static $children;
if (!isset($children)) {
$result = db_query('SELECT tid, parent FROM {term_hierarchy}');
while ($term = db_fetch_object($result)) {
$children[$term->parent][] = $term->tid;
}
}
return $children[$tid] ? $children[$tid] : array();
}
function taxonomy_get_term_by_name($name) {
$db_result = db_query("SELECT * FROM {term_data} WHERE LOWER('%s') LIKE LOWER(name)", trim($name));
$result = array();
while ($term = db_fetch_object($db_result)) {
$result[] = $term;
}
return $result;
}
function taxonomy_get_vocabulary($vid) {
$result = db_query('SELECT v.*, n.type FROM {vocabulary} v LEFT JOIN {vocabulary_node_types} n ON v.vid = n.vid WHERE v.vid = %d ORDER BY v.weight, v.name', $vid);
$node_types = array();
while ($voc = db_fetch_object($result)) {
$node_types[] = $voc->type;
unset($voc->type);
$voc->nodes = $node_types;
$vocabulary = $voc;
}
return $vocabulary;
}
function taxonomy_get_term($tid) {
return db_fetch_object(db_query('SELECT * FROM {term_data} WHERE tid = %d', $tid));
}
function _taxonomy_term_select($title, $name, $value, $vocabulary_id, $description, $multiple, $blank, $exclude = array()) {
$tree = taxonomy_get_tree($vocabulary_id);
$options = array();
if ($blank) {
$options[0] = $blank;
}
if ($tree) {
foreach ($tree as $term) {
if (!in_array($term->tid, $exclude)) {
$options[$term->tid] = _taxonomy_depth($term->depth, '-') . $term->name;
}
}
if (!$blank && !$value) {
$value = $tree[0]->tid;
}
}
return form_select($title, $name . ($multiple ? '' : ']['), $value, $options, $description, $multiple ? 'size="'. min(12, count($options)) .'"' : 0, $multiple);
}
function _taxonomy_depth($depth, $graphic = '--') {
for ($n = 0; $n < $depth; $n++) {
$result .= $graphic;
}
return $result;
}
function _taxonomy_prepare_update($data) {
foreach ($data as $key => $value) {
$q[] = "$key = '". str_replace('%', '%%', db_escape_string($value)) ."'";
}
$result = implode(', ', $q);
return $result;
}
function _taxonomy_prepare_insert($data, $stage) {
if ($stage == 1) {
$result = implode(', ', array_keys($data));
}
else {
foreach (array_values($data) as $value) {
if (is_int($value)) {
$q[] = $value;
}
else {
$q[] = "'". str_replace('%', '%%', db_escape_string($value)) ."'";
}
}
$result = implode(', ', $q);
}
return "($result)";
}
function taxonomy_select_nodes($tids = array(), $operator = 'or', $depth = 0, $pager = TRUE) {
if (count($tids) > 0) {
$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);
$descendant_tids[] = array_merge(array($tid), array_map('_taxonomy_get_tid_from_term', $tree));
}
if ($operator == 'or') {
$str_tids = implode(',', call_user_func_array('array_merge', $descendant_tids));
$sql = 'SELECT DISTINCT(n.nid), n.sticky, n.title, n.created FROM {node} n INNER JOIN {term_node} tn ON n.nid = tn.nid WHERE tn.tid IN ('. $str_tids .') AND n.status = 1 ORDER BY n.sticky DESC, n.created DESC';
$sql_count = 'SELECT COUNT(DISTINCT(n.nid)) FROM {node} n INNER JOIN {term_node} tn ON n.nid = tn.nid WHERE tn.tid IN ('. $str_tids .') AND n.status = 1';
}
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), n.sticky, n.title, n.created FROM {node} n '. $joins .' WHERE n.status = 1 '. $wheres .' ORDER BY n.sticky DESC, n.created DESC';
$sql_count = 'SELECT COUNT(DISTINCT(n.nid)) FROM {node} n '. $joins .' WHERE n.status = 1 ' . $wheres;
}
$sql = db_rewrite_sql($sql);
$sql_count = db_rewrite_sql($sql_count);
if ($pager) {
$result = pager_query($sql, variable_get('default_nodes_main', 10), 0, $sql_count);
}
else {
$result = db_query_range($sql, 0, 15);
}
}
return $result;
}
function taxonomy_render_nodes($result) {
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.');
}
return $output;
}
function taxonomy_nodeapi($node, $op, $arg = 0) {
switch ($op) {
case 'insert':
taxonomy_node_save($node->nid, $node->taxonomy);
break;
case 'update':
taxonomy_node_save($node->nid, $node->taxonomy);
break;
case 'delete':
taxonomy_node_delete($node->nid);
break;
case 'rss item':
return taxonomy_rss_item($node);
break;
}
}
function taxonomy_term_page($str_tids = '', $depth = 0, $op = 'page') {
if (preg_match('/^([0-9]+[+ ])+[0-9]+$/', $str_tids)) {
$operator = 'or';
$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();
}
$rss_tids = urlencode($str_tids);
if ($tids) {
$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;
}
if ($names) {
drupal_set_title($title = check_plain(implode(', ', $names)));
switch ($op) {
case 'page':
$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_add_link(array('rel' => 'alternate',
'type' => 'application/rss+xml',
'title' => 'RSS - '. $title,
'href' => url('taxonomy/term/'. $rss_tids .'/'. $depth .'/feed')));
$output = taxonomy_render_nodes(taxonomy_select_nodes($tids, $operator, $depth, TRUE));
$output .= theme('xml_icon', url("taxonomy/term/$rss_tids/$depth/feed"));
print theme('page', $output);
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();
}
}
else {
drupal_not_found();
}
}
}
function taxonomy_admin() {
$op = $_POST['op'];
$edit = $_POST['edit'];
if (empty($op)) {
$op = arg(2);
}
switch ($op) {
case 'add':
if (arg(3) == 'vocabulary') {
$output = taxonomy_form_vocabulary();
}
else if (arg(3) == 'term') {
$output = taxonomy_form_term();
}
break;
case 'edit':
if (arg(3) == 'vocabulary') {
$output = taxonomy_form_vocabulary(object2array(taxonomy_get_vocabulary(arg(4))));
}
else if (arg(3) == 'term') {
$output = taxonomy_form_term(object2array(taxonomy_get_term(arg(4))));
}
break;
case 'preview':
$output = taxonomy_form(arg(4));
break;
case t('Delete'):
if (!$edit['confirm']) {
if (arg(3) == 'vocabulary') {
$output = _taxonomy_confirm_del_vocabulary($edit['vid']);
}
else {
$output = _taxonomy_confirm_del_term($edit['tid']);
}
break;
}
else {
$edit['name'] = 0;
}
case t('Submit'):
if (arg(3) == 'vocabulary') {
taxonomy_save_vocabulary($edit);
}
else {
taxonomy_save_term($edit);
}
drupal_goto('admin/taxonomy');
default:
$output = taxonomy_overview();
}
print theme('page', $output);
}
function taxonomy_rss_item($node) {
$output = array();
$terms = taxonomy_node_get_terms($node->nid);
foreach ($terms as $term) {
$output[] = array('key' => 'category',
'value' => check_plain($term->name),
'attributes' => array('domain' => url('taxonomy/term/'.$term->tid, NULL, NULL, TRUE)));
}
return $output;
}
function taxonomy_help($section) {
switch ($section) {
case 'admin/modules#description':
return t('Enables the categorization of content.');
case 'admin/taxonomy':
return t('<p>The taxonomy module allows you to classify content into categories and subcategories; it allows 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). To delete a term choose "edit term". To delete a vocabulary, and all its terms, choose "edit vocabulary".</p>');
case 'admin/taxonomy/add/vocabulary':
return t("<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 piece 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 Slashdot.org's or Kuro5hin.org's sections. For more complex implementations, you might create a hierarchical list of categories.</p>");
case 'admin/help#taxonomy':
return t('
<h3>Background</h3>
<p>Taxonomy is the study of classification. Drupal\'s taxonomy module allows you to define vocabularies which are used to classify content. The module supports hierarchical classification and association between terms, allowing for truly flexible information retrieval and classification. For more details about <a href="%classification-types">classification types</a> and insight into the development of the taxonomy module, see this <a href="%drupal-dis">drupal.org discussion</a>.</p>
<h3>An example taxonomy: food</h3>
<ul><li>Dairy<ul><li>Milk</li></ul></li><li>Drink<ul><li>Alcohol<ul><li>Beer</li><li>Wine</li></ul></li><li>Pop</li><li>Milk</li></ul></li><li>Meat<ul><li>Beef</li><li>Chicken</li><li>Lamb</li></ul></li><li>Spices<ul><li>Sugar</li></ul></li></ul>
<p><strong>Notes</strong></p><ul><li>The term <em>Milk</em> appears within both <em>Dairy</em> and <em>Drink</em>. This is an example of <em>multiple parents</em> for a term.</li><li>In Drupal the order of siblings (e.g. <em>Beef</em>, <em>Chicken</em>, <em>Lamb</em>) in a vocabulary may be controlled with the <em>weight</em> parameter.</li></ul>
<h3>Vocabularies</h3>
<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 piece 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="%slashdot">Slashdot</a>\'s sections. For more complex implementations, you might create a hierarchical list of categories such as <em>Food</em> taxonomy shown above.</p>
<h4>Setting up a vocabulary</h4>
<p>When setting up a controlled vocabulary, if you select the <em>hierarchy</em> option, you will be defining a tree structure of terms, as in a thesaurus. If you select the <em>related terms</em> option, you are allowing the definition of related terms (think <em>see also</em>), as in a thesaurus. Selecting <em>multiple select</em> will allow you to describe a piece of content using more than one term. That content will then appear on each term\'s page, increasing the chance that a user will find it.</p>
<p>When setting up a controlled vocabulary you are asked for: <ul>
<li><strong>Vocabulary name</strong>: The name for this vocabulary. Example: <em>Dairy</em>.</li>
<li><strong>Description</strong>: Description of the vocabulary. This can be used by modules and feeds.</li>
<li><strong>Types</strong>: The list of content types you want to associate this vocabulary with. Some available types are blog, book, forum, page, and story.</li>
<li><a id="related-terms"></a><strong>Related terms</strong>: Allows relationships between terms within this vocabulary. Think of these as <em>see also</em> references.</li>
<li><a id="hierarchy"></a><strong>Hierarchy</strong>: Allows a tree-like vocabulary, as in our <em>Foods</em> example above.</li>
<li><strong>Multiple select</strong>: Allows pieces of content to be described using more than one term. Content may then appear on multiple taxonomy pages.</li>
<li><strong>Required</strong>: If selected, each piece of content must have a term in this vocabulary associated with it.</li>
<li><strong>Weight</strong>: The overall weight for this vocabulary in listings with multiple vocabularies.</li>
</ul></p>
<h4>Adding terms to a vocabulary</h4>
<p>Once done defining the vocabulary, you have to add terms to it to make it useful. The options you see when adding a term to a vocabulary will depend on what you selected for <em>related terms</em>, <em>hierarchy</em> and <em>multiple select</em>. These options are:</p>
<p><ul>
<li><strong>Term name</strong>: The name for this term. Example: <em>Milk</em>.</li>
<li><strong>Description</strong>: Description of the term that may be used by modules and feeds. This is synonymous with a "scope note".</li>
<li><strong><a id="parent"></a>Parent</strong>: 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.</li>
<li><strong><a id="synonyms"></a>Synonyms</strong>: 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 vocabulary (i.e. <em>unauthorized terms</em>).</li>
<li><strong>Weight</strong>: The weight is used to sort the terms of this vocabulary.</li>
</ul></p>
<h3><a id="taxonomy-url"></a>Displaying content organized by terms</h3>
<p>In order to view the content associated with a term or a collection of terms, you should browse to a properly formed Taxonomy URL. For example, <a href="%taxo-example">taxonomy/term/1+2</a>. Taxonomy URLs always contain one or more term IDs at the end of the URL. You may learn the term ID for a given term by hovering over that term in the <a href="%taxo-overview">taxonomy overview</a> page and noting the number at the end or the URL. To build a Taxonomy URL start with "taxonomy/term/". Then list the term IDs, separated by "+" to choose content tagged with <strong>any</strong> of the given term IDs, or separated by "," to choose content tagged with <strong>all</strong> of the given term IDs. In other words, "+" is less specific than ",". Finally, you may optionally specify a "depth" in the vocabulary hierarchy. This defaults to "0", which means only the explicitly listed terms are searched. A positive number indicates the number of additional levels of the tree to search. You may also use the value "all", which means that all descendant terms are searched.</p>
<h3>RSS feeds</h3>
<p>Every term, or collection of terms, provides an <a href="%userland-rss">RSS</a> feed to which interested users may subscribe. The URL format for a sample RSS feed is <a href="%sample-rss">taxonomy/term/1+2/0/feed</a>. These are built just like <a href="%taxo-help">Taxonomy URLs</a>, but are followed by the word "feed".</p>', array('%classification-types' => 'http://en.wikipedia.org/wiki/Taxonomic_classification', '%drupal-dis' => 'http://drupal.org/node/55', '%slashdot' => 'http://slashdot.org/', '%taxo-example' => url('taxonomy/term/1+2'), '%taxo-overview' => url('admin/taxonomy'), '%userland-rss' => 'http://backend.userland.com/stories/rss', '%sample-rss' => url('taxonomy/term/1+2/feed'), '%taxo-help' => url('admin/help/taxonomy', NULL, 'taxonomy-url')));
}
}
function _taxonomy_get_tid_from_term($term) {
return $term->tid;
}
?>