community_tags.module in Community Tags 6.2
Same filename and directory in other branches
Implements community tagging of nodes using a specific vocabulary for Drupal v6.x
File
community_tags.moduleView source
<?php
/**
* @file
* Implements community tagging of nodes using a specific vocabulary for Drupal v6.x
*/
/**
* Display modes.
*/
define('COMMUNITY_TAGS_MODE_BLOCK', 0);
define('COMMUNITY_TAGS_MODE_TAB', 1);
define('COMMUNITY_TAGS_MODE_INLINE', 2);
define('COMMUNITY_TAGS_MODE_NONE', 3);
define('COMMUNITY_TAGS_MODE_HIDE_TERMS_PAGE', 1);
define('COMMUNITY_TAGS_MODE_HIDE_TERMS_TEASER', 2);
/**
* Operation modes.
*/
define('COMMUNITY_TAGS_OPMODE_NOSYNC', 0x0);
define('COMMUNITY_TAGS_OPMODE_DELETE_ORPHAN_TERMS', 0x2);
/**
* Implementation of hook_help().
*/
function community_tags_help($path, $arg) {
switch ($path) {
case 'admin/settings/community-tags':
return t('To set up community tagging, you must first <a href="@taxonomy">create a normal free tagged vocabulary</a>. Then activate community tagging on such a vocabulary below, and set the <a href="@workflow">workflow options</a> for node types to control how users can tag nodes.', array(
'@taxonomy' => url('admin/content/taxonomy'),
'@workflow' => url('admin/content/types'),
));
break;
}
}
/**
* Implementation of hook_theme().
*/
function community_tags_theme() {
return array(
'community_tags_form' => array(
'arguments' => array(
'form' => NULL,
),
'file' => 'community_tags.pages.inc',
),
'community_tags' => array(
'arguments' => array(
'tags' => NULL,
),
),
'community_tags_links' => array(
'arguments' => array(
'tags' => NULL,
),
),
'community_tags_settings' => array(
'arguments' => array(
'element' => NULL,
),
),
'community_tags_tag_mgmt' => array(
'arguments' => array(
'node' => NULL,
),
),
);
}
/**
* Implementation of hook_menu().
*/
function community_tags_menu() {
$items = array();
$items['admin/settings/community-tags'] = array(
'title' => 'Community tags',
'description' => 'Configure community tagging.',
'page callback' => 'community_tags_settings',
'access arguments' => array(
'administer site configuration',
),
'file' => 'community_tags.admin.inc',
);
$items['admin/settings/community-tags/default'] = array(
'title' => 'Community tags settings',
'description' => 'Configure community tagging.',
'page callback' => 'community_tags_settings',
'access arguments' => array(
'administer site configuration',
),
'file' => 'community_tags.admin.inc',
'type' => MENU_DEFAULT_LOCAL_TASK,
);
$items['admin/settings/community-tags/%taxonomy_vocabulary/%'] = array(
// 'title' => 'Community tags',
'title callback' => 'community_tags_sub_settings_title',
'title arguments' => array(
3,
4,
),
'description' => 'Configure community tagging for vocabulary and content type.',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'community_tags_sub_settings',
3,
4,
),
'access arguments' => array(
'administer site configuration',
),
'file' => 'community_tags.admin.inc',
);
$items['admin/settings/community-tags/ops/broken'] = array(
'title' => 'Delete broken community tags',
'description' => 'Delete broken community tags.',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'community_tags_delete_broken_tags_form',
),
'access arguments' => array(
'administer site configuration',
),
'type' => MENU_CALLBACK,
'file' => 'community_tags.admin.inc',
);
$items['admin/settings/community-tags/ops/purge/%taxonomy_vocabulary'] = array(
'title' => 'Delete community tags',
'description' => 'Delete community tags.',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'community_tags_delete_all_form',
5,
),
'access arguments' => array(
'administer site configuration',
),
'type' => MENU_CALLBACK,
'file' => 'community_tags.admin.inc',
);
$items['community-tags/js/%node'] = array(
'page callback' => 'community_tags_from_js',
'page arguments' => array(
2,
),
// vid will be passed if supplied as 4th argument e.g. community-tags/js/23/2 from community_tags.js ajax call - see hook_menu().
'access callback' => 'user_access',
'access arguments' => array(
'tag content',
),
'type' => MENU_CALLBACK,
'file' => 'community_tags.ajax.inc',
);
$items['community-tags/tag/%node/%'] = array(
'title' => 'Tag Content',
'page callback' => 'community_tags_node_view',
'page arguments' => array(
2,
FALSE,
3,
),
'access callback' => 'user_access',
'access arguments' => array(
'tag content',
),
);
$items['node/%node/tag'] = array(
'title' => 'Tags',
'page callback' => 'community_tags_node_view',
'page arguments' => array(
1,
FALSE,
),
'access callback' => '_community_tags_tab_access',
'access arguments' => array(
1,
),
'type' => MENU_LOCAL_TASK,
'weight' => 2,
'file' => 'community_tags.pages.inc',
);
$items['node/%node/tagmgmt'] = array(
'title' => 'Tag Management',
'page callback' => 'community_tags_node_tag_management',
'page arguments' => array(
1,
),
'access callback' => '_community_tags_mgmt_tab_access',
'access arguments' => array(
1,
),
'type' => MENU_LOCAL_TASK,
'weight' => 3,
'file' => 'community_tags.pages.inc',
);
$items['community-tags/tagmgmtops/%/%node/%'] = array(
'title' => 'Tag Management Operation',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'community_tags_node_tag_mgmt_confirm',
3,
4,
2,
),
'access callback' => '_community_tags_mgmt_tab_access',
'access arguments' => array(
3,
),
'type' => MENU_CALLBACK,
'file' => 'community_tags.pages.inc',
);
return $items;
}
/**
* Title callback for sub-settings configuration page.
*/
function community_tags_sub_settings_title($arg1, $arg2) {
module_load_include('inc', 'community_tags', 'community_tags.admin');
return _community_tags_sub_settings_title($arg1, $arg2);
}
/**
* Implementation of hook_block().
*/
function community_tags_block($op = 'list', $delta = 0, $edit = array()) {
global $user;
switch ($op) {
case 'list':
// tagging form block should not be cached as block uses JS settings in community_tags_node_view()
$block[0] = array(
'info' => t('Community tagging form'),
'cache' => BLOCK_NO_CACHE,
);
return $block;
case 'view':
if (_community_tags_view_access()) {
if (arg(0) == 'node' && is_numeric(arg(1)) && (arg(2) == '' || arg(2) == 'view')) {
$node = menu_get_object();
if (_community_tags_is_tagging_view_visible($node, COMMUNITY_TAGS_MODE_BLOCK)) {
$block['subject'] = t('Tag this');
$block['content'] = community_tags_node_view($node, TRUE);
return $block;
}
}
}
break;
}
}
/**
* Implementation of hook_perm().
*/
function community_tags_perm() {
return array(
'tag content',
'edit own tags',
'manage tags',
'manage tags on own content',
'view tags',
);
}
/**
* Implementation of hook_nodeapi().
* Community tags hooks should be called after taxonomy module hooks - see system
* weight in community_tags.install.
*/
function community_tags_nodeapi(&$node, $op, $teaser) {
switch ($op) {
case 'load':
$node->community_tags_form = _community_tags_is_tagging_view_visible($node, COMMUNITY_TAGS_MODE_INLINE);
break;
case 'delete':
_community_tags_node_delete($node);
case 'view':
global $user;
// Show quick tag form for this node if we're on a node page view and the
// form is enabled for this node and the default quick tag vocab is set and it's not a search build.
if (!$teaser && $node->build_mode != NODE_BUILD_SEARCH_INDEX && $node->community_tags_form) {
$node->content['community_tags'] = array(
'#value' => community_tags_node_view($node, TRUE),
'#weight' => 50,
);
}
break;
case 'alter':
$hide_terms_modes = variable_get('community_tags_hide_terms_' . $node->type, array());
$hide_terms_modes = drupal_map_assoc($hide_terms_modes);
if ($teaser && isset($hide_terms_modes[COMMUNITY_TAGS_MODE_HIDE_TERMS_TEASER]) || !$teaser && isset($hide_terms_modes[COMMUNITY_TAGS_MODE_HIDE_TERMS_PAGE])) {
unset($node->taxonomy);
}
break;
}
}
/**
* Implementation of hook_link(). Add tag links to teasers etc.
*/
function community_tags_link($type, $object, $teaser = FALSE) {
$links = array();
if ($type == 'node') {
if (user_access('tag content')) {
$vids = community_tags_vids_for_node($object);
// filter out any vids that don't have trag links enabled for this content type
foreach ($vids as $vid) {
$settings = _community_tags_get_settings($vid, $object->type);
if ($teaser && empty($settings['tag_links']['teaser']) || !$teaser && empty($settings['tag_links']['full'])) {
unset($vids[$vid]);
}
}
if (count($vids) > 1) {
foreach ($vids as $vid) {
$vocabulary = taxonomy_vocabulary_load($vid);
$link_title = t('Tag this (@name)', array(
'@name' => $vocabulary->name,
));
$links['community_tag-' . $vid] = array(
'title' => $link_title,
'href' => 'community-tags/tag/' . $object->nid . '/' . $vid,
);
}
}
elseif (count($vids) == 1) {
$vid = reset($vids);
$links['community_tag-' . $vid] = array(
'title' => t('Tag this'),
'href' => 'community-tags/tag/' . $object->nid . '/' . $vid,
);
}
}
}
return $links;
}
/**
* Implementation of hook_preprocess_type(). Allow overrides of node terms display.
*/
function community_tags_preprocess_node(&$variables) {
$settings = community_tags_get_content_type_settings($variables['type']);
if ($variables['teaser']) {
$override = $settings['community_tags_terms_teaser'];
}
elseif ($variables['page']) {
$override = $settings['community_tags_terms_page'];
}
switch ($override) {
case 'hide':
unset($variables['terms']);
break;
case 'override':
$tags = _community_tags_get_tag_counts($variables['node'], NULL, NULL);
foreach ($tags as $tag) {
$link = l($tag->name, taxonomy_term_path($tag), array(
'attributes' => array(
'rel' => 'tag',
'title' => strip_tags($tag->description),
),
));
$ct_links['taxonomy_term_' . $tag->tid] = array(
'title' => $link . '<span class="ct-count">(' . $tag->count . ')</span>',
'html' => TRUE,
);
}
drupal_add_css(drupal_get_path('module', 'community_tags') . '/community_tags.css', 'module');
$variables['terms'] = theme('links', $ct_links, array(
'class' => 'links inline ct-counts',
));
break;
default:
}
}
/**
* Implementation of hook_taxonomy().
* Handle term deletion. No need to handle vocabulary deletion term/delete
* hook is called for every term in the vocabulary before vocabulary/delete hook.
*/
function community_tags_taxonomy($op = NULL, $type = NULL, $term = NULL) {
if ($type == 'term' && $term['tid']) {
switch ($op) {
case 'delete':
// if term is deleted then remove all ctags for the term
$term = (object) $term;
_community_tags_term_delete($term);
break;
}
}
}
/**
* Implementation of hook_user().
*
* Handle user deletion.
*/
function community_tags_user($op, &$edit, &$user) {
if ($op == 'delete') {
// if user is deleted then remove all ctags for the user.
// @todo consider option of moving all tags to a "dead" user so tags are not lost
_community_tags_user_delete($user);
}
}
/**
* Implement CCK's hook_content_extra_fields().
*/
function community_tags_content_extra_fields($type_name) {
$extra = array();
if (variable_get('community_tags_display_' . $type_name, COMMUNITY_TAGS_MODE_TAB) == COMMUNITY_TAGS_MODE_INLINE) {
$extra['community_tags'] = array(
'label' => t('Community Tags'),
'description' => t('Community Tags Form'),
'weight' => 100,
);
}
return $extra;
}
/**
* Implementation of hook_form_alter().
*/
function community_tags_form_alter(&$form, &$form_state, $form_id) {
// Provide option to enable Community Tags per node type.
if ($form_id == 'node_type_form' && isset($form['#node_type']->type)) {
module_load_include('inc', 'community_tags', 'community_tags.admin');
return _community_tags_node_type_form_alter($form, $form_state, $form_id);
}
}
function community_tags_get_content_type_settings($type = NULL) {
$settings = variable_get('community_tags_content_types', array());
$defaults = array(
'community_tags_terms_page' => 'none',
'community_tags_terms_teaser' => 'none',
'ct_links_limit' => 8,
);
if ($type) {
return isset($settings[$type]) ? array_merge($defaults, $settings[$type]) : $defaults;
}
else {
return $settings;
}
}
/**
* Save community_tags term associations and counts for a given node.
*
* Do user ctags processing. If new tags added or tags deleted and synchronisation required,
* call node_save() so that other modules get to act including taxonomy.module which will create
* or destroy term node records.
*
* @param $tags_and_terms
* All the users' terms - array('tags' => array(vid1 => array($tagname1, $tagname2...), vid2 => array(...)))
* NB: may have more than 1 vocabulary.
*/
function community_tags_taxonomy_node_save($node, $tags_and_terms, $is_owner, $uid) {
// get permitted CT vocabularies
$vids = community_tags_vids_for_node($node);
// find existing terms and identify new tags
$processed_tags_and_terms = _community_tags_node_process_tags_and_terms($tags_and_terms, $vids, $node, $uid);
$user = user_load($uid);
// for each vocabulary supplied
foreach ($processed_tags_and_terms as $vid => $tags_and_terms) {
// compare existing node terms and tags to processed terms and tags - add or delete as required.
$existing_tags_and_terms = community_tags_get_user_node_tags_and_terms($user, $node, $vid);
// get new tags and terms
$new_tags_and_terms = _community_tags_diff_tags_and_terms($tags_and_terms, $existing_tags_and_terms);
// get removed tags and terms - a removed tag may be one that is removed whilst pending moderation.
$removed_tags_and_terms = _community_tags_diff_tags_and_terms($existing_tags_and_terms, $tags_and_terms);
// add tags and terms
community_tags_tag($node, $user, $vid, $new_tags_and_terms);
// remove tags and terms
community_tags_untag($node, $user, $vid, $removed_tags_and_terms);
}
}
function _community_tags_diff_tags_and_terms($tags_and_terms1, $tags_and_terms2) {
$terms = array_diff_key($tags_and_terms1['terms'], $tags_and_terms2['terms']);
$tags = array_diff($tags_and_terms1['new tags'], $tags_and_terms2['new tags']);
return array(
'terms' => $terms,
'new tags' => $tags,
);
}
function _community_tags_get_display_handlers() {
static $handlers;
if (!$handlers) {
$handlers = array(
'none' => array(
'id' => 'none',
'title' => t('None'),
'fn' => '_community_tags_display_handler_none',
),
'links' => array(
'id' => 'links',
'title' => t('Links'),
'fn' => '_community_tags_display_handler_links',
),
);
if (module_exists('tagadelic')) {
$handlers['tagadelic'] = array(
'id' => 'tagadelic',
'title' => t('Tagadelic'),
'fn' => '_community_tags_display_handler_tagadelic',
);
}
}
return $handlers;
}
/**
* Get handler options for admin form. Interim measure pending pluggable display handlers.
*/
function _community_tags_get_display_handler_options() {
$options = array();
foreach (_community_tags_get_display_handlers() as $key => $handler) {
$options[$key] = $handler['title'];
}
return $options;
}
/**
* Perhaps extend with ctools.
* Return configured display handler or default to 'links' if configured handler not available.
*/
function _community_tags_get_display_handler($vid, $content_type, $inline = TRUE) {
// get settings
$settings = _community_tags_get_settings($vid, $content_type);
// get all handlers
$handlers = _community_tags_get_display_handlers();
return isset($handlers[$settings['display_handler']]) ? $handlers[$settings['display_handler']] : $handlers['links'];
}
/**
* No all tag display.
*/
function _community_tags_display_handler_none() {
return;
}
/**
* Display all tags as simple links.
*/
function _community_tags_display_handler_links($node, $vid) {
$tags = _community_tags_get_tag_counts($node, NULL, NULL, $vid);
return theme('community_tags_links', $tags);
}
/**
* Display all tags using tagadelic. Only called if tagadelic module is enabled. See _community_tags_get_tag_result() for definitions
* of $type and the arguments.
*/
function _community_tags_display_handler_tagadelic($node, $vid) {
$result = _community_tags_get_tag_counts($node, NULL, NULL, $vid, array(
'dbresult' => TRUE,
));
$weighted_tags = tagadelic_build_weighted_tags($result);
$sorted_tags = tagadelic_sort_tags($weighted_tags);
return theme('community_tags', $sorted_tags);
}
/**
* Community tags callback for node view.
*
* chaps2 - implemented multiple vocabularies base on patch at #199936.
* @todo refactor to allow use of block cache
*/
function community_tags_node_view($node, $inline = TRUE, $vid = NULL) {
global $user;
// restrict access to view tags at least
if (!_community_tags_view_access()) {
return FALSE;
}
if (is_numeric($node)) {
$node = node_load($node);
}
// Guard against duff nids and nodes. Added in response to http://drupal.org/node/331819.
if (!$node || !is_object($node)) {
return;
}
if (!$inline) {
drupal_set_title(check_plain($node->title));
}
module_load_include('inc', 'community_tags', 'community_tags.pages');
$output = '';
$vids = $vid ? array(
$vid,
) : community_tags_vids_for_node($node);
foreach ($vids as $vid) {
$tags = community_tags_get_user_node_tags($user, $node, $vid);
$display_handler = _community_tags_get_display_handler($vid, $node->type, $inline);
$cloud = call_user_func($display_handler['fn'], $node, $vid);
$names = array();
if (!user_is_logged_in()) {
$output .= drupal_get_form('community_tags_form', array(
'node' => $node,
'cloud' => $cloud,
'nid' => $node->nid,
'vid' => $vid,
'tags' => NULL,
'inline' => $inline,
'multiple' => count($vids),
));
}
else {
// TODO might want to optimise this call
if (!count($tags)) {
// User has not yet added tags to this node yet. Show form.
$output .= drupal_get_form('community_tags_form', array(
'node' => $node,
'cloud' => $cloud,
'nid' => $node->nid,
'vid' => $vid,
'tags' => NULL,
'inline' => $inline,
'multiple' => count($vids),
));
}
elseif (user_access('edit own tags')) {
// User has already tagged this node, but can edit their tags. Show form
// with the user's tags pre-populated.
$names = community_tags_flatten($tags);
$tags = taxonomy_implode_tags($tags);
$output .= drupal_get_form('community_tags_form', array(
'node' => $node,
'cloud' => $cloud,
'nid' => $node->nid,
'vid' => $vid,
'tags' => $tags,
'inline' => $inline,
'multiple' => count($vids),
));
}
else {
// Sorry, no more adding tags for you!
$output .= '<p>' . t('You have already tagged this post. Your tags: ') . theme('community_tags', $tags) . '</p>';
}
}
}
return $output;
}
/**
* Theme function to display a list of community tags via tagadelic.
*
* @ingroup themeable
*/
function theme_community_tags($tags) {
return '<div class="cloud">' . (count($tags) ? theme('tagadelic_weighted', $tags) : t('None')) . '</div>';
}
/**
* Theme function to display a list of community tags as simple links.
*
* @ingroup themeable
*/
function theme_community_tags_links($tags) {
$output = '<ul class="links">';
foreach ($tags as $tag) {
$output .= '<li>';
$output .= l($tag->name, taxonomy_term_path($tag), array(
'id' => 'ct-link-' . $tag->tid,
));
$output .= '<span class="ct-count">(' . $tag->count . ')</span>';
$output .= '</li>';
}
$output .= '</ul>';
return $output;
}
/**
* Community tags view tags access check
*/
function _community_tags_view_access() {
return user_access('access content') && (user_access('view tags') || user_access('tag content'));
}
/**
* Community tags view tags access
*/
function _community_tags_tag_access() {
return user_access('tag content');
}
/**
* Menu access callback; Check if the user can access the 'Tags' local task on
* node pages.
*/
function _community_tags_tab_access($node) {
return _community_tags_is_tagging_view_visible($node, COMMUNITY_TAGS_MODE_TAB) && _community_tags_view_access();
}
/**
* Menu access callback; Check if the user can access the 'Tags' local task on
* node pages.
*/
function _community_tags_mgmt_tab_access($node) {
global $user;
$enabled_vids = _community_tags_vids_for_node_type($node->type);
return !empty($enabled_vids) && (user_access('manage tags') || user_access('manage tags on own content') && (isset($user->uid) && $user->uid == $node->uid));
}
/**
* Helper function for the JS tagger.
*/
function community_tags_flatten($tags) {
$names = array();
foreach ($tags as $tag) {
$names[] = $tag->name;
}
return $names;
}
/*****************************************************************************
* High level community tag ops - API.
****************************************************************************/
/**
* Perform "user tags a node" operation. This should only be called directly as
* a result of user tagging activity. Usually via the CT interface but may be
* called by other modules providing their own interface.
*
* Terms may be new terms or existing terms either previously used to tag this term or not.
*
* Allow moderation of added tags via hooks.
*
* @param $tags_and_terms array:
* "terms" => array of existing terms to add keyed by tid
* "new tags" => array of tag words to add
*/
function community_tags_tag($node, $user, $vid, $tags_and_terms) {
// Allow moderation of added tags via hooks. Modules may do what they like to tags and terms.
// Any new tags that are left will have terms created for them.
drupal_alter('community_tags_moderate_tags', $tags_and_terms, 'tag', $node, $user, $vid);
// convert new tags to new terms
if (!empty($tags_and_terms['new tags'])) {
foreach ($tags_and_terms['new tags'] as $tag_name) {
// create term.
$edit = array(
'vid' => $vid,
'name' => $tag_name,
);
// the following call may result in contrib hook_invocations
$status = taxonomy_save_term($edit);
$new_term = taxonomy_get_term($edit['tid']);
$tags_and_terms['terms'][$new_term->tid] = $new_term;
}
}
// add tags
community_tags_add_tags($node, $user, $tags_and_terms['terms']);
// invoke hooks
module_invoke_all('community_tags_tagged', $node, $user, $tags_and_terms['terms'], $vid);
}
/**
* Perform "user untags a node" operation. This should only be called directly as
* a result of user tagging activity. Usually via the CT interface but may be
* called by other modules providing their own interface.
*
* Allow moderation of added tags via hooks.
*
* @param $tags_and_terms array:
* "terms" => array of existing terms to add keyed by tid
* "new tags" => array of tag words to add
*/
function community_tags_untag($node, $user, $vid, $tags_and_terms) {
// Allow moderation of removed tags via hooks. Modules may do what they like to tags and terms.
// Exmaple use: moderator might have added extra terms that may need removing.
drupal_alter('community_tags_moderate_tags', $tags_and_terms, 'untag', $node, $user, $vid);
// remove tags
if (!empty($tags_and_terms['terms'])) {
community_tags_remove_tags($node, $user, $tags_and_terms['terms']);
}
// invoke hooks
module_invoke_all('community_tags_untagged', $node, $user, $tags_and_terms['terms'], $vid);
}
/**
* Add tags to given node, attributed to given user, for all the given terms. Other modules
* or plugins may call this to add tags as a consquence of some action that is
* not explicitly a tagging operation.
*
* @param $node
* A single node object with minimal properties of {nid, type}.
* @param $user
* A single user object with minimal properties of {uid}.
* @param $terms
* An array of term objects with minimal properties of {tid, vid}.
*/
function community_tags_add_tags($node, $user, $terms) {
foreach ($terms as $term) {
_community_tags_add_tag($node->nid, $term->tid, $user->uid);
}
// invoke hooks
module_invoke_all('community_tags_tags_added', $node, $user, $terms);
}
/**
* Remove a users' tags for specified terms from a node. Other modules
* or plugins may call this to remove tags as a consquence of some action that is
* not explicitly an un-tagging operation.
*
* @param $user
* User object. If null tags are deleted from node for all users.
* @param $terms
* Array of terms keyed on tid.
*/
function community_tags_remove_tags($node, $user, $terms, $source = 'community_tags') {
// get the set of tags that will be removed
$tags_for_removal = _community_tags_get_tags($node, $user, $terms);
// delete with general purpose delete function
$tags_removed_count = _community_tags_delete_tags($node, $user, $terms);
// invoke hooks
module_invoke_all('community_tags_tags_removed', $node, $user, $terms, $source, $tags_for_removal, $tags_removed_count);
return $tags_removed_count;
}
/**
* Implementation of hook_community_tags_tags_removed(). Remove redundant terms if configured to do so.
*/
function community_tags_community_tags_tags_removed($node, $user, $terms, $source, $removed_tags, $tags_removed_count) {
// check source for batch tag removal with term sync disabled
if ($source == 'community_tags:purge:no_sync') {
return;
}
// delete redundant terms
// only apply if content type/node type allows
$ctags_by_type = community_tags_tags_group_by($removed_tags, 'type');
foreach ($ctags_by_type as $type => $ctags_for_type) {
// now group by vid as logic depends on combination of vid and node type
$ctags_for_type_by_vid = community_tags_tags_group_by($ctags_for_type, 'vid');
foreach ($ctags_for_type_by_vid as $vid => $ctags_for_type_and_vid) {
if (_community_tags_is_opmode(COMMUNITY_TAGS_OPMODE_DELETE_ORPHAN_TERMS, $vid, $type)) {
// get the unique set of terms to cleanup
$ctags_for_type_and_vid_by_tid = community_tags_tags_group_by($ctags_for_type_and_vid, 'tid');
// @todo make sure this isn't too onerous - we're probably in an AJAX call here...
$tids = array_keys($ctags_for_type_and_vid_by_tid);
_community_tags_cleanup_orphaned_tags_by_tids($tids);
}
}
}
}
/*****************************************************************************
* Node (hook_nodeapi) handlers for CT.
*
* Permissions - user editing a node may cause community tags to be created
* or deleted without having explicit permission to do so.
*****************************************************************************/
/**
* Node has been deleted. Delete all community tags for the deleted node.
* Node terms will have been removed.
*/
function _community_tags_node_delete($node) {
// delete all tags for this node
community_tags_remove_tags($node, NULL, NULL, 'node:delete');
}
/*****************************************************************************
* Taxonomy hook handlers
****************************************************************************/
/**
* Term has been deleted. Delete all community tags for the deleted term.
*/
function _community_tags_term_delete($term) {
// delete all tags for this term
community_tags_remove_tags(NULL, NULL, array(
$term->tid => $term,
), 'term:delete');
}
/*****************************************************************************
* User hook handlers
****************************************************************************/
/**
* User has been deleted. Delete all user tags for the deleted user.
*/
function _community_tags_user_delete($user) {
// remove all tags for this user
community_tags_remove_tags(NULL, $user, NULL, 'user:delete');
}
/*****************************************************************************
* Orphaned term handling.
****************************************************************************/
/**
* Check for orphaned node terms and delete if required - by default doesn't.
* Provides fix for [#984462] - "When a tag is no longer attached to any nodes, (provide option to) automatically remove it from its taxonomy vocabulary"
*
* @param $tids
* Doesn't check settings.
*/
function _community_tags_cleanup_orphaned_tags_by_tids($tids) {
$count = 0;
if (!empty($tids)) {
// only delete if not ctag, not node term, not involved in relation, has no synonyms, and has no children
$results = db_query("SELECT td.* FROM term_data td\n LEFT JOIN term_hierarchy th ON th.parent = td.tid\n LEFT JOIN term_relation tr ON tr.tid1 = td.tid OR tr.tid2 = td.tid\n LEFT JOIN term_synonym ts ON ts.tid = td.tid\n LEFT JOIN term_node tn ON tn.tid = td.tid\n LEFT JOIN community_tags ct ON ct.tid = td.tid\n WHERE td.tid IN (" . db_placeholders($tids) . ")\n AND tn.tid IS NULL\n AND ct.tid IS NULL\n AND th.parent IS NULL\n AND (tr.tid1 IS NULL AND tr.tid2 IS NULL)\n AND ts.tid IS NULL", $tids);
while ($row = db_fetch_object($results)) {
_community_tags_delete_redundant_term($row->tid);
}
}
return $count;
}
/**
* @todo set flag to skip tag delete attempt in community_tags_taxonomy() invocation
*/
function _community_tags_delete_redundant_term($tid) {
// Be careful of other dependencies on taxonomy terms
// Hook community_tags_taxonomy() will be invoked which will attempt to delete
// tags for the deleted term. There will be none so a pointless step - potential to set a flag to skip.
taxonomy_del_term($tid);
}
/*****************************************************************************
* Visibility and access helpers
****************************************************************************/
/**
* Check that tagging form is configured for display for given node in given context. Does not check user access.
*
* @param $context
* Either COMMUNITY_TAGS_MODE_BLOCK, COMMUNITY_TAGS_MODE_BLOCK, or COMMUNITY_TAGS_MODE_INLINE.
*/
function _community_tags_is_tagging_view_visible($node, $context) {
if ($node && variable_get('community_tags_display_' . $node->type, COMMUNITY_TAGS_MODE_TAB) == $context) {
$vids = community_tags_vids_for_node($node);
if (!empty($vids)) {
return TRUE;
}
}
}
/**
* Check whether a given node has one or more community tagged vocabularies associated with its type.
*/
function community_tags_vids_for_node($node) {
// Allow both nids and nodes
if (is_numeric($node)) {
$node = node_load($node);
}
return _community_tags_vids_for_node_type($node->type);
}
/**
* Check whether given node type has one or more community tagged vocabularies associated with it.
*/
function _community_tags_vids_for_node_type($type) {
$settings = _community_tags_get_settings(NULL, NULL, TRUE);
$vids = array();
foreach ($settings as $vid => $settings_for_vid) {
if (!empty($settings_for_vid['types'][$type])) {
$vids[$vid] = $vid;
}
}
return $vids;
}
/**
* Check whether given node type has one or more community tagged vocabularies associated with it.
*/
function _community_tags_vids($type = NULL) {
$community_tagged = variable_get('community_tags_vocabularies', array());
if ($type) {
$result = db_query("SELECT vnt.vid FROM {vocabulary_node_types} vnt JOIN {vocabulary} v ON v.vid = vnt.vid AND v.tags = 1 WHERE vnt.type = '%s'", $type);
}
else {
$result = db_query("SELECT vnt.vid FROM {vocabulary_node_types} vnt JOIN {vocabulary} v ON v.vid = vnt.vid AND v.tags = 1");
}
$vids = array();
while ($vid = db_fetch_object($result)) {
if (isset($community_tagged[$vid->vid])) {
$vids[$vid->vid] = $vid->vid;
}
}
return $vids;
}
/**
* Determine whether such and such a CT operation mode is set for tagging in given vocabulary. Returns
* true if any of the modes is set.
*
* @param $modes
* A bitwise OR of the operation modes to test.
*
* @todo Add settings to admin screen. Is it necessary to have settings per vid / per type?
*/
function _community_tags_is_opmode($modes, $vid, $content_type) {
$settings = _community_tags_get_settings($vid, $content_type);
if ($settings) {
return $settings['opmode'] & $modes;
}
// default to keeping node terms and community tags in sync
return FALSE;
}
/**
* Get CT settings. This is more complex than it might be because the validity of
* CT settings depends on various other factors that may change after a CT configuration
* has been changed. This gaurantees that returned settings are valid so users should
* never see any broken displays. Factors that may invalidate a configuration are:
*
* - Display handler: A pluggable display handler is not available - e.g. tagadelic is disabled.
* - Vocabulary settings: A vocabulary is not set to free-tagging which is a requirement of CT.
* - Assigned content types: A content type is no longer assigned to the vocabulary.
*
*
* @return
*/
function _community_tags_get_settings($vid = NULL, $content_type = NULL, $valid = FALSE) {
static $settings, $valid_settings;
$handlers = _community_tags_get_display_handlers();
$default_display_handler = isset($handlers['tagadelic']) ? 'tagadelic' : 'links';
$default_settings = array(
'assigned' => TRUE,
'opmode' => COMMUNITY_TAGS_OPMODE_NOSYNC,
'display_handler' => $default_display_handler,
'enabled' => FALSE,
'tag_links' => array(
'teaser' => 'teaser',
),
);
if (!$settings) {
// Build list of available free-tagging vocabularies
// $valid_CT_vocabularies = _community_tags_vids();
$CT_vocabularies = variable_get('community_tags_vocabularies', array());
$result = db_query('SELECT v.vid, v.name, v.tags, nt.name type_name, nt.type
FROM {vocabulary} v
LEFT JOIN {vocabulary_node_types} vnt ON vnt.vid = v.vid
LEFT JOIN {node_type} nt ON nt.type = vnt.type
ORDER BY v.weight, v.name, nt.name');
$settings = array();
$valid_settings = array();
while ($row = db_fetch_object($result)) {
// create structure grouped on vocabulary
if (!isset($settings[$row->vid])) {
$settings[$row->vid] = array(
'name' => $row->name,
'tagging' => $row->tags,
'types' => array(),
);
}
// check if a content type is assigned
if (!empty($row->type)) {
// if there are saved settings for this combination of vocabulary and row then add them to this settings array
if (is_array($CT_vocabularies) && is_array($CT_vocabularies[$row->vid]) && !empty($CT_vocabularies[$row->vid]['types'][$row->type])) {
// provided for backwards compatibility with CT version 1
$saved_settings = $CT_vocabularies[$row->vid]['types'][$row->type];
if (!empty($CT_vocabularies[$row->vid]['is_enabled'])) {
$saved_settings['enabled'] = 1;
}
// add saved settings
$settings_for_vid_and_type = $saved_settings;
// set useful defaults that are not saved
$settings_for_vid_and_type['type_name'] = $row->type_name;
$settings_for_vid_and_type['assigned'] = TRUE;
$settings_for_vid_and_type = array_merge($default_settings, $settings_for_vid_and_type);
if ($settings[$row->vid]['tagging'] && $saved_settings['enabled']) {
$valid_settings[$row->vid]['types'][$row->type] = $settings_for_vid_and_type;
}
}
else {
$settings_for_vid_and_type = $default_settings;
$settings_for_vid_and_type['type_name'] = $row->type_name;
}
$settings[$row->vid]['types'][$row->type] = $settings_for_vid_and_type;
}
}
}
// either return from valid settings only or from all settings
$rt = $valid ? $valid_settings : $settings;
if ($vid && $content_type) {
$return = !empty($rt[$vid]['types'][$content_type]) ? $rt[$vid]['types'][$content_type] : FALSE;
return $return;
}
elseif ($vid) {
return !empty($rt[$vid]) ? $rt[$vid] : FALSE;
}
else {
return $rt;
}
}
/*****************************************************************************
* Tag/term input processors.
*****************************************************************************/
/**
* Process tags and terms - resolve tags (supplied as the tag name) to existing terms and
* identify new tags - but don't create.
*
* Give other modules a chance to have their say. E.g. unitag may replace a new tag with an existing term.
*
* @param $terms
* A data structure as processed by taxonomy_save_node. Maybe tags, terms, tids etc.
*
* @param $vids
* The valid vocabulary vids - ignore all other terms and tags
*
* @return
* An array of terms and new tags grouped by vid. Each element has the following structure:
* 'terms' => array of term objects
* 'new tags' => array of new tag names
*/
function _community_tags_node_process_tags_and_terms($tags_and_terms, $vids, $node, $uid) {
$processed_terms = array();
if (is_array($tags_and_terms)) {
foreach ($tags_and_terms as $key => $term) {
if (!is_numeric($key) && $key == 'tags') {
// tags are grouped by vid
foreach ($term as $vid => $vid_value) {
// only process ctag vocabulary tags
if (isset($vids[$vid])) {
// make sure we pass back at least an empty array for the provided vid
$processed_terms[$vid] = array(
'terms' => array(),
'new tags' => array(),
);
// handle array of tags or comma seperated list of tags
$vid_tags = is_array($vid_value) ? $vid_value : drupal_explode_tags($vid_value);
foreach ($vid_tags as $tag) {
if (empty($tag)) {
// guard against empty tag submissions
continue;
}
// See if the term exists in the chosen vocabulary
// and return the tid, otherwise, add a new record.
$matching_terms = taxonomy_get_term_by_name($tag);
$matching_term = NULL;
// tid match if any.
foreach ($matching_terms as $matching_term_it) {
if ($matching_term_it->vid == $vid) {
$matching_term = $matching_term_it;
break;
}
}
if (!$matching_term) {
$processed_terms[$vid]['new tags'][] = $tag;
}
else {
$processed_terms[$vid]['terms'][$matching_term->tid] = $matching_term;
}
}
}
}
}
else {
if (is_array($term)) {
foreach ($term as $tid) {
if ($tid) {
$term_object = taxonomy_get_term($tid);
if ($term_object && isset($vids[$term_object->vid])) {
if (!isset($processed_terms[$term_object->vid])) {
$processed_terms[$term_object->vid] = array(
'terms' => array(),
'new tags' => array(),
);
}
$processed_terms[$term_object->vid]['terms'][$tid] = $term_object;
}
}
}
}
else {
if ($term) {
$term_object = !is_object($term) ? taxonomy_get_term($term) : $term;
if ($term_object && isset($vids[$term_object->vid])) {
if (!isset($processed_terms[$term_object->vid])) {
$processed_terms[$term_object->vid] = array(
'terms' => array(),
'new tags' => array(),
);
}
$processed_terms[$term_object->vid]['terms'][$term_object->tid] = $term_object;
}
}
}
}
}
}
// invoke hooks - processed terms may be altered in any way
drupal_alter('community_tags_moderate_terms', $processed_terms, $node, $uid);
return $processed_terms;
}
/*****************************************************************************
* Query helpers
****************************************************************************/
/**
* Retrieve list of tags for a given node that belong to a user.
*/
function community_tags_get_user_node_tags($user, $node, $vid) {
$tags_and_terms = community_tags_get_user_node_tags_and_terms($user, $node, $vid);
// merge terms and new tags (i.e. have no tid) into array of tags
$tags = $tags_and_terms['terms'];
if (!empty($tags_and_terms['new tags'])) {
foreach ($tags_and_terms['new tags'] as $new_tag) {
$tags[$new_tag] = (object) array(
'name' => $new_tag,
'tid' => $new_tag,
);
}
}
return $tags;
}
/**
* Retrieve list of tags for a given node that belong to a user.
*/
function community_tags_get_user_node_tags_and_terms($user, $node, $vid) {
$tags_and_terms = array(
'terms' => array(),
'new tags' => array(),
);
$tags_and_terms['terms'] = _community_tags_get_node_user_vid_tags($node, $user, $vid);
// allow other modules to have a say
drupal_alter('community_tags_get_user_node_tags', $tags_and_terms, $user, $node, $vid);
return $tags_and_terms;
}
/**
* Retrieve list of tags for a given node and user. Includes a count of the number of users who have tagged it.
*
* @return
* Array of objects {tid, name, count} keyed on tid. The count is the number of users who share the tag.
*/
function _community_tags_get_node_user_vid_tags($node, $user, $vid) {
$tags = _community_tags_get_tag_counts($node, $user, NULL, $vid);
$tags_by_tid = array();
foreach ($tags as $tag) {
$tags_by_tid[$tag->tid] = $tag;
}
return $tags_by_tid;
}
/*****************************************************************************
* Low level community tag operations. Keep cruft out of these. For an API, wrap
* these in higher level functions that can include hook invocation, permission
* checking, configuration checks, bulk operations etc.
****************************************************************************/
/**
* Add a community tag. Nid and vid and user should be valid
*/
function _community_tags_add_tag($nid, $tid, $uid) {
$time = time();
db_query('INSERT INTO {community_tags} (tid, nid, uid, date) VALUES (%d, %d, %d, %d)', $tid, $nid, $uid, $time);
}
/**
* Remove tags from the database as specified by $node, $user, and $term.
*
* @see _communtity_tags_get_tags_where_clause().
*
* @return number of rows deleted
*/
function _community_tags_delete_tags($node, $user, $term) {
$where = _communtity_tags_get_tags_where_clause($node, $user, $term);
$where_clause = $where['where'];
$result = db_query("DELETE FROM {community_tags} WHERE {$where_clause}", $where['args']);
return db_affected_rows();
}
/*****************************************************************************
* SQL query functions.
*****************************************************************************/
/**
* Get tag counts from the database as specified by $node, $user, and $term.
*
* @param $options
* Array containing options:
* - 'dbresult' => boolean - if set will return the database query object - (required for tagadelic)
*
* @see _communtity_tags_get_tags_where_clause().
*
* @return
* Array of tag counts. Each tag is an object with properties: {tid, nid, count, vid, type}.
*/
function _community_tags_get_tag_counts($node, $user, $term, $vid = NULL, $options = array()) {
$where = _communtity_tags_get_tags_where_clause($node, $user, $term, 'ct');
$where_clause = $where['where'];
$args = $where['args'];
if ($vid) {
$args[] = $vid;
$where_clause .= " AND td.vid = %d ";
}
$sql = "SELECT ct.nid, ct.tid, count(ct.uid) count, td.vid, n.type, td.name\n FROM {community_tags} ct\n INNER JOIN {term_data} td ON td.tid = ct.tid\n INNER JOIN {node} n ON n.nid = ct.nid\n WHERE {$where_clause}\n GROUP BY ct.nid, ct.tid ORDER BY count DESC";
$result = db_query($sql, $args);
if (!empty($options['dbresult']) && $options['dbresult']) {
return $result;
}
else {
$tags = array();
while ($term = db_fetch_object($result)) {
$tags[] = $term;
}
return $tags;
}
}
/**
* Get unique tags (with counts) from the database as specified by $node, $user, and $term.
*
* @see _communtity_tags_get_tags_where_clause().
*
* @return
* Array of tags. Each tag is an object with properties: {tid, nid, uid, count, vid, type}.
*/
function _community_tags_get_tags($node, $user, $term, $vid = NULL, $options = array()) {
$where = _communtity_tags_get_tags_where_clause($node, $user, $term, '_ct');
$sub_where_clause = $where['where'];
$args = $where['args'];
if ($vid) {
$args[] = $vid;
$sub_where_clause .= " AND _td.vid = %d ";
}
$sql = "SELECT ct.nid, ct.tid, ct.uid, count(ct2.uid) count, ct.vid, ct.type, ct.name\n FROM (\n SELECT _ct.tid, _ct.nid, _ct.uid, _td.vid, _td.name, _n.type FROM {community_tags} _ct\n INNER JOIN {term_data} _td ON _td.tid = _ct.tid\n INNER JOIN {node} _n ON _n.nid = _ct.nid\n WHERE {$sub_where_clause}\n ) AS ct\n INNER JOIN {community_tags} ct2 ON ct2.tid = ct.tid AND ct2.nid = ct.nid\n GROUP BY ct.nid, ct.tid, ct.uid ORDER BY count DESC";
$result = db_query($sql, $args);
$tags = array();
while ($term = db_fetch_object($result)) {
$tags[] = $term;
}
return $tags;
}
/**
* @param $node
* null or single node object
* @param $user
* null or single user object
* @param term
* may be NULL for all terms, a single term, or an array of terms keyed on tid.
*/
function _communtity_tags_get_tags_where_clause($node, $user, $term, $table_alias = NULL) {
$where_clauses = array();
$table_alias = $table_alias ? $table_alias . '.' : '';
if (!empty($node)) {
$args[] = $node->nid;
$where_clauses[] = $table_alias . "nid = %d";
}
if (!empty($user)) {
$args[] = $user->uid;
$where_clauses[] = $table_alias . "uid = %d ";
}
if (!empty($term)) {
if (is_array($term) && count($term) > 1) {
$tids = array_keys($term);
$args = array_merge($args, $tids);
$where_clauses[] = $table_alias . "tid IN (" . db_placeholders($tids) . ") ";
}
else {
$tid = is_array($term) ? reset(array_keys($term)) : $term->tid;
$args[] = $tid;
$where_clauses[] = $table_alias . "tid = %d ";
}
}
$where_clause_str = implode(' AND ', $where_clauses);
return array(
'args' => $args,
'where' => $where_clause_str,
);
}
/**
* Helper to return the set of ctags grouped by a given property.
* @param $group_by
* Typically one of nid, tid, or uid.
*/
function community_tags_tags_group_by($ctags, $group_by) {
$grouped_ctags = array();
foreach ($ctags as $ctag) {
$grouped_ctags[$ctag->{$group_by}][] = $ctag;
}
return $grouped_ctags;
}
/**
* Clear the block cache for all users for the node page.
*/
function _community_tags_community_tags_block_cache_invalidate($node) {
static $once = FALSE;
if (!$once) {
if (_community_tags_is_tagging_view_visible($node, COMMUNITY_TAGS_MODE_BLOCK)) {
$url = url('node/' . $node->nid, array(
'absolute' => TRUE,
));
$cid = 'community_tags:0:%%:' . $url;
// only valid if block caching per user and page
db_query("DELETE FROM {cache_block} WHERE cid LIKE '%s'", $cid);
$once = TRUE;
}
}
}
function _community_tags_add_js() {
static $once = FALSE;
if (!$once) {
drupal_add_js(drupal_get_path('module', 'community_tags') . '/community_tags.js');
$once = TRUE;
}
}
function _community_tags_add_css() {
static $once = FALSE;
if (!$once) {
drupal_add_css(drupal_get_path('module', 'community_tags') . '/community_tags.css', 'module');
$once = TRUE;
}
}
/**
* Return whether user is a trusted tagger.
*/
function _community_tags_user_is_trusted_tagger($user, $node) {
return node_access('update', $node, $user);
}
Functions
Name | Description |
---|---|
community_tags_add_tags | Add tags to given node, attributed to given user, for all the given terms. Other modules or plugins may call this to add tags as a consquence of some action that is not explicitly a tagging operation. |
community_tags_block | Implementation of hook_block(). |
community_tags_community_tags_tags_removed | Implementation of hook_community_tags_tags_removed(). Remove redundant terms if configured to do so. |
community_tags_content_extra_fields | Implement CCK's hook_content_extra_fields(). |
community_tags_flatten | Helper function for the JS tagger. |
community_tags_form_alter | Implementation of hook_form_alter(). |
community_tags_get_content_type_settings | |
community_tags_get_user_node_tags | Retrieve list of tags for a given node that belong to a user. |
community_tags_get_user_node_tags_and_terms | Retrieve list of tags for a given node that belong to a user. |
community_tags_help | Implementation of hook_help(). |
community_tags_link | Implementation of hook_link(). Add tag links to teasers etc. |
community_tags_menu | Implementation of hook_menu(). |
community_tags_nodeapi | Implementation of hook_nodeapi(). Community tags hooks should be called after taxonomy module hooks - see system weight in community_tags.install. |
community_tags_node_view | Community tags callback for node view. |
community_tags_perm | Implementation of hook_perm(). |
community_tags_preprocess_node | Implementation of hook_preprocess_type(). Allow overrides of node terms display. |
community_tags_remove_tags | Remove a users' tags for specified terms from a node. Other modules or plugins may call this to remove tags as a consquence of some action that is not explicitly an un-tagging operation. |
community_tags_sub_settings_title | Title callback for sub-settings configuration page. |
community_tags_tag | Perform "user tags a node" operation. This should only be called directly as a result of user tagging activity. Usually via the CT interface but may be called by other modules providing their own interface. |
community_tags_tags_group_by | Helper to return the set of ctags grouped by a given property. |
community_tags_taxonomy | Implementation of hook_taxonomy(). Handle term deletion. No need to handle vocabulary deletion term/delete hook is called for every term in the vocabulary before vocabulary/delete hook. |
community_tags_taxonomy_node_save | Save community_tags term associations and counts for a given node. |
community_tags_theme | Implementation of hook_theme(). |
community_tags_untag | Perform "user untags a node" operation. This should only be called directly as a result of user tagging activity. Usually via the CT interface but may be called by other modules providing their own interface. |
community_tags_user | Implementation of hook_user(). |
community_tags_vids_for_node | Check whether a given node has one or more community tagged vocabularies associated with its type. |
theme_community_tags | Theme function to display a list of community tags via tagadelic. |
theme_community_tags_links | Theme function to display a list of community tags as simple links. |
_community_tags_add_css | |
_community_tags_add_js | |
_community_tags_add_tag | Add a community tag. Nid and vid and user should be valid |
_community_tags_cleanup_orphaned_tags_by_tids | Check for orphaned node terms and delete if required - by default doesn't. Provides fix for [#984462] - "When a tag is no longer attached to any nodes, (provide option to) automatically remove it from its taxonomy vocabulary" |
_community_tags_community_tags_block_cache_invalidate | Clear the block cache for all users for the node page. |
_community_tags_delete_redundant_term | @todo set flag to skip tag delete attempt in community_tags_taxonomy() invocation |
_community_tags_delete_tags | Remove tags from the database as specified by $node, $user, and $term. |
_community_tags_diff_tags_and_terms | |
_community_tags_display_handler_links | Display all tags as simple links. |
_community_tags_display_handler_none | No all tag display. |
_community_tags_display_handler_tagadelic | Display all tags using tagadelic. Only called if tagadelic module is enabled. See _community_tags_get_tag_result() for definitions of $type and the arguments. |
_community_tags_get_display_handler | Perhaps extend with ctools. Return configured display handler or default to 'links' if configured handler not available. |
_community_tags_get_display_handlers | |
_community_tags_get_display_handler_options | Get handler options for admin form. Interim measure pending pluggable display handlers. |
_community_tags_get_node_user_vid_tags | Retrieve list of tags for a given node and user. Includes a count of the number of users who have tagged it. |
_community_tags_get_settings | Get CT settings. This is more complex than it might be because the validity of CT settings depends on various other factors that may change after a CT configuration has been changed. This gaurantees that returned settings are valid so users… |
_community_tags_get_tags | Get unique tags (with counts) from the database as specified by $node, $user, and $term. |
_community_tags_get_tag_counts | Get tag counts from the database as specified by $node, $user, and $term. |
_community_tags_is_opmode | Determine whether such and such a CT operation mode is set for tagging in given vocabulary. Returns true if any of the modes is set. |
_community_tags_is_tagging_view_visible | Check that tagging form is configured for display for given node in given context. Does not check user access. |
_community_tags_mgmt_tab_access | Menu access callback; Check if the user can access the 'Tags' local task on node pages. |
_community_tags_node_delete | Node has been deleted. Delete all community tags for the deleted node. Node terms will have been removed. |
_community_tags_node_process_tags_and_terms | Process tags and terms - resolve tags (supplied as the tag name) to existing terms and identify new tags - but don't create. |
_community_tags_tab_access | Menu access callback; Check if the user can access the 'Tags' local task on node pages. |
_community_tags_tag_access | Community tags view tags access |
_community_tags_term_delete | Term has been deleted. Delete all community tags for the deleted term. |
_community_tags_user_delete | User has been deleted. Delete all user tags for the deleted user. |
_community_tags_user_is_trusted_tagger | Return whether user is a trusted tagger. |
_community_tags_vids | Check whether given node type has one or more community tagged vocabularies associated with it. |
_community_tags_vids_for_node_type | Check whether given node type has one or more community tagged vocabularies associated with it. |
_community_tags_view_access | Community tags view tags access check |
_communtity_tags_get_tags_where_clause |