Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

518 lines (469 sloc) 16.215 kb
<?php
/**
* Implements hook_help().
*/
function tagadelic_help($path, $arg) {
switch ($path) {
case 'admin/help#tagadelic':
return t('Tagadelic offers dynamic urls. <br/>Visit example.com/tagadelic/list/2,1,5 to get the vocabularies 2,1 and 5 listed as tag groups. <br/>Visit example.com/tagadelic/chunk/2,1,5 to get a tag cloud of the terms in the vocabularies 2,1 and 5.<br/> Note that we limit to five vocabularies.');
}
}
/**
* Implements hook_init().
*/
function tagadelic_init() {
drupal_add_css(drupal_get_path('module', 'tagadelic') .'/tagadelic.css');
}
/**
* Implements hook_menu().
*/
function tagadelic_menu() {
$items = array();
$items['admin/settings/tagadelic'] = array(
'title' => 'Tagadelic configuration',
'description' => 'Configure the tag clouds. Set the order, the number of tags, and the depth of the clouds.',
'page callback' => 'drupal_get_form',
'page arguments' => array('tagadelic_settings'),
'access callback' => 'user_access',
'access arguments' => array('administer taxonomy'),
);
$items['tagadelic'] = array(
'title' => 'Tags',
'page callback' => 'tagadelic_page_chunk',
'page arguments' => array(NULL),
'access callback' => 'user_access',
'access arguments' => array('access content'),
'type' => MENU_SUGGESTED_ITEM,
);
$items['tagadelic/list/%tagadelic_vocs'] = array(
'title callback' => 'tagadelic_page_title_callback',
'title arguments' => array(2),
'page callback' => 'tagadelic_page_list',
'page arguments' => array(2),
'access callback' => 'user_access',
'access arguments' => array('access content'),
'type' => MENU_CALLBACK,
);
$items['tagadelic/chunk/%tagadelic_vocs'] = array(
'title callback' => 'tagadelic_page_title_callback',
'title arguments' => array(2),
'page callback' => 'tagadelic_page_chunk',
'page arguments' => array(2),
'access callback' => 'user_access',
'access arguments' => array('access content'),
'type' => MENU_SUGGESTED_ITEM,
);
return $items;
}
/**
* Implements hook_nodeapi().
*
* You will have a nice variable in $node available for processing tags!
*/
function tagadelic_nodeapi(&$node, $op, $teaser, $page) {
if ($op == 'load') {
$node->tags = tagadelic_node_get_terms($node);
}
}
/**
* Menu callback. Admin setting page for tagadelic.
*/
function tagadelic_settings() {
$options = array('weight,asc' => t('by weight, ascending'), 'weight,desc' => t('by weight, descending'), 'title,asc' => t('by title, ascending'), 'title,desc' => t('by title, descending'), 'random,none' => t('random'));
$form['tagadelic_sort_order'] = array(
'#type' => 'radios',
'#title' => t('Tagadelic sort order'),
'#options' => $options,
'#default_value' => variable_get('tagadelic_sort_order', 'title,asc'),
'#description' => t('Determines the sort order of the tags on the freetagging page.'),
);
$form['tagadelic_page_amount'] = array(
'#type' => 'textfield',
'#size' => 5,
'#title' => t('Amount of tags on the pages'),
'#default_value' => variable_get('tagadelic_page_amount', '60'),
'#description' => t('The amount of tags that will show up in a cloud on the pages. Amount of tags in blocks must be configured in the block settings of the various cloud blocks.'),
);
$form['tagadelic_levels'] = array(
'#type' => 'textfield',
'#size' => 5,
'#title' => t('Number of levels'),
'#default_value' => variable_get('tagadelic_levels', 6),
'#description' => t('The number of levels between the least popular tags and the most popular ones. Different levels will be assigned a different class to be themed in tagadelic.css'),
);
return system_settings_form($form);
}
/**
* Menu wildcard callback.
*/
function tagadelic_vocs_load($vocs) {
$parsed_vocs = array();
if (is_numeric($vocs)) {
$parsed_vocs = array($vocs);
}
elseif (preg_match('/^([0-9]+,){1,5}[0-9]+$/', $vocs)) {
$parsed_vocs = explode(',', $vocs);
}
return $parsed_vocs;
}
/**
* Menu callback to render the tagadelic title.
*
* @param $vocs
* An array of taxonomy vocabulary ids.
*/
function tagadelic_page_title_callback($vocs) {
$title = '';
if (empty($vocs)) {
$title = t('Tags');
}
else {
$title = t('Tags in @vocabularies', array('@vocabularies' => theme('tagadelic_list_vocs', $vocs)));
}
return $title;
}
/**
* Theme function that creates a comma separated list of vocabulary terms.
*
* @params $vocs
* An array of taxonomy vocabulary ids.
*
* @ingroup themable
*/
function theme_tagadelic_list_vocs($vocs) {
$voc_names = array();
foreach ($vocs as $vid) {
$vocabulary = taxonomy_vocabulary_load($vid);
if (!empty($vocabulary)) {
$voc_names[] = $vocabulary->name;
}
}
return join(', ', $voc_names);
}
/**
* Menu callback renders a tagadelic page.
*/
function tagadelic_page_chunk($vocs) {
if ($vocs == NULL) {
foreach (taxonomy_get_vocabularies(NULL) as $vocabulary) {
$vocs[] = $vocabulary->vid;
}
}
$tags = tagadelic_get_weighted_tags($vocs, variable_get('tagadelic_levels', 6), variable_get('tagadelic_page_amount', '60'));
$tags = tagadelic_sort_tags($tags);
$output = theme('tagadelic_weighted', $tags);
if (!$output) {
return drupal_not_found();
}
$output = "<div class=\"wrapper tagadelic\">$output</div>";
return $output;
}
/**
* Menu callback renders a tagadelic page with listed items: each vocabulary.
*/
function tagadelic_page_list($vocs) {
$output = '';
if ($vocs == NULL) {
return drupal_not_found();
}
foreach ($vocs as $vid) {
$vocabulary = taxonomy_vocabulary_load($vid);
if (!empty($vocabulary)) {
// Clean out vocabulary, so that we don't have to leave security to our
// theme layer.
$vocabulary->description = filter_xss_admin($vocabulary->description);
$vocabulary->name = filter_xss_admin($vocabulary->name);
$tags = tagadelic_get_weighted_tags(array($vocabulary->vid), variable_get('tagadelic_levels', 6), variable_get('tagadelic_page_amount', '60'));
$tags = tagadelic_sort_tags($tags);
$output .= theme('tagadelic_list_box', $vocabulary, $tags);
}
}
if (empty($output)) {
return drupal_not_found();
}
$stylesheet = drupal_get_path('module', 'tagadelic') .'/tagadelic.css';
drupal_add_css($stylesheet, 'all');
$output = "<div class=\"wrapper tagadelic\">$output</div>";
return $output;
}
/**
* API that returns a multidimensional array with tags given a node.
*
* @param $node
* A node object.
*/
function tagadelic_node_get_terms($node) {
static $vocs;
if ($terms = taxonomy_node_get_terms($node, 'tid')) {
if (!isset($vocs[$node->type])) {
$vocs[$node->type] = taxonomy_get_vocabularies($node->type);
}
$tags = array();
foreach ($terms as $tid => $term) {
if ($vocs[$node->type][$term->vid]->tags) {
$tags[$term->vid][$tid] = $term;
}
}
return $tags;
}
}
/**
* API function that returns the tags of a node in fancy titled lists.
*
* @param $node
* A node object.
*/
function tagadelic_tags_lists($node) {
if (is_array($node->tags)) {
$output = '';
foreach ($node->tags as $vid => $terms) {
$vocabulary = taxonomy_vocabulary_load($vid);
$title = l($vocabulary->name, "tagadelic/chunk/$vid");
$items = array();
foreach ($terms as $term) {
$items[] = l($term->name, taxonomy_term_path($term), array('attributes' => array('title' => t('view all posts tagged with "@tag"', array('@tag' => $term->name)))));
}
$output .= theme('item_list', $items, $title);
}
return $output;
}
}
/**
* Function that gets the information from the database, passes it along to the
* weight builder and returns these weighted tags. Note that the tags are
* unordered at this stage, hence they need ordering either by calling our api
* or by your own ordering data.
*
* @param $vids
* Vocabulary ids representing the vocabularies where you want the tags from.
* @param $steps
* The amount of tag-sizes you will be using. If you give "12" you sill get
* six different "weights". Defaults to 6 and is optional.
* @return
* An <em>unordered</em> array with tags-objects, containing the attribute
* $tag->weight.
*/
function tagadelic_get_weighted_tags($vids, $steps = 6, $size = 60) {
$tags = array();
// Build the options so we can cache multiple versions.
global $language;
$options = implode('_',$vids) .'_'. $language->language .'_'. $steps .'_'. $size;
// Check if the cache exists.
$cache_name = 'tagadelic_cache_'. $options;
$cache = cache_get($cache_name, 'cache_page');
// Make sure cache has data.
if (isset($cache->data)) {
$tags = $cache->data;
}
else {
if (!is_array($vids) || count($vids) == 0) {
return array();
}
$result = db_query_range(db_rewrite_sql('SELECT COUNT(*) AS count, td.tid, td.vid, td.name, td.description FROM {term_data} td INNER JOIN {term_node} tn ON td.tid = tn.tid INNER JOIN {node} n ON tn.vid = n.vid WHERE td.vid IN ('. db_placeholders($vids) .') AND n.status = 1 GROUP BY td.tid, td.vid, td.name, td.description HAVING COUNT(*) > 0 ORDER BY count DESC'), $vids, 0, $size);
$tags = tagadelic_build_weighted_tags($result, $steps);
cache_set($cache_name, $tags, 'cache_page', CACHE_TEMPORARY);
}
return $tags;
}
/**
* API that returns an array with weighted tags.
*
* This is the hard part. People with better ideas are very very welcome to send
* these to ber@webschuur.com. Distribution is one thing that needs attention.
*
* @param $result
* A query result, any query result that contains an <em>object</em> with the
* following attributes: $tag->count, $tag->tid, $tag->name and $tag->vid.
* Refer to tagadelic_get_weighted_tags() for an example.
* @param $steps
* The amount of tag-sizes you will be using. If you give "12" you sill get
* six different "weights". Defaults to 6 and is optional.
*
* @return
* An <em>unordered</em> array with tags-objects, containing the attribute
* $tag->weight.
*/
function tagadelic_build_weighted_tags($result, $steps = 6) {
// Find minimum and maximum log-count. By our MatheMagician Steven Wittens aka
// UnConeD.
$tags = array();
$min = 1e9;
$max = -1e9;
while ($tag = db_fetch_object($result)) {
$tag->number_of_posts = $tag->count;
$tag->count = log($tag->count);
$min = min($min, $tag->count);
$max = max($max, $tag->count);
$tags[$tag->tid] = $tag;
}
// Note: we need to ensure the range is slightly too large to make sure even
// the largest element is rounded down.
$range = max(.01, $max - $min) * 1.0001;
foreach ($tags as $key => $value) {
$tags[$key]->weight = 1 + floor($steps * ($value->count - $min) / $range);
}
return $tags;
}
/**
* API function to order a set of tags.
*
* @todo
* If you feel like making this more modular, please send me patches.
**/
function tagadelic_sort_tags($tags) {
list($sort, $order) = explode(',', variable_get('tagadelic_sort_order', 'title,asc'));
switch ($sort) {
case 'title':
usort($tags, "_tagadelic_sort_by_title");
break;
case 'weight':
usort($tags, "_tagadelic_sort_by_weight");
break;
case 'random':
shuffle($tags);
break;
}
if ($order == 'desc') {
$tags = array_reverse($tags);
}
return $tags;
}
/**
* Callback for usort, sort by count.
*/
function _tagadelic_sort_by_title($a, $b) {
return strnatcasecmp($a->name, $b->name);
}
/**
* Callback for usort, sort by weight.
*/
function _tagadelic_sort_by_weight($a, $b) {
if ($a->weight == $b->weight) {
// Ensure correct order when same weight
return $a->count > $b->count;
}
return $a->weight > $b->weight;
}
/**
* Theme function that renders the HTML for the tags.
*
* @ingroup themable
*/
function theme_tagadelic_weighted($terms) {
$output = '';
foreach ($terms as $term) {
$output .= l($term->name, taxonomy_term_path($term), array(
'attributes' => array(
'class' => "tagadelic level$term->weight",
'rel' => 'tag',
'title' => $term->description,
)
)
) ." \n";
}
return $output;
}
/**
* Theme function that renders an entry in tagadelic/list/ views.
*
* @param $vocabulary
* A full vocabulary object.
* @param $tags
* An array with weigthed tag objects.
*
* @ingroup themable
*/
function theme_tagadelic_list_box($vocabulary, $tags) {
$output = '';
$content = theme('tagadelic_weighted', $tags);
if ($vocabulary->description) {
$content = theme("box", NULL, $vocabulary->description) . $content;
}
$output .= theme('box', $vocabulary->name, $content);
return $output;
}
/**
* Theme function to provide a more link.
*
* @param $vid
* Vocabulary id for which more link is wanted. Optional, if left empty, no
* vocabulary is expected, and the more-link will point to the main tagadelic
* page at /tagadelic instead.
*
* @ingroup themable
*/
function theme_tagadelic_more($vid = NULL) {
return "<div class='more-link'>". l(t('more tags'), $vid ? "tagadelic/chunk/$vid" : "tagadelic") ."</div>";
}
/**
* Implements hook_block().
*/
function tagadelic_block($op = 'list', $delta = 0, $edit = array()) {
$blocks = array();
if ($op == 'view') {
if ($voc = taxonomy_vocabulary_load($delta)) {
$blocks['subject'] = variable_get('tagadelic_block_title_'. $delta, t('Tags in @voc', array('@voc' => $voc->name)));
$tags = tagadelic_get_weighted_tags(array($voc->vid), variable_get('tagadelic_levels', 6), variable_get('tagadelic_block_tags_'. $delta, 12));
$tags = tagadelic_sort_tags($tags);
// Return a chunk of 12 tags
$blocks['content'] = theme('tagadelic_weighted', $tags);
if (count($tags) >= variable_get('tagadelic_block_tags_'. $delta, 12)) {
// Add more link
$blocks['content'] .= theme('tagadelic_more', $voc->vid);
}
}
elseif ($delta == 'all') {
$blocks['subject'] = t('Tags');
$tags = tagadelic_get_weighted_tags(array_keys(taxonomy_get_vocabularies()), variable_get('tagadelic_levels', 6), variable_get('tagadelic_block_tags_'. $delta, 12));
$tags = tagadelic_sort_tags($tags);
$blocks['content'] = theme('tagadelic_weighted', $tags);
if (count($tags) >= variable_get('tagadelic_block_tags_'. $delta, 12)) {
// Add more link
$blocks['content'] .= theme('tagadelic_more');
}
}
elseif (arg(0) == 'node' && is_numeric(arg(1)) && $node = node_load(arg(1))) {
$blocks['subject'] = t('Tags for @title', array('@title' => $node->title));
$blocks['content'] = tagadelic_tags_lists($node);
}
return $blocks;
}
elseif ($op == 'list') {
foreach (taxonomy_get_vocabularies() as $voc) {
$blocks[$voc->vid]['info'] = t('Tags in @voc', array('@voc' => $voc->name));
$blocks[$voc->vid]['cache'] = BLOCK_CACHE_GLOBAL;
}
$blocks[0]['info'] = t('Tags for the current post');
$blocks[0]['cache'] = BLOCK_CACHE_PER_PAGE;
$blocks['all']['info'] = t('Tags for all vocabularies');
$blocks['all']['cache'] = BLOCK_CACHE_GLOBAL;
return $blocks;
}
elseif ($op == 'configure') {
$voc = taxonomy_vocabulary_load($delta);
$form = array();
$form['tags'] = array(
'#type' => 'textfield',
'#title' => t('Tags to show'),
'#default_value' => variable_get('tagadelic_block_tags_'. $delta, 12),
'#maxlength' => 3,
'#description' => t('The number of tags to show in this block.'),
);
return $form;
}
elseif ($op == 'save') {
variable_set('tagadelic_block_tags_'. $delta, $edit['tags']);
return;
}
}
/**
* Implements hook_theme().
*/
function tagadelic_theme() {
return array(
'tagadelic_list_box' => array('arguments' => array('vocabulary' => NULL, 'tags' => NULL)),
'tagadelic_more' => array('arguments' => array('vid' => NULL)),
'tagadelic_weighted' => array('arguments' => array('terms' => NULL)),
'tagadelic_list_vocs' => array('arguments' => array('vid' => NULL))
);
}
Jump to Line
Something went wrong with that request. Please try again.