--- vocabulary_list.module Sat Nov 6 00:58:14 2004 +++ vocabulary_listn.module Sun May 1 22:39:33 2005 @@ -1,145 +1,156 @@ -Displaying content within specific vocabularies -

In order to view the content associated with a vocabulary, or a collection of vocabularies, you should browse to a properly formed Vocabulary URL. For example, taxonomy/vocabulary/1+2. Vocabulary URLs always contain one or more vocabulary IDs at the end of the URL. You may learn the vocabulary ID for a given vocabulary by hovering over "edit vocabulary" in the taxonomy overview page, and noting the number at the end of the URL.

-

To build a Vocabulary URL, start with "taxonomy/vocabulary/". Then list the vocabulary IDs, separated by "+" to choose content tagged with terms within any of the given vocabulary IDs, or separated by "," to choose content tagged with terms within all of the given vocabulary IDs. In other words, "+" is less specific than ",". You may optionally specify a "depth" in the taxonomy tree hierarchy. This defaults to "1", which means only nodes tagged with top-level terms within the vocabulary are listed. A positive number indicates the number of additional levels of the taxonomy tree to search. You may also use the value "all", which means that all terms within a vocabulary are searched.

-

RSS feeds

-

Every vocabulary, or collection of vocabularies, provides an RSS feed to which interested users may subscribe. The URL format for a sample RSS feed is taxonomy/vocabulary/1+2/0/feed. These are built just like -Vocabulary URLs, but are followed by the word "feed".

', array('%vocab-example' => url('taxonomy/vocabulary/1+2'), '%taxo-overview' => url('admin/taxonomy'), '%userland-rss' => 'http://backend.userland.com/stories/rss', '%sample-rss' => url('taxonomy/vocabulary/1+2/feed'), '%vocab-help' => url('admin/help/vocabulary_list', NULL, 'vocabulary-url'))); - } -} - -/** - * Implementation of hook_menu(). - */ -function vocabulary_list_menu($may_cache) { - $items = array(); - - if ($may_cache) { - $items[] = array('path' => 'taxonomy/vocabulary', 'title' => t('vocabulary'), - 'callback' => 'vocabulary_term_page', - 'access' => user_access('access content'), - 'type' => MENU_CALLBACK); - } - - return $items; -} - -/** - * Menu callback; displays all nodes associated with a vocabulary. - */ -function vocabulary_term_page($str_vids = '', $depth = 0, $op = 'page') { - if (preg_match('/^([0-9]+[+ ])+[0-9]+$/', $str_vids)) { - $operator = 'or'; - // The '+' character in a query string may be parsed as ' '. - $vids = preg_split('/[+ ]/', $str_vids); - } - else if (preg_match('/^([0-9]+,)*[0-9]+$/', $str_vids)) { - $operator = 'and'; - $vids = explode(',', $str_vids); - } - else { - drupal_not_found(); - } - - if ($vids) { - // Build title: - $result = db_query('SELECT name FROM {vocabulary} WHERE vid IN (%s)', implode(',', $vids)); - $names = array(); - while ($vocab = db_fetch_object($result)) { - $names[] = $vocab->name; - } - $title = implode(', ', $names); - - switch ($op) { - case 'page': - drupal_set_html_head(''); - - $output = taxonomy_render_nodes(_vocabulary_select_nodes($vids, $operator, $depth, TRUE)); - print theme('page', $output, $title); - break; - - case 'feed': - $vocab = taxonomy_get_vocabulary($vids[0]); - $channel['link'] = url('taxonomy/vocabulary/'. $str_vids .'/'. $depth, NULL, NULL, TRUE); - $channel['title'] = variable_get('site_name', 'drupal') .' - '. $title; - $channel['description'] = $vocab->description; - - $result = _vocabulary_select_nodes($vids, $operator, $depth, FALSE); - node_feed($result, $channel); - break; - default: - drupal_not_found(); - } - } -} - -/** - * Finds all nodes that match selected taxonomy conditions. - * - * @param $vids - * An array of vocabulary 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". - * @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. - */ -function _vocabulary_select_nodes($vids = array(), $operator = 'or', $depth = 0, $pager = TRUE) { - if (count($vids) > 0) { - // For each vocabulary ID, generate an array of descendant taxonomy term IDs to the right depth. - $descendant_tids = array(); - if ($depth === 'all') { - $depth = NULL; - } - else if ($depth === 0) { - $depth = 1; - } - foreach ($vids as $index => $vid) { - $tree = taxonomy_get_tree($vid, 0, -1, $depth); - $descendant_tids[] = array_merge(array($vid), 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.created 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), n.sticky, n.created 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; - } - - 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; -} - -?> +Displaying content within specific vocabularies +

In order to view the content associated with a vocabulary, or a collection of vocabularies, you should browse to a properly formed Vocabulary URL. For example, taxonomy/vocabulary/1+2. Vocabulary URLs always contain one or more vocabulary IDs at the end of the URL. You may learn the vocabulary ID for a given vocabulary by hovering over "edit vocabulary" in the taxonomy overview page, and noting the number at the end of the URL.

+

To build a Vocabulary URL, start with "taxonomy/vocabulary/". Then list the vocabulary IDs, separated by "+" to choose content tagged with terms within any of the given vocabulary IDs, or separated by "," to choose content tagged with terms within all of the given vocabulary IDs. In other words, "+" is less specific than ",". You may optionally specify a "depth" in the taxonomy tree hierarchy. This defaults to "1", which means only nodes tagged with top-level terms within the vocabulary are listed. A positive number indicates the number of additional levels of the taxonomy tree to search. You may also use the value "all", which means that all terms within a vocabulary are searched.

+

RSS feeds

+

Every vocabulary, or collection of vocabularies, provides an RSS feed to which interested users may subscribe. The URL format for a sample RSS feed is taxonomy/vocabulary/1+2/0/feed. These are built just like +Vocabulary URLs, but are followed by the word "feed".

', array('%vocab-example' => url('taxonomy/vocabulary/1+2'), '%taxo-overview' => url('admin/taxonomy'), '%userland-rss' => 'http://backend.userland.com/stories/rss', '%sample-rss' => url('taxonomy/vocabulary/1+2/feed'), '%vocab-help' => url('admin/help/vocabulary_list', NULL, 'vocabulary-url'))); + } +} + +/** + * Implementation of hook_menu(). + */ +function vocabulary_list_menu($may_cache) { + $items = array(); + + if ($may_cache) { + $items[] = array('path' => 'taxonomy/vocabulary', 'title' => t('vocabulary'), + 'callback' => 'vocabulary_term_page', + 'access' => user_access('access content'), + 'type' => MENU_CALLBACK); + } + + return $items; +} + +/** + * Menu callback; displays all nodes associated with a vocabulary. + */ +function vocabulary_term_page($str_vids = '', $depth = 0, $op = 'page') { + if (preg_match('/^([0-9]+[+ ])+[0-9]+$/', $str_vids)) { + $operator = 'or'; + // The '+' character in a query string may be parsed as ' '. + $vids = preg_split('/[+ ]/', $str_vids); + } + else if (preg_match('/^([0-9]+,)*[0-9]+$/', $str_vids)) { + $operator = 'and'; + $vids = explode(',', $str_vids); + } + else { + drupal_not_found(); + } + + // Needed for '+' to show up in RSS discovery URLs + $rss_vids = urlencode($str_vids); + + if ($vids) { + // Build title: + $result = db_query('SELECT name FROM {vocabulary} WHERE vid IN (%s)', implode(',', $vids)); + $names = array(); + while ($vocab = db_fetch_object($result)) { + $names[] = $vocab->name; + } + if ($names) { + drupal_set_title($title = implode(', ', $names)); + + switch ($op) { + case 'page': + drupal_set_html_head(''); + + $output = taxonomy_render_nodes(_vocabulary_select_nodes($vids, $operator, $depth, TRUE)); + $output .= theme('xml_icon', url("taxonomy/vocabulary/$rss_vids/$depth/feed")); + print theme('page', $output); + break; + + case 'feed': + $vocab = taxonomy_get_vocabulary($vids[0]); + $channel['link'] = url('taxonomy/vocabulary/'. $str_vids .'/'. $depth, NULL, NULL, TRUE); + $channel['title'] = variable_get('site_name', 'drupal') .' - '. $title; + $channel['description'] = $vocab->description; + + $result = _vocabulary_select_nodes($vids, $operator, $depth, FALSE); + node_feed($result, $channel); + break; + default: + drupal_not_found(); + } + } + else { + drupal_not_found(); + } + } +} + +/** + * Finds all nodes that match selected vocabulary conditions. + * + * @param $vids + * An array of vocabulary 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". + * @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. + */ +function _vocabulary_select_nodes($vids = array(), $operator = 'or', $depth = 0, $pager = TRUE) { + if (count($vids) > 0) { + // For each vocabulary ID, generate an array of descendant taxonomy term IDs to the right depth. + $descendant_tids = array(); + if ($depth === 'all') { + $depth = NULL; + } + else if ($depth === 0) { + $depth = 1; + } + foreach ($vids as $index => $vid) { + $tree = taxonomy_get_tree($vid, 0, -1, $depth); + $descendant_tids[] = array_map('_taxonomy_get_tid_from_term', $tree); + } + + if ($operator == 'or') { + $str_tids = implode(',', call_user_func_array('array_merge', $descendant_tids)); + $sql = 'SELECT 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(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 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(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; +} + +?> +