similarterms.module in Similar By Terms 6
Same filename and directory in other branches
Similar By Terms module displays a block with similar content based on taxonomy terms.
File
similarterms.moduleView source
<?php
// by Jeff Robbins
/**
* @file
* Similar By Terms module displays a block with similar content
* based on taxonomy terms.
*/
/**
* Display help and module information
* @param path which path of the site we're displaying help
* @param arg array that holds the current path as would be returned from arg() function
* @return help text for the path
*/
function similarterms_help($path, $arg) {
$output = '';
switch ($path) {
case "admin/help#similarterms":
$output = '<p>' . t("Displays a block with similar content based on taxonomy terms.") . '</p>';
break;
}
return $output;
}
// function similarterms_help
/**
* Valid permissions for this module
* @return array An array of valid permissions for the similarterms module
*/
function similarterms_perm() {
return array(
'access similarterms content',
'administer similarterms content',
);
}
// function similarterms_perm()
/**
* Implementation of hook_block().
*/
function similarterms_block($op = 'list', $delta = 0, $edit = array()) {
$block = $form = array();
switch ($op) {
case 'list':
return similarterms_block_list();
case 'view':
return similarterms_block_view($delta);
case 'configure':
return similarterms_block_configure($delta);
case 'save':
similarterms_block_save($delta, $edit);
return;
}
}
/**
* Perform the "list" op for hook_block().
*
* @return
* Array of block definition.
*/
function similarterms_block_list() {
$blocks[0]['info'] = t('Similar entries from ANY vocabulary.');
$blocks[0]['cache'] = BLOCK_CACHE_PER_PAGE;
if (variable_get("similarterms_vocabularies", 'multi_select_and_tags') == 'all') {
foreach (taxonomy_get_vocabularies() as $v) {
$blocks[$v->vid]['info'] = t('Similar entries from the @vocab vocabulary.', array(
'@vocab' => $v->name,
));
$blocks[$v->vid]['cache'] = BLOCK_CACHE_PER_PAGE;
}
}
else {
foreach (taxonomy_get_vocabularies() as $v) {
// this only makes sense for multi-select vocabularies and free tagging
if ($v->multiple || $v->tags) {
$blocks[$v->vid]['info'] = t('Similar entries from the @vocab vocabulary.', array(
'@vocab' => $v->name,
));
$blocks[$v->vid]['cache'] = BLOCK_CACHE_PER_PAGE;
}
}
}
return $blocks;
}
/**
* Perform the "view" op for hook_block().
*
* @param $delta
* String specifying which block to proocess.
*
* @return
* Array of block contents and title.
*/
function similarterms_block_view($delta) {
if ($delta == 0) {
$block['subject'] = t('Similar');
$block['content'] = theme('similarterms', variable_get('similarterms_display_options', 'title_only'), similarterms_list());
}
else {
$block['subject'] = t('Similar');
$block['content'] = theme('similarterms', variable_get('similarterms_display_options', 'title_only'), similarterms_list($delta));
}
return $block;
}
/**
* Perform the "configure" op for hook_block().
*
* @param $delta
* String specifying which block to proocess.
*
* @return
* Settings form array.
*/
function similarterms_block_configure($delta = 0) {
$form['count'] = array(
'#type' => 'textfield',
'#title' => t('Item count'),
'#default_value' => variable_get('simterms_count_' . $delta, 5),
'#size' => 3,
'#description' => t('The maximum number of similar items to display'),
);
//petertj addition to configuration to permit display of current node in list
$form['showcurrentnode'] = array(
'#type' => 'checkbox',
'#title' => t('Show current node as active in the list'),
'#default_value' => variable_get('similarterms_showcurrentnode_' . $delta, FALSE),
'#required' => FALSE,
);
//mimo addition to configuration to limit to same page type
$types = array(
'0' => t('<none>'),
'1' => t('same as current'),
);
$arr_types_obj = node_get_types();
foreach ($arr_types_obj as $type => $obj) {
$types[$type] = $obj->name;
}
$form['sametype'] = array(
'#type' => 'select',
'#title' => t('Content type limit'),
'#default_value' => variable_get('simterms_sametype_' . $delta, FALSE),
'#options' => $types,
'#description' => t('Limit to pages of this or these content type(s)'),
'#multiple' => TRUE,
);
if ($delta > 0) {
$terms = array();
$tree = taxonomy_get_tree($delta);
foreach ($tree as $term) {
$terms[$term->tid] = $term->name;
}
$form['ignoreterms'] = array(
'#type' => 'select',
'#title' => t('Terms to be ignored'),
'#default_value' => variable_get('simterms_ignoreterms_' . $delta, array()),
'#options' => $terms,
'#description' => t('Ignore selected terms here from being used to search for similar entries'),
'#multiple' => TRUE,
);
}
return $form;
}
/**
* Perform the "save" op for hook_block().
*
* @param $delta
* String specifying which block to proocess.
* @param $edit
* Array containg the form input.
*
* @return
* None. Values are saved as system variables.
*/
function similarterms_block_save($delta = 0, $edit = array()) {
variable_set('simterms_count_' . $delta, $edit['count']);
variable_set('simterms_sametype_' . $delta, $edit['sametype']);
variable_set('simterms_ignoreterms_' . $delta, $edit['ignoreterms']);
variable_set('similarterms_showcurrentnode_' . $delta, $edit['showcurrentnode']);
}
/**
* Output the block
*
* @param $vocid
* integer - vocabulary id, leave out to use ALL terms for this node
* @param $nid
* integer - nid, leave out to use the current node
* @return
* an array of node objects
*/
function similarterms_list($vocid = 0, $nid = NULL) {
$lists = array();
$nodes = array();
$args = array();
$list_num = 0;
$sql = "";
$cache_lifetime = variable_get('similarterms_cache_options', 3600);
$count = variable_get('simterms_count_' . $vocid, 5);
if (arg(0) == 'node' && is_numeric(arg(1)) && !$nid) {
$nid = arg(1);
}
if ($nid != NULL) {
$cid = "{$vocid}:{$nid}";
if ($cache_lifetime) {
if ($cached = cache_get($cid, 'cache_similarterms')) {
return $cached->data;
}
}
if (variable_get('similarterms_override_options', 0)) {
$lists = similarterms_get_overrides($nid, $vocid);
if ($lists[$vocid]) {
foreach ($lists[$vocid] as $nid_list) {
if (is_numeric($nid_list)) {
if ($list_num <= $count) {
$list_num = $list_num + 1;
$nodes[] = node_load($nid_list);
}
}
}
}
}
$node_obj = node_load($nid);
if ($vocid == 0) {
$terms = array_keys(taxonomy_node_get_terms($node_obj));
}
else {
$terms = array_keys(taxonomy_node_get_terms_by_vocabulary($node_obj, $vocid));
}
// Filter out some terms
$terms_filter = variable_get('simterms_ignoreterms_' . $vocid, array());
foreach ($terms_filter as $v) {
$idx = array_search($v, $terms);
if ($idx >= 0) {
unset($terms[$idx]);
}
}
if (!empty($terms)) {
//past events
$pasts = array();
$sql = 'SELECT n.nid, n.title, COUNT(n.nid) AS ncount ';
$sql .= 'FROM {node} n ';
$sql .= 'INNER JOIN {term_node} tn ON n.vid = tn.vid ';
$sql .= 'WHERE tn.tid IN (';
$number_of_terms = count($terms);
foreach ($terms as $terms_items) {
$number_of_terms--;
if ($number_of_terms) {
$sql .= "'%s',";
}
else {
$sql .= "'%s'";
}
$args[] = $terms_items;
}
$sql .= ') ';
$types = variable_get('simterms_sametype_' . $vocid, FALSE);
if ($types !== FALSE && is_array($types) && count($types) > 0 && $types['0'] == NULL) {
if ($types[1]) {
$node_obj = node_load($nid);
$types[1] = $node_obj->type;
}
$sql .= 'AND n.type IN (';
$number_of_types = count($types);
foreach ($types as $types_items) {
$number_of_types--;
if ($number_of_types) {
$sql .= "'%s',";
}
else {
$sql .= "'%s'";
}
$args[] = $types_items;
}
$sql .= ') ';
}
//if showcurrentnode option is false (default state), create filter for query.
if (!variable_get('similarterms_showcurrentnode_' . $vocid, FALSE)) {
$sql .= 'AND n.nid != %d ';
$args[] = $nid;
}
$sql .= 'AND n.status = 1 ';
$sql .= 'AND n.moderate = 0 ';
$sql .= "AND (n.language = '' OR n.language = '%s') ";
$args[] = $node_obj->language;
$sql .= 'GROUP BY n.nid, n.title, n.created ';
if (variable_get('similarterms_ncount_options', 'default') == 'default') {
$sql .= 'ORDER BY ncount DESC, ';
}
else {
$sql .= 'ORDER BY ncount ASC, ';
}
$sql .= 'n.created DESC ';
$sql .= 'LIMIT %d';
$args[] = $count;
$sql = db_rewrite_sql($sql);
$result = db_query($sql, $args);
// watchdog('similarterms', $sql, NULL, WATCHDOG_INFO);
while ($r = db_fetch_object($result)) {
$nodes[] = node_load($r->nid);
}
// Allow modules to alter the list of nodes by implementing a hook.
// Design pattern from comment_invoke_comment().
foreach (module_implements('similarterms') as $name) {
$function = $name . '_similarterms';
$function($nodes, $node_obj);
}
if ($cache_lifetime) {
cache_set($cid, $nodes, 'cache_similarterms', time() + $cache_lifetime);
}
}
}
return $nodes;
}
/**
* Implementation of hook_flush_caches().
*/
function similarterms_flush_caches() {
return array(
'cache_similarterms',
);
}
/**
* Implementation of hook_form_alter().
*/
function similarterms_form_alter(&$form, $form_state, $form_id) {
if (isset($form['type']) && $form['type']['#value'] . '_node_form' == $form_id) {
if (!variable_get('similarterms_override_options', 0)) {
return;
}
// no need to alter form if block module is off
if (!module_exists('block')) {
return;
}
$blocks = similarterms_get_active_block_vocabularies();
// no need to alter form if no similarterms blocks are active
if (sizeof($blocks) == 0) {
return;
}
$overrides = array();
if (is_numeric($form['nid']['#value'])) {
$overrides = similarterms_get_overrides($form['nid']['#value']);
}
$form['similarterms'] = array(
'#type' => 'fieldset',
'#title' => t('Similar Terms'),
'#description' => t('Override the links generated by similar terms module.'),
'#collapsible' => 1,
'#collapsed' => sizeof($overrides) ? 0 : 1,
);
$node_type = $form['type']['#value'];
$no_similarterms = 1;
foreach (similarterms_taxonomy_get_vocabularies() as $v) {
if (!$blocks[$v->vid]) {
continue;
}
$types = variable_get('simterms_sametype_' . $v->vid, array(
'0' => '0',
));
if (!$types[$node_type] && !isset($types[0])) {
continue;
}
$no_similarterms = 0;
$form['similarterms']['similarterms_vid_' . $v->vid] = array(
'#type' => 'fieldset',
'#title' => $v->name,
'#collapsible' => 1,
'#collapsed' => sizeof($overrides[$v->vid]) ? 0 : 1,
'#tree' => 1,
);
$form['similarterms']['similarterms_vid_' . $v->vid]['similarterms_paths'] = array(
'#type' => 'fieldset',
'#title' => t('Paths'),
'#tree' => 1,
);
$count = variable_get('simterms_count_' . $v->vid, 5);
for ($i = 0; $i < $count; $i++) {
$default_value = '';
if ($overrides[$v->vid][$i]) {
$default_value = drupal_lookup_path('alias', 'node/' . $overrides[$v->vid][$i]);
if (!$default_value) {
$default_value = 'node/' . $overrides[$v->vid][$i];
}
}
$form['similarterms']['similarterms_vid_' . $v->vid]['similarterms_paths'][$i] = array(
'#type' => 'textfield',
'#title' => t('Path %d', array(
'%d' => $i + 1,
)),
'#default_value' => $default_value ? $default_value : '',
);
}
$form['similarterms']['similarterms_vid_' . $v->vid]['similarterms_override_delete'] = array(
'#type' => 'checkbox',
'#title' => t('Delete Similar Terms Overrides?'),
'#description' => t('If this option is checked all paths will be deleted for this vocabulary.'),
'#default_value' => 0,
);
}
if ($no_similarterms) {
unset($form['similarterms']);
}
}
}
/**
* This function returns a list of overrides
*/
function similarterms_get_overrides($nid, $vid = NULL) {
$paths = array();
$query = "SELECT * FROM {similarterms_override} WHERE nid = '%s'";
$args = array(
$nid,
);
if ($vid) {
$query .= " AND vid = %s";
$args[] = $vid;
}
$result = db_query($query, $args);
while ($object = db_fetch_object($result)) {
$paths[$object->vid][] = $object->path;
}
return $paths;
}
/**
* Implementation of hook_nodeapi().
*/
function similarterms_nodeapi($node, $op, $arg = 0) {
switch ($op) {
case 'delete':
similarterms_node_delete($node);
break;
case 'insert':
case 'update':
similarterms_node_save($node);
break;
case 'validate':
similarterms_node_validate($node);
break;
}
}
/**
* Function to delete entries from overrides table when a node is deleted
*/
function similarterms_node_delete($node, $vid = NULL) {
if (!variable_get('similarterms_override_options', 0)) {
return;
}
$query = "DELETE FROM {similarterms_override} WHERE nid = %d";
$args = array(
$node->nid,
);
if ($vid) {
$query .= " AND vid = %d";
$args[] = $vid;
}
db_query($query, $args);
}
/**
* Function to populate overrides table
*/
function similarterms_node_save($node) {
if (!variable_get('similarterms_override_options', 0)) {
return;
}
$result = array();
$query = "INSERT INTO {similarterms_override} (nid, path, vid) VALUES(%d, %d, %d)";
foreach (similarterms_taxonomy_get_vocabularies() as $v) {
$vid = 'similarterms_vid_' . $v->vid;
$alias =& $node->{$vid};
similarterms_node_delete($node, $v->vid);
if ($alias['similarterms_override_delete']) {
continue;
}
foreach ($alias['similarterms_paths'] as $id => $path) {
$pieces = explode('/', $path);
if (sizeof($pieces) == 2 && $pieces[0] == "node" && is_numeric($pieces[1])) {
$nid = $pieces[1];
}
else {
$path = drupal_lookup_path('source', $path);
$pieces = explode('/', $path);
$nid = $pieces[1];
}
if ($nid) {
$args = array(
$node->nid,
$nid,
$v->vid,
);
$result[$id] = db_query($query, $args);
}
}
}
}
/**
* Function to validate entries into the overrides table
*/
function similarterms_node_validate($node) {
if (!variable_get('similarterms_override_options', 0)) {
return;
}
foreach (similarterms_taxonomy_get_vocabularies() as $v) {
$vid = 'similarterms_vid_' . $v->vid;
$alias =& $node->{$vid};
// Make sure that the paths are valid
foreach ($alias['similarterms_paths'] as $id => $path) {
$pieces = explode('/', $path);
if (sizeof($pieces) == 2 && $pieces[0] == "node" && is_numeric($pieces[1])) {
// If there's a better way to check if a node exists, replace this code
$thisnode = node_load($pieces[1]);
if (!$thisnode->nid) {
form_set_error("{$vid}][similarterms_paths][{$id}", t('%path is not a valid path', array(
'%path' => $path,
)));
}
}
elseif ($path == '') {
continue;
}
elseif (!drupal_lookup_path('source', $path)) {
form_set_error("{$vid}][similarterms_paths][{$id}", t('%vocab %path is not a valid path', array(
'%path' => $path,
'%vocab' => $v->name,
)));
}
}
}
}
/**
* This function returns a list of all blocks for similarterms
*
* Note: I could not find a public function in the block module to do this
* so I wrote this function based on _block_rehash(). If there's a better
* way to do this, this code should be refactored
*/
function similarterms_get_active_block_vocabularies() {
// TODO: add in code to check for blockcache module
global $theme_key;
init_theme();
$result = db_query("SELECT * FROM {blocks} WHERE theme = '%s' AND module = '%s'", $theme_key, 'similarterms');
while ($object = db_fetch_object($result)) {
if ($object->status) {
$blocks[$object->delta] = 1;
}
}
return $blocks;
}
/**
* This function gets taxonomy vocabularies and add in 0 for "all vocabs";
*/
function similarterms_taxonomy_get_vocabularies() {
$object = taxonomy_get_vocabularies();
$object[0]->vid = 0;
$object[0]->name = t('Any Vocabulary');
return $object;
}
/**
* Implementation of hook_menu().
*/
function similarterms_menu() {
// Admin settings for the site.
$items['admin/settings/similarterms'] = array(
'title' => 'Similar By Terms',
'description' => 'Basic Settings for similar term most settings are in the blocks config.',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'similarterms_admin_settings',
),
'file' => 'similarterms.admin.inc',
'access arguments' => array(
'administer site configuration',
),
'type' => MENU_NORMAL_ITEM,
);
return $items;
}
/**
* Theme function for similar block
*
*/
function similarterms_theme() {
return array(
'similarterms' => array(
'template' => 'similarterms',
'arguments' => array(
'display_options' => NULL,
'items' => NULL,
),
),
);
}
Functions
Name | Description |
---|---|
similarterms_block | Implementation of hook_block(). |
similarterms_block_configure | Perform the "configure" op for hook_block(). |
similarterms_block_list | Perform the "list" op for hook_block(). |
similarterms_block_save | Perform the "save" op for hook_block(). |
similarterms_block_view | Perform the "view" op for hook_block(). |
similarterms_flush_caches | Implementation of hook_flush_caches(). |
similarterms_form_alter | Implementation of hook_form_alter(). |
similarterms_get_active_block_vocabularies | This function returns a list of all blocks for similarterms |
similarterms_get_overrides | This function returns a list of overrides |
similarterms_help | Display help and module information |
similarterms_list | Output the block |
similarterms_menu | Implementation of hook_menu(). |
similarterms_nodeapi | Implementation of hook_nodeapi(). |
similarterms_node_delete | Function to delete entries from overrides table when a node is deleted |
similarterms_node_save | Function to populate overrides table |
similarterms_node_validate | Function to validate entries into the overrides table |
similarterms_perm | Valid permissions for this module |
similarterms_taxonomy_get_vocabularies | This function gets taxonomy vocabularies and add in 0 for "all vocabs"; |
similarterms_theme | Theme function for similar block |