386 lines
No EOL
11 KiB
Text
386 lines
No EOL
11 KiB
Text
<?php
|
|
/**
|
|
* @file
|
|
* Recently read module file.
|
|
* Displays a history of recently read nodes by currently logged in user.
|
|
*
|
|
*
|
|
* @todo: create a function that deletes a history
|
|
* @todo: create recently_read_node_was_read($nid, $uid)
|
|
* @todo: remove current if on node page
|
|
@todo: truncate number of rr in the block to number of elements from block settings
|
|
*/
|
|
|
|
|
|
/**
|
|
* Implementation of hook_menu().
|
|
*/
|
|
function recently_read_menu() {
|
|
$items['admin/settings/recently-read'] = array(
|
|
'title' => 'Recently read content',
|
|
'description' => 'Tracks the history of recently read content by each user.',
|
|
'page callback' => 'drupal_get_form',
|
|
'page arguments' => array('recently_read_settings'),
|
|
'access arguments' => array('administer site configuration'),
|
|
'type' => MENU_NORMAL_ITEM,
|
|
);
|
|
return $items;
|
|
}
|
|
|
|
|
|
/**
|
|
* Implementation of hook_theme().
|
|
*/
|
|
function recently_read_theme() {
|
|
return array(
|
|
'recently_read_item' => array(
|
|
'arguments' => array('item' => NULL)
|
|
),
|
|
'recently_read_item_list' => array(
|
|
'arguments' => array('item' => NULL)
|
|
),
|
|
);
|
|
}
|
|
|
|
|
|
/**
|
|
* Implementation of hook_block().
|
|
*/
|
|
function recently_read_block($op = 'list', $delta = 0, $edit = array()) {
|
|
switch ($op) {
|
|
case 'list':
|
|
// each enabled content type has its own block
|
|
$types = node_get_types();
|
|
$enabled = variable_get('recently_read_node_types', array('page', 'story'));
|
|
$blocks = array();
|
|
foreach ($enabled as $key) {
|
|
$blocks[$key]['info'] = t('Recently read - @type', array('@type' => $types[$key]->name));
|
|
$blocks[$key]['cache'] = BLOCK_NO_CACHE;
|
|
}
|
|
return $blocks;
|
|
|
|
case 'configure':
|
|
// allow user to customize the length of a list for each node type
|
|
$max_entries = variable_get('recently_read_max_entries', 10);
|
|
$max_count = variable_get("recently_read_max_length", array('page' => 10, 'story' => 10));
|
|
|
|
$form['items_count'] = array(
|
|
'#type' => 'textfield',
|
|
'#title' => t('Maximum number of links to display in the block'),
|
|
'#description' => t('Enter the positive integer value, less or equal to %limit.',
|
|
array('%limit' => $max_entries)
|
|
),
|
|
'#default_value' => (key_exists($delta, $max_count)) ? $max_count[$delta] : $max_entries,
|
|
);
|
|
return $form;
|
|
|
|
case 'save':
|
|
// save configuration settings
|
|
$max_entries = variable_get('recently_read_max_entries', 10);
|
|
$value = max(1, min($edit['items_count'], $max_entries));
|
|
$max_count = variable_get('recently_read_max_length', array('page' => 10, 'story' => 10));
|
|
$max_count[$delta] = $value;
|
|
variable_set('recently_read_max_length', $max_count);
|
|
return;
|
|
|
|
case 'view':
|
|
// disable caching of entire page if recently read block is being displayed
|
|
recently_read_disable_page_cache();
|
|
|
|
// view block containing links to recently visited nodes
|
|
global $user;
|
|
|
|
$max_entries = variable_get('recently_read_max_entries', 10);
|
|
$max_count = variable_get('recently_read_max_length', array('page' => 10, 'story' => 10));
|
|
isset($max_count[$delta]) ? $limit = $max_count[$delta] : $limit = $max_entries;
|
|
|
|
$items = recently_read_get_read_items(array($delta), $user->uid, $limit);
|
|
$types = node_get_types();
|
|
return array(
|
|
'subject' => t('Recently read - @type', array('@type' => $types[$delta]->name)),
|
|
'content' => theme('recently_read_item_list', $items)
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
function recently_read_exit() {
|
|
global $user;
|
|
|
|
drupal_bootstrap(DRUPAL_BOOTSTRAP_PATH);
|
|
|
|
// track history for authenticated user
|
|
if ((arg(0) == 'node') && is_numeric(arg(1))) { // && arg(2) == '') {
|
|
$nid = arg(1);
|
|
|
|
// get node type
|
|
$type = db_result(db_query('SELECT type FROM {node} WHERE nid = %d', $nid));
|
|
|
|
// track history for authenticated user
|
|
if (recently_read_is_enabled($type) && $user->uid) {
|
|
$record = new stdClass();
|
|
$record->nid = $nid;
|
|
$record->type = $type;
|
|
$record->uid = $user->uid;
|
|
$record->timestamp = time();
|
|
|
|
$views = db_result(db_query(
|
|
'SELECT views FROM {recently_read_nodes} WHERE nid = %d AND uid = %d AND type = "%s"',
|
|
$nid, $user->uid, $type
|
|
));
|
|
// a node has been viewed before, make an update
|
|
if (db_affected_rows()) {
|
|
$record->views = $views + 1;
|
|
drupal_write_record('recently_read_nodes', $record, array('nid', 'uid'));
|
|
}
|
|
// a node has not been viewed before, add new row
|
|
else {
|
|
$record->views = 1;
|
|
drupal_write_record('recently_read_nodes', $record);
|
|
}
|
|
}
|
|
|
|
// track history for anonymous user
|
|
if (recently_read_is_enabled($type) && !$user->uid && variable_get('recently_read_anonymous_enabled', FALSE)) {
|
|
|
|
$key = "recently_read-$type";
|
|
if (!isset($_SESSION[$key])) {
|
|
$_SESSION[$key] = array();
|
|
}
|
|
|
|
// remove previous entry, if present
|
|
unset($_SESSION[$key][$nid]);
|
|
|
|
// add new entry at the beginning of array
|
|
$title = db_result(db_query('SELECT title FROM {node} WHERE nid = %d', $nid));
|
|
$entry = array(
|
|
'nid' => $nid,
|
|
'title' => $title,
|
|
'type' => $type,
|
|
'timestamp' => time()
|
|
);
|
|
$_SESSION[$key] = array($nid => $entry) + $_SESSION[$key];
|
|
|
|
while (count($_SESSION[$key]) > variable_get('recently_read_max_entries', 10)) {
|
|
array_pop($_SESSION[$key]);
|
|
}
|
|
}
|
|
|
|
// remove old entries
|
|
$nids = array();
|
|
$result = db_query("SELECT nid FROM {recently_read_nodes} WHERE uid = %d and type = '%s' ORDER BY timestamp DESC LIMIT %d,1000",
|
|
$user->uid,
|
|
$type,
|
|
variable_get('recently_read_max_entries', 10)+1
|
|
);
|
|
while ($nid = db_result($result)) {
|
|
$nids[] = $nid;
|
|
};
|
|
if (count($nids)) {
|
|
$placeholders = implode(',', array_fill(0, count($nids), "%d"));
|
|
db_query("DELETE FROM {recently_read_nodes} WHERE uid = %d AND nid IN($placeholders)",
|
|
array_merge((array) $user->uid, $nids)
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Form builder; Configure recently read settings.
|
|
*/
|
|
function recently_read_settings() {
|
|
$types = node_get_types();
|
|
|
|
$options = array();
|
|
foreach ($types as $key => $type) {
|
|
$options[$key] = $type->name;
|
|
}
|
|
|
|
$form['node_types'] = array(
|
|
'#type' => 'checkboxes',
|
|
'#title' => t('Enable history tracking of the following content'),
|
|
'#description' => t('Select which content types will be tracked.'),
|
|
'#default_value' => variable_get('recently_read_node_types', array('page', 'story')),
|
|
'#options' => $options
|
|
);
|
|
|
|
$form['anonymous_enabled'] = array(
|
|
'#type' => 'checkbox',
|
|
'#title' => t('Enable history tracking for anonymous users'),
|
|
'#description' => t('If disabled, user must be logged to view recently read blocks.'),
|
|
'#default_value' => variable_get('recently_read_anonymous_enabled', FALSE)
|
|
);
|
|
|
|
$form['max_entries'] = array(
|
|
'#type' => 'textfield',
|
|
'#title' => t('Recently read list length'),
|
|
'#description' => 'Provide the maximum number of entires stored for each read content type (per user) in the database.',
|
|
'#default_value' => variable_get('recently_read_max_entries', 10),
|
|
'#required' => TRUE
|
|
);
|
|
|
|
$form['submit'] = array(
|
|
'#type' => 'submit',
|
|
'#value' => t('Save configuration')
|
|
);
|
|
|
|
return $form;
|
|
}
|
|
|
|
|
|
function recently_read_settings_validate($form, &$form_state) {
|
|
$max = $form_state['values']['max_entries'];
|
|
if (!is_numeric($max) || $max < 1) {
|
|
form_set_error('max_entries', t('%field must be a positive integer value.',
|
|
array('%field' => $form['max_entries']['#title'])
|
|
));
|
|
}
|
|
}
|
|
|
|
|
|
function recently_read_settings_submit($form, &$form_state) {
|
|
$selected = array();
|
|
foreach ($form_state['values']['node_types'] as $value) {
|
|
if ($value) {
|
|
$selected[] = $value;
|
|
}
|
|
}
|
|
variable_set('recently_read_node_types', $selected);
|
|
variable_set('recently_read_max_entries', $form_state['values']['max_entries']);
|
|
variable_set('recently_read_anonymous_enabled', $form_state['values']['anonymous_enabled']);
|
|
drupal_set_message(t('The configuration options have been saved.'));
|
|
}
|
|
|
|
|
|
/*
|
|
* Function that checks if a specific node type history tracking has been enabled
|
|
*/
|
|
function recently_read_is_enabled($node_type) {
|
|
$enabled_types = variable_get('recently_read_node_types', array('page', 'story'));
|
|
return in_array($node_type, $enabled_types);
|
|
}
|
|
|
|
|
|
/*
|
|
* Get a list of recently read items by node types and for a specific user,
|
|
* sorted by read date.
|
|
*
|
|
* @param $node_types
|
|
* An array of node types.
|
|
*
|
|
* @param $user_id
|
|
* Id of a user whose list is returned.
|
|
*
|
|
* @param $limit
|
|
* Number of items to return (zero to return all)
|
|
*
|
|
* @return
|
|
* An array of recently read items. Each item is an array.
|
|
* Properties of the item: nid, title, type, timestamp
|
|
*/
|
|
function recently_read_get_read_items($node_types, $user_id, $limit = 0) {
|
|
// normalize arguments
|
|
if (!is_array($node_types)) {
|
|
$node_types = array($node_types);
|
|
}
|
|
|
|
if ($limit == 0) {
|
|
$limit = variable_get('recently_read_max_entries', 10) * count($node_types);
|
|
}
|
|
|
|
// get history from _SESSION variable if anonymous
|
|
if ($user_id==0 && variable_get('recently_read_anonymous_enabled', FALSE)) {
|
|
$items = array();
|
|
foreach ($node_types as $node_type) {
|
|
$key = "recently_read-$node_type";
|
|
if (isset($_SESSION[$key]) && is_array($_SESSION[$key])) {
|
|
$items = $items + $_SESSION[$key];
|
|
}
|
|
}
|
|
usort($items, '_recently_read_sort_fcn');
|
|
$items = array_slice($items, 0, $limit);
|
|
}
|
|
|
|
// get history from database if authenticated
|
|
if ($user_id > 0) {
|
|
// make a list of links to recently read nodes which are published
|
|
$placeholders = db_placeholders($node_types, 'text');
|
|
|
|
// prepare args for sql query
|
|
$args = array($user_id);
|
|
$args = array_merge($args, $node_types);
|
|
$args[] = $limit;
|
|
$result = db_query(db_rewrite_sql("SELECT n.nid, n.title, n.type, rr.timestamp FROM {node} n
|
|
INNER JOIN {recently_read_nodes} rr
|
|
ON n.nid = rr.nid WHERE rr.uid = %d AND n.status = 1 AND n.type IN($placeholders)
|
|
ORDER BY rr.timestamp DESC
|
|
LIMIT 0, %d"),
|
|
$args
|
|
);
|
|
|
|
$items = array();
|
|
while ($row = db_fetch_array($result)) {
|
|
$items[] = $row;
|
|
}
|
|
}
|
|
|
|
return $items;
|
|
}
|
|
|
|
|
|
/*
|
|
* Disables page caching. Call this function if you want to display recently read content (i.e. block).
|
|
*/
|
|
function recently_read_disable_page_cache() {
|
|
$GLOBALS['conf']['cache'] = FALSE;
|
|
}
|
|
|
|
|
|
/*
|
|
* Return a themed recently read item.
|
|
*
|
|
* @param $item
|
|
* An object containing the properties of the item.
|
|
* Properties used: nid, title, type, timestamp
|
|
* @return
|
|
* A themed HTML string containing a link to the recently read item.
|
|
*/
|
|
function theme_recently_read_item($item) {
|
|
return l($item['title'], 'node/' . $item['nid']);
|
|
}
|
|
|
|
|
|
/**
|
|
* Return a themed list of recently read items.
|
|
*
|
|
* @param $items
|
|
* An array of recently read items to be displayed in the list.
|
|
* @return
|
|
* A string containing the list output.
|
|
*
|
|
*/
|
|
function theme_recently_read_item_list($items) {
|
|
if (count($items)==0) {
|
|
return t('Nothing has been read yet.');
|
|
}
|
|
|
|
// theme each individual item on the list
|
|
foreach ($items as &$item) {
|
|
$item = theme('recently_read_item', $item);
|
|
}
|
|
|
|
// theme the list
|
|
return theme('item_list', $items);
|
|
}
|
|
|
|
|
|
/*
|
|
* Compare function for sorting recently read items
|
|
*/
|
|
function _recently_read_sort_fcn($a, $b) {
|
|
$delta = $b['timestamp'] - $a['timestamp'];
|
|
if ($delta > 0) return 1;
|
|
if ($delta < 0) return -1;
|
|
return 0;
|
|
} |