vid"] = "$o->name - $o->description" ;
}
$form[Taxonews::VAR_VOCABULARY] = array
(
'#type' => 'select',
'#title' => t('Vocabularies'),
'#default_value' => variable_get(Taxonews::VAR_VOCABULARY, 0),
'#options' => $vocabularies,
'#description' => t('Vocabularies to be used for the generation of blocks. A block will be defined for each term in each vocabulary selected here.'),
'#required' => TRUE,
'#multiple' => TRUE,
'#size' => count($vocabularies),
);
$form[Taxonews::VAR_LIFETIME] = array
(
'#type' => 'textfield',
'#title' => t('Lifetime of news before expiration'),
'#default_value' => variable_get(Taxonews::VAR_LIFETIME, Taxonews::DEF_LIFETIME),
'#size' => 3,
'#max_length' => 3,
'#description' => t('The number of days a news item remains displayed in blocks.'),
'#required' => TRUE
) ;
$form[Taxonews::VAR_MAX_ROWS] = array
(
'#type' => 'textfield',
'#title' => t('Maximum number of rows per block'),
'#default_value' => variable_get(Taxonews::VAR_MAX_ROWS, Taxonews::DEF_MAX_ROWS),
'#size' => 3,
'#max_length' => 3,
'#description' => t('The maximum number of rows that the builtin theme will display in a block.'),
'#required' => TRUE
) ;
$form[Taxonews::VAR_PONDERATED] = array
(
'#type' => 'select',
'#title' => t('Ponderate sorting by'),
'#options' => array
(
0 => t('Creation date'),
),
);
if (module_exists('statistics'))
{
$form[Taxonews::VAR_PONDERATED]['#options'] += array
(
1 => t('Total views'),
2 => t('Daily views')
);
$form[Taxonews::VAR_PONDERATED] += array
(
'#default_value' => variable_get(Taxonews::VAR_PONDERATED, 0),
'#description' => t('Sort displayed news by descending creation date, possibly ponderated by total number of views and daily views. This ponderation only affects sorting, not news selection, which are always selected by creation date.'),
);
}
else
{
$form[Taxonews::VAR_PONDERATED] += array
(
'#default_value' => 0,
'#description' => t('Sort displayed news by descending creation date. Additional sortings will be available if you enable statistics.module. It is currently disabled.'),
);
}
$form[Taxonews::VAR_FEED] = array
(
'#type' => 'checkbox',
'#title' => t('Display RSS feed icon on taxonews blocks'),
'#default_value' => variable_get(Taxonews::VAR_FEED, TRUE),
'#description' => t('This setting allows taxonews to display a RSS feed icon on each non empty block. Default value is True.'),
);
$form[Taxonews::VAR_SHOW_NAME] = array
(
'#type' => 'checkbox',
'#title' => t('Prepend taxonews module name in block list'),
'#default_value' => variable_get(Taxonews::VAR_SHOW_NAME, TRUE),
'#description' => t('This allows the modules to appear grouped on the block list at Administer/Blocks, to avoid cluttering.'),
);
$form[Taxonews::VAR_SHOW_ARCHIVE] = array
(
'#type' => 'checkbox',
'#title' => t('Include "Archive" link to older articles in block'),
'#default_value' => variable_get(Taxonews::VAR_SHOW_ARCHIVE, TRUE),
'#description' => t('If articles matching the term exist, but cannot be placed in the block, for instance if they are too old, add an "Archive" link at the end of the block. The link will not be shown if no matching article exists.'),
);
$form[Taxonews::VAR_SHOW_EMPTY] = array
(
'#type' => 'checkbox',
'#title' => t('Include blocks with currently no matching nodes in the blocks list'),
'#default_value' => variable_get(Taxonews::VAR_SHOW_EMPTY, TRUE),
'#description' => t('It is strongly advised to keep this setting to True. If set to False, the block numbers ($delta) will shift in case new content becomes categorized under a yet-empty term.')
);
$form ['Taxonews::VERSION'] = array
(
'#value' => t('
This site is running taxonews.module version:
%version.
',
array('%version' => Taxonews::VERSION))
);
$ret = system_settings_form($form);
return $ret;
}
/**
* Is there any data matching that term ?
* @param int $tid
* @param array $nids Array of displayed nodes, to ignore
* @return boolean
*
* The function expects the nids of the already displayed nodes
* to be the keys of the $items array, so it can ignore them
*/
static function archiveExists($tid, $items)
{
$sq = 'SELECT count(tn.nid) '
. 'FROM {term_node} tn '
. 'WHERE tn.tid = %d ';
if (!isset($items))
{
$items = array();
}
$ar_nids = array_keys($items);
$s_nids = implode(',', $ar_nids);
if (sizeof($ar_nids))
{
$sq .= 'AND tn.nid NOT IN (%s) ';
$q = db_query_range($sq, $tid, $s_nids, 0, 1);
}
else
{
$q = db_query_range($sq, $tid, 0, 1);
}
$ret = db_result($q);
$ret = $ret > 0;
return $ret;
}
/**
* Implement hook_block('configure')
*
* @param mixed $delta
* @return array
* @see taxonews_block()
*/
static function blockConfigure($delta)
{
$description = t('By default, blocks without matching content are not displayed. This setting allows you to force a static content.');
$form [Taxonews::VAR_EMPTY_MESSAGES] = array
(
'#title' => t('Text to be displayed if block has no matching content'),
'#type' => 'textfield',
'#default_value'=> Taxonews::emptyMessages($delta),
'#size' => 60,
'#max_length' => 60,
'#description' => $description,
);
return $form;
}
/**
* Implement hook_block('list')
*
* @return array
* @see taxonews_block()
*/
static function blockList()
{
$i = 0 ;
$blocks = array() ;
$prefix = variable_get(Taxonews::VAR_SHOW_NAME, TRUE) ? 'taxonews/' : '' ;
$showEmpty = variable_get(Taxonews::VAR_SHOW_EMPTY, TRUE);
$sq = 'SELECT count(tn.nid) cnt '
. 'FROM {term_node} tn '
. 'WHERE tn.tid = %d and tn.status = 1 ';
$terms = Taxonews::getTerms();
if (count($terms) == 0)
{
$module_path = db_result(db_query("SELECT filename FROM {system} WHERE name = 'taxonews' AND type = 'module'"));
$module_path = dirname($module_path);
drupal_set_message(
t('WARNING: You will not be able to configure taxonews blocks until you !configure and !define in the taxonews vocabularies. You might want to refer to !install.',
array(
'!configure' => l(t('configure taxonews'), Taxonews::PATH_SETTINGS),
'!define' => l(t('define terms'), 'admin/content/taxonomy'),
'!install' => l('INSTALL.txt', "$module_path/INSTALL.txt")
)
),
'error');
unset($module_path);
}
foreach ($terms as $term)
{
/**
* @todo extract query out of the loop to avoid repeated queries
*/
if (!$showEmpty)
{
$q = db_query($sq, $term->tid);
$o = db_fetch_object($q);
if ($o->cnt == 0)
{
continue; // Do not display the block, do not increment the counter
}
}
$blocks[$i] = array() ;
$blocks[$i]['info'] = "$prefix$term->vocabulary_name/$term->name" ;
$i++ ;
}
return $blocks ;
}
/**
* Implement hook_block('save')
*
* Save the configuration (i.e. the text) of the selected block
*
* @param mixed $delta Usually an int
* @param $edit The edit form fields
* @return void
* @see hook_block()
*/
static function blockSave($delta, $edit)
{
$emptyMessages = Taxonews::emptyMessages();
$emptyMessages[$delta] = $edit[Taxonews::VAR_EMPTY_MESSAGES];
variable_set(Taxonews::VAR_EMPTY_MESSAGES, $emptyMessages);
}
/**
* Implement hook_block('view')
*
* @param mixed $delta Drupal block delta, usually an int
* @return string HTML
*/
static function blockView($delta)
{
$terms = Taxonews::getTerms() ;
/**
* ponderation must only be taken into account is statistics module exists
* because the module may have been online, allowing ponderation to be set,
* then removed, causing stats to no longer be updated
*/
$ponderation = module_exists('statistics')
? variable_get(Taxonews::VAR_PONDERATED, 0)
: 0;
/**
* There's a small trick for case 0: n.created is not a views count, but can
* be used exactly like one: more recent nodes will have a higher value in
* this field, so we can sort on it for display just like we sort on actual
* view counts otherwise. That way we only have one sort rule for all three
* different cases.
*/
switch ($ponderation)
{
case 1: // by total views
$sq = 'SELECT n.nid, n.title, td.name, nc.totalcount views '
. 'FROM {node} n '
. ' INNER JOIN {term_node} tn ON n.nid = tn.nid '
. ' INNER JOIN {term_data} td ON tn.tid = td.tid '
. ' INNER JOIN {node_counter} nc on n.nid = nc.nid '
. 'WHERE td.tid = %d '
. ' AND (n.created > unix_timestamp(curdate())-%d*86400) '
. ' AND (n.status = 1) '
. ' ORDER BY n.created desc, n.changed desc ';
break;
case 2: // by daily views since creation. Multiply by 86400 to avoid 0-rounding
$sq = 'SELECT n.nid, n.title, td.name, '
. ' nc.totalcount*86400/(unix_timestamp(curdate())-n.created) views '
. 'FROM {node} n '
. ' INNER JOIN {term_node} tn ON n.nid = tn.nid '
. ' INNER JOIN {term_data} td ON tn.tid = td.tid '
. ' INNER JOIN {node_counter} nc on n.nid = nc.nid '
. 'WHERE td.tid = %d '
. ' AND (n.created > unix_timestamp(curdate())-%d*86400) '
. ' AND (n.status = 1) '
. ' ORDER BY n.created desc, n.changed desc ';
break;
case 0: // not ponderated
default: // ignore invalid values
$sq = 'SELECT n.nid, n.title, td.name, n.created views '
. 'FROM {node} n '
. ' INNER JOIN {term_node} tn ON n.nid = tn.nid '
. ' INNER JOIN {term_data} td ON tn.tid = td.tid '
. 'WHERE td.tid = %d '
. ' AND (n.created > unix_timestamp(curdate())-%d*86400) '
. ' AND (n.status = 1) '
. ' ORDER BY n.created desc, n.changed desc ';
break;
}
if (($q = db_query_range ($sq, $terms[$delta]->tid,
variable_get(Taxonews::VAR_LIFETIME, Taxonews::DEF_LIFETIME),
0,
variable_get(Taxonews::VAR_MAX_ROWS, Taxonews::DEF_MAX_ROWS)
))
&& (db_num_rows($q) > 0))
{
$ret = array();
$items = array();
while ($o = db_fetch_object ($q))
{
$items[$o->views] = l($o->title, 'node/' . $o->nid);
/**
* $o->name is undefined outside the loop, and re-initializing it for
* every value in the loop seems to actually be the cheapest way of
* keeping it, although its value is the same for all rows in the result
* set
*/
$ret['subject'] = $o->name ;
}
krsort($items); // sort descending on views
}
else
{
$items = NULL;
$term = taxonomy_get_term($terms[$delta]->tid);
$ret['subject'] = $term->name;
}
$ret['content'] = theme('taxonews_block_view', $delta, $items, $terms[$delta]->tid);
return $ret;
}
/**
* Generate the default content for block when no node content is available
*
* @param mixed $delta
* @return string
*/
static function emptyMessages($delta = NULL)
{
static $emptyMessages;
if (empty($emptyMessages))
{
$emptyMessages = variable_get(Taxonews::VAR_EMPTY_MESSAGES, array());
}
$ret = isset($delta)
? (array_key_exists($delta, $emptyMessages) ? $emptyMessages[$delta] : NULL)
: $emptyMessages;
return $ret;
}
/**
* Query for terms in selected vocabularies
*
* @return array [tid, name]
*/
static function getTerms()
{
static $terms = array();
if (count($terms) == 0)
{
$sq = 'SELECT td.tid, td.name '
. 'FROM {term_data} td '
. 'WHERE td.vid = %s '
. 'ORDER BY 2, 1 ';
$vids = variable_get(Taxonews::VAR_VOCABULARY, array());
foreach ($vids as $vid)
{
$sq = 'SELECT td.tid, td.name, v.name as vocabulary_name '
. 'FROM {term_data} td '
. 'INNER JOIN {vocabulary} v ON td.vid = v.vid '
. 'WHERE td.vid = %s '
. 'AND td.vid = v.vid '
. 'ORDER BY 2, 1 ';
$q = db_query($sq, $vid) ;
while ($o = db_fetch_object($q))
{
$terms[] = $o;
}
}
}
return $terms ;
}
} // end of class
/**
* Work around the limitation on static class methods in the menu system
* @param string $method The name of the method to be invoked
* @return mixed Returns the result of the invoked method
*/
function taxonews_facade($method)
{
$args = func_get_args();
$ret = call_user_func_array(array('Taxonews', $method), $args);
return $ret;
}
/**
* -----------------------------------------------------------------------------
* Drupal hooks below
* -----------------------------------------------------------------------------
*/
/**
* Implement hook_help
*
* @param string $section
* @return string HTML
*/
function taxonews_help($section)
{
$ret = NULL;
$help = t('Publish node teasers into blocks based on a taxonomy vocabulary.
') ;
switch ($section)
{
case 'admin/help#taxonews':
$ret = $help .
t('This module creates blocks containing a selection of node titles, linking to the node themselves. Blocks are created for each taxonomy term in the vocabularies enabled for block generation.
')
. t('Settings allow the administrator to choose the age limit for nodes included in the blocks, as well as various settings to handle special cases like empty blocks.
')
. t('By default, nodes are displayed in reverse chronological order. If statistics.module is enabled and node counts are active, nodes can also be displayed by descending order of total views or daily views since their creation. The node selection process by creation date is not affected by these sorting rules.
');
break;
case 'admin/modules#description':
$ret = $help;
break;
}
return $ret;
}
/**
* Implement hook_block
*
* @param string $op list|view|configure|save
* @param integer $delta
* @param array $edit
* @return mixed either void or HTML for blocks/block list
* @see Taxonews::blockList()
* @see Taxonews::block_view()
*/
function taxonews_block ($op = 'list', $delta = 0, $edit = array())
{
switch ($op)
{
case 'list': $ret = Taxonews::blockList(); break;
case 'view': $ret = Taxonews::blockView($delta); break;
case 'configure': $ret = Taxonews::blockConfigure($delta); break;
case 'save': $ret = Taxonews::blockSave($delta, $edit); break;
default: $ret = NULL;
}
return $ret;
}
/**
* Implement hook_settings
*
* @param boolean $may_cache
* @return array
*/
function taxonews_menu($may_cache)
{
if ($may_cache)
{
$items[] = array
(
'path' => Taxonews::PATH_SETTINGS,
'title' => t('Taxonews settings'),
'description' => t('Configure Taxonews block generation by vocabulary.'),
'callback' => 'drupal_get_form',
'callback arguments' => array('taxonews_facade', 'adminSettings'),
'access' => user_access('administer site configuration'),
);
}
return $items;
}
/**
* -----------------------------------------------------------------------------
* Default theme functions below
* -----------------------------------------------------------------------------
*/
/**
* Themeable function for TN blocks
*
* The default theme won't link to the "archive" page if there are no
* nodes in addition to the ones already listed. If a site-specific theme
* want to display the link anyway, pass null instead of $items to
* Taxonews::archiveExists to check for the page contents. Note that in most
* normal situations, it will exist and contain at least the nodes already listed
* in the block.
*
* @param mixed $delta the block delta, usually integer but now always
* @param array $items A possibly empty array of links
* @param int $tid The tid for the taxonomy term used to build the block
* @see Taxonews::archiveExists()
*
*/
function theme_taxonews_block_view($delta, $items = NULL, $tid)
{
$ret = $items
? theme('item_list', $items)
: Taxonews::emptyMessages($delta);
if (!empty($ret) && Taxonews::archiveExists($tid, $items))
{
if (variable_get(Taxonews::VAR_SHOW_ARCHIVE, TRUE))
{
$ret .= ''
. l(t('Archive'), "taxonomy/term/$tid", NULL, NULL, NULL, TRUE)
. ' ' ;
}
}
if (!empty($ret) && variable_get(Taxonews::VAR_FEED, TRUE))
{
$ret .= theme('xml_icon', url("taxonomy/term/$tid/0/feed"));
}
$ret = empty($ret)
? NULL
: "$ret
\n";
return $ret;
}
error_reporting($taxonewsErrorReporting);
unset($taxonewsErrorReporting);