'Favorite nodes',
'path' => 'admin/settings/favorite_nodes',
'description' => 'Settings for favorite nodes',
'callback' => 'drupal_get_form',
'callback arguments' => 'favorite_nodes_settings',
'type' => MENU_NORMAL_ITEM,
'access' => user_access(FAVORITE_NODES_PERM_ADMINISTER),
);
$items[] = array(
'path' => 'favorite_nodes/add',
'callback' => 'favorite_nodes_add_page',
'type' => MENU_CALLBACK,
'access' => user_access(FAVORITE_NODES_PERM_ADD),
);
$items[] = array(
'path' => 'favorite_nodes/delete',
'callback' => 'favorite_nodes_delete_page',
'type' => MENU_CALLBACK,
'access' => user_access(FAVORITE_NODES_PERM_ADD),
);
$items[] = array(
'path' => 'favorite_nodes/view',
'callback' => 'favorite_nodes_view_page',
'title' => t('Favorites'),
'type' => MENU_CALLBACK,
'access' => user_access(FAVORITE_NODES_PERM_VIEW),
);
$items[] = array(
'path' => 'favorites/view',
'callback' => 'favorite_nodes_view_page',
'type' => MENU_CALLBACK,
'access' => user_access(FAVORITE_NODES_PERM_VIEW),
);
}
else {
global $user;
if ($user->uid && variable_get(FAVORITE_NODES_MENUS, 0)) {
foreach (_node_types_natcasesort() as $type) {
if (variable_get(FAVORITE_NODES_NODE_TYPE . $type->type, 0)) {
$items[] = array(
'path' => "favorites/view/$user->uid/$type->type",
'title' => t('Favorite @type', array('@type' => $type->name)),
'callback' => 'favorite_nodes_view_page',
'type' => MENU_NORMAL_ITEM,
'access' => user_access(FAVORITE_NODES_PERM_VIEW),
);
}
}
}
if (variable_get(FAVORITE_NODES_VIEW_IN_LOCAL_TASK, NULL) && user_access(FAVORITE_NODES_PERM_VIEW)) {
// arg(1) is always uid in user's profile page
$items[] = array(
'path' => 'user/'.arg(1).'/favorites',
'title' => t('Favorites'),
'callback' => 'favorite_nodes_view_all_page',
'callback arguments' => array(arg(1)),
'type' => MENU_LOCAL_TASK,
'access' => user_access(FAVORITE_NODES_PERM_VIEW),
);
}
}
return $items;
}
/**
* Implementation of hook_xmlrpc().
*/
function favorite_nodes_xmlrpc() {
$items = array();
$items[] = array(
'favorite_nodes.add',
'favorite_nodes_add',
array('boolean', 'int'),
t('Add a favorite node to the current user\'s list.')
);
}
function _node_types_natcasesort() {
static $node_types;
if (!isset($node_types)) {
$node_types = node_get_types();
uasort($node_types, create_function('$a, $b', 'return strnatcasecmp($a->name, $b->name);'));
}
return $node_types;
}
/**
* Implementation of hook_user().
*/
function favorite_nodes_user($op, &$edit, &$user, $category = null) {
switch ($op) {
case 'view':
return theme('favorite_nodes_user_page', $user);
break;
case 'delete':
favorite_nodes_delete_favorites($user->uid);
break;
}
}
/**
* List of favorite enabled content types with favorites
*/
function theme_favorite_nodes_user_page($account) {
$fav_list = array();
foreach (_node_types_natcasesort() as $type) {
if (variable_get(FAVORITE_NODES_NODE_TYPE . $type->type, 0)) {
$uid = intval($account->uid);
$favorites = favorite_nodes_get($uid, $type->type, variable_get(FAVORITE_NODES_BLOCK_LIMIT, 5));
$items = array();
if (!empty($favorites)) {
foreach ($favorites as $favorite) {
$items[] = l($favorite->title, "node/$favorite->nid");
}
}
$fav_list[] = array(
'title' => $items ? l($type->name, "favorite_nodes/view/$account->uid/$type->type") : $type->name,
'value' => theme('item_list', $items),
);
}
}
return array(t('Favorites') => $fav_list);
}
/**
* Implementation of hook_nodeapi().
*/
function favorite_nodes_nodeapi(&$node, $op, $teaser = null, $page = null) {
switch ($op) {
case 'delete':
// Delete all favorite entries of the node being deleted.
db_query("DELETE FROM {favorite_nodes} WHERE nid = %d", $node->nid);
break;
}
}
/**
* Implementation of hook_block().
*/
function favorite_nodes_block($op = 'list', $delta = 0, $edit = array()) {
global $user;
$node_types = _node_types_natcasesort();
switch ($op) {
case 'list':
return array(array('info' => t('Favorite nodes')));
case 'view':
if (user_access(FAVORITE_NODES_PERM_VIEW)) {
$block = array();
$block['subject'] = variable_get(FAVORITE_NODES_BLOCK_TITLE, t('Favorites'));
$block['content'] = '';
foreach ($node_types as $type) {
if (variable_get(FAVORITE_NODES_NODE_TYPE . $type->type, 0)) {
$uid = intval($user->uid);
$favorites = favorite_nodes_get($uid, $type->type, variable_get(FAVORITE_NODES_BLOCK_LIMIT, 5));
$items = array();
if (!empty($favorites)) {
foreach ($favorites as $favorite) {
$items[] = l($favorite->title, "node/$favorite->nid");
}
$block['content'] .= theme('item_list', $items, variable_get(FAVORITE_NODES_BLOCK . $type->type, $type->name));
}
$sql = "SELECT COUNT(*) FROM {node} n INNER JOIN {favorite_nodes} f USING(nid) WHERE n.type = '%s' AND f.uid = %d";
$count = db_result(db_query($sql, $type->type, $user->uid));
if ($count > variable_get(FAVORITE_NODES_BLOCK_LIMIT, 5)) {
$block['content'] .= "
\n";
$block['content'] .= l(t('More Favorite !types', array('!types' => variable_get(FAVORITE_NODES_BLOCK . $type->type, $type->name))), "favorite_nodes/view/$user->uid/$type->type");
$block['content'] .= "
\n";
}
}
}
}
return $block;
case 'configure':
$form = array();
$form['titles'] = array(
'#type' => 'fieldset',
'#title' => t('Titles'),
'#collapsible' => true,
'#collapsed' => false,
);
$form['titles']['title'] = array(
'#type' => 'textfield',
'#title' => t('Block title'),
'#size' => 60,
'#description' => t('This title will be displayed at the top of the block.'),
'#default_value' => variable_get(FAVORITE_NODES_BLOCK_TITLE, t('Favorites')),
);
$form['limit'] = array(
'#type' => 'textfield',
'#title' => t('Number of favorites to display'),
'#size' => 4,
'#description' => t('Up to this many favorites of each type of content will be displayed in the block. If there are no marked favorites of a type, then that type won\'t show up.'),
'#default_value' => variable_get(FAVORITE_NODES_BLOCK_LIMIT, 5),
);
$form['titles']['subtitles'] = array(
'#type' => 'fieldset',
'#title' => t('Type subtitles'),
'#collapsible' => true,
'#collapsed' => true,
);
foreach ($node_types as $type) {
if (variable_get(FAVORITE_NODES_NODE_TYPE . $type->type, 0)) {
$form['titles']['subtitles'][FAVORITE_NODES_BLOCK . $type->type] = array(
'#type' => 'textfield',
'#title' => t('Subtitle for the %name content type', array('%name' => $type->name)),
'#size' => 60,
'#description' => t('Within the block, any links to content of the %name type will be categorized under this subtitle.', array('%name' => $name)),
'#default_value' => variable_get(FAVORITE_NODES_BLOCK . $type->type, $type->name),
);
}
}
return $form;
case 'save':
variable_set(FAVORITE_NODES_BLOCK_TITLE, $edit['title']);
variable_set(FAVORITE_NODES_BLOCK_LIMIT, $edit['limit']);
foreach ($node_types as $type) {
if (variable_get(FAVORITE_NODES_NODE_TYPE . $type->type, 0)) {
variable_set(FAVORITE_NODES_BLOCK . $type->type, $edit[FAVORITE_NODES_BLOCK . $type->type]);
}
}
break;
default:
break;
}
}
/**
* Implementation of hook_links().
*/
function favorite_nodes_link($type, $node = null, $teaser = false) {
global $user;
$links = array();
if ($type == 'node' && !$teaser && variable_get(FAVORITE_NODES_SHOWLINK, 1)) {
if (variable_get(FAVORITE_NODES_NODE_TYPE . $node->type, 0)) {
if (user_access(FAVORITE_NODES_PERM_ADD)) {
$links = theme('favorite_nodes_links', $node);
}
}
}
return $links;
}
/**
* Allow theming of links().
*/
function theme_favorite_nodes_links($node) {
if (variable_get(FAVORITE_NODES_NODE_TYPE . $node->type, 0)) {
if (user_access(FAVORITE_NODES_PERM_ADD)) {
if (!_favorite_nodes_check($node->nid)) {
$links['favorite_nodes_add'] = array('title' => t('add to favorites'), 'href' => 'favorite_nodes/add/'. $node->nid, 'attributes' => array('class' => 'favorites add'));
}
else {
if (user_access(FAVORITE_NODES_PERM_VIEW)) {
$links['favorite_nodes_in'] = array('title' => t('in favorites'));
$links['favorite_nodes_remove'] = array('title' => t('remove from favorites'), 'href' => 'favorite_nodes/delete/'. $node->nid, 'attributes' => array('class' => 'favorites remove'));
}
}
}
}
return $links;
}
/**
* Settings page for this module.
*/
function favorite_nodes_settings() {
$set = 'page';
$form[$set] = array(
'#type' => 'fieldset',
'#title' => t('Favorites Page Settings'),
'#collapsible' => true,
'#collapsed' => false,
);
$form[$set][FAVORITE_NODES_PAGE_LIMIT] = array(
'#type' => 'textfield',
'#title' => t('Favorite Nodes Page Limit'),
'#default_value' => variable_get(FAVORITE_NODES_PAGE_LIMIT, 10),
'#description' => t('How many items to display on a single page of marked favorites.'),
);
$form[$set][FAVORITE_NODES_PROFILE_LIMIT] = array(
'#type' => 'textfield',
'#title' => t('Favorite Nodes Profile Limit'),
'#default_value' => variable_get(FAVORITE_NODES_PROFILE_LIMIT, 3),
'#description' => t('How many items per type to display on the profile page.'),
);
$form[$set][FAVORITE_NODES_VIEW_IN_PROFILE] = array(
'#type' => 'checkbox',
'#title' => t('View favorite nodes in profile informations'),
'#default_value' => variable_get(FAVORITE_NODES_VIEW_IN_PROFILE, 1),
'#description' => t('If you select this option, favorite nodes will be displayed into the user profile informations. This is the default behavior.'),
);
$form[$set][FAVORITE_NODES_VIEW_IN_LOCAL_TASK] = array(
'#type' => 'checkbox',
'#title' => t('View favorite nodes in a tab in user profile'),
'#default_value' => variable_get(FAVORITE_NODES_VIEW_IN_LOCAL_TASK, 0),
'#description' => t('If you select this option, a new tab in users page will be added. Note that you can cumulate this option with the previous one, but you may choose one of the two.'),
);
$form[$set][FAVORITE_NODES_PAGE_TYPE] = array(
'#type' => 'select',
'#title' => t('Type of Page Display for Favorite Nodes'),
'#options' => array(
'table' => 'Table',
'teasers' => 'Teasers',
),
'#default_value' => variable_get(FAVORITE_NODES_PAGE_TYPE, 'table'),
'#description' => t('How should favorites be displayed on the favorite nodes page?'),
);
$form[$set][FAVORITE_NODES_LIST_EMPTY_TITLES] = array(
'#type' => 'checkbox',
'#title' => t('Display empty tables in user favorite listing ?'),
'#default_value' => variable_get(FAVORITE_NODES_LIST_EMPTY_TITLES, 0),
'#description' => t('By default, all node types are listed on the user favorite nodes table view. In many cases, you may want to limit the lists to those that have favorite nodes actually bookmarked. Selecting this option will allow all the lists to appear regardless of whether they contain nodes or not. Unselecting this option will restirct the list to only those actually containing nodes.'),
);
$form[$set][FAVORITE_NODES_MENUS] = array(
'#type' => 'checkbox',
'#title' => t('Navigation menu items'),
'#return_value' => 1,
'#default_value' => variable_get(FAVORITE_NODES_MENUS, 0),
'#description' => t('Whether to show a menu item in the navigation block for each node type?'),
);
$form[$set][FAVORITE_NODES_SHOWLINK] = array(
'#type' => 'checkbox',
'#title' => t('Display Favorite Node options as links'),
'#return_value' => 1,
'#default_value' => variable_get(FAVORITE_NODES_SHOWLINK, 1),
'#description' => t('Whether to show link items in the node view?'),
);
$set = 'types';
$form[$set] = array(
'#type' => 'fieldset',
'#title' => t('Enable favorites for these node types'),
'#collapsible' => true,
'#collapsed' => false,
);
foreach (_node_types_natcasesort() as $type) {
$form[$set][FAVORITE_NODES_NODE_TYPE . $type->type] = array(
'#type' => 'checkbox',
'#title' => $type->name,
'#return_value' => 1,
'#default_value' => variable_get(FAVORITE_NODES_NODE_TYPE . $type->type, 0),
);
}
return system_settings_form($form);
}
/**
* Add a favorite node.
*/
function favorite_nodes_add($nid) {
global $user;
// We can come here via xmlrpc, so we validate access checks again
if (!user_access(FAVORITE_NODES_PERM_ADD)) {
return FALSE;
}
$node = node_load($nid);
if (!$node->nid) {
return FALSE;
}
db_query("DELETE FROM {favorite_nodes} WHERE nid = %d AND uid = %d", $nid, $user->uid);
db_query("INSERT INTO {favorite_nodes} (nid, uid, last) VALUES (%d, %d, %d)", $nid, $user->uid, time());
/**
* Invoke hook_favorite_nodes(), which has the following parameters:
* @param op
* The operation being performed. Can be either 'add' or 'delete'.
* @param node
* The node object being added or deleted.
*/
module_invoke_all('favorite_nodes', 'add', $node);
return TRUE;
}
/**
* Delete a favorite node.
*/
function favorite_nodes_delete($nid) {
global $user;
$node = node_load($nid);
if (!$node->nid) {
return FALSE;
}
db_query("DELETE FROM {favorite_nodes} WHERE nid = %d AND uid = %d", $nid, $user->uid);
/**
* Invoke hook_favorite_nodes(), which has the following parameters:
* @param op
* The operation being performed. Can be either 'add' or 'delete'.
* @param node
* The node object being added or deleted.
*/
module_invoke_all('favorite_nodes', 'delete', $node);
return TRUE;
}
/**
* Select all the favorite nodes a user has.
*/
function favorite_nodes_get($uid, $type = null, $limit = null) {
if (is_null($limit)) {
$limit = variable_get(FAVORITE_NODES_PAGE_LIMIT, 10);
}
$row = array();
if ($type && variable_get(FAVORITE_NODES_NODE_TYPE . $type, 0)) {
$sql = "SELECT n.nid, n.title, f.uid, f.last FROM {node} n INNER JOIN {favorite_nodes} f ON n.nid = f.nid WHERE n.type = '%s' AND f.uid = %d ORDER by f.last DESC";
$sql_count = "SELECT COUNT(*) FROM {node} n INNER JOIN {favorite_nodes} f ON n.nid = f.nid WHERE n.type = '%s' AND f.uid = %d";
$result = pager_query($sql, $limit, 0, $sql_count, $type, $uid);
if ($result && db_num_rows($result) > 0) {
while ($data = db_fetch_object($result)) {
$row[$data->nid] = $data;
}
}
}
return $row;
}
/**
* Page to add a favorite node.
*/
function favorite_nodes_add_page() {
$nid = arg(2);
if (is_numeric($nid)) {
$result = favorite_nodes_add($nid);
if ($result) {
$node = node_load($nid);
$type = node_get_types('name', $node);
drupal_set_message(t('The !type was added to your favorites.', array("!type" => $type)));
}
else {
}
drupal_goto('node/'. $nid);
}
drupal_not_found();
}
/**
* Page to delete a favorite node.
*/
function favorite_nodes_delete_page() {
global $user;
$nid = arg(2);
favorite_nodes_delete($nid);
$node = node_load($nid);
$type = node_get_types('name', $node);
drupal_set_message(t('The !type was removed from your favorites.', array("!type" => $type)));
drupal_goto("user/$user->uid");
}
/*
* Page to display all user's favorite list.
*/
function favorite_nodes_view_all_page($uid) {
$output = "";
if (($uid = intval($uid)) > 0) {
$fav_list = array();
foreach (_node_types_natcasesort() as $type) {
if (variable_get(FAVORITE_NODES_NODE_TYPE . $type->type, 0)) {
$favorites = favorite_nodes_get($uid, $type->type, variable_get(FAVORITE_NODES_BLOCK_LIMIT, 5));
$output .= theme('favorite_nodes_view_'. variable_get(FAVORITE_NODES_PAGE_TYPE, 'table'), $favorites, $uid, $type->type);
}
}
}
return $output;
}
/**
* Page to display a user's favorite list.
*/
function favorite_nodes_view_page() {
$type = arg(3);
$uid = arg(2);
$output = theme('favorite_nodes_view_'. variable_get(FAVORITE_NODES_PAGE_TYPE, 'table'), favorite_nodes_get($uid, $type), $uid, $type);
return $output;
}
/**
* Delete favorite nodes a user has.
*/
function favorite_nodes_delete_favorites($uid) {
db_query("DELETE FROM {favorite_nodes} WHERE uid = %d", $uid);
}
/**
* Get all the favorite nodes inner joining the users.
* TODO: currently not being used.. do we need this?
*/
function _favorite_nodes_get_users($nid) {
$sql = "SELECT u.*, f.last FROM {users} u INNER JOIN {favorite_nodes} f USING(uid) WHERE f.nid = %d ORDER by f.last DESC";
$result = db_query($sql, $nid);
$row = array();
while ($data = db_fetch_object($result)) {
$row[$data->uid] = $data;
}
return $row;
}
/**
* Check if a user already has a node in their favorite list.
*/
function _favorite_nodes_check($nid) {
global $user;
$sql = "SELECT COUNT(*) FROM {favorite_nodes} WHERE uid = %d AND nid = %d";
return db_result(db_query($sql, $user->uid, $nid));
}
/**
* TODO: This is not being used.. do we need it?
* Notice: we should, 'teaser' view is a good feature.
*/
function theme_favorite_nodes_view_teasers($list = array(), $uid = null, $type = null) {
$type_desc = variable_get(FAVORITE_NODES_BLOCK . $type, $type);
$user = user_load(array('uid' => $uid));
if (!$type) {
$output .= t('Please select favorite type.');
}
else {
if (!empty($list)) {
$output .= ''. t('Favorite !type for !user', array('!type' => $type_desc, '!user' => theme('username', $user))) ."
\n";
foreach ($list as $nid => $data) {
$node = node_load($nid);
$output .= node_view($node, true);
}
}
else {
$output .= t('No favorites of type !type.', array('!type' => $type_desc));
}
}
$output .= theme('pager');
return $output;
}
/**
* Table which displays favorite node lists.
*/
function theme_favorite_nodes_view_table($list = array(), $uid = null, $type = null) {
if (! $uid) {
global $user;
}
else {
$user = user_load(array('uid' => $uid));
}
$header = array(t('Title'), t('Added'), t('Operations'));
$rows = array();
if (isset($list)) {
foreach ($list as $nid => $data) {
$title = array(l($data->title, "node/$nid"), format_date($data->last, 'custom', 'Y-m-d H:i'));
if ($user->uid == $data->uid || $user->uid == 1) {
$delete = array(l(t('delete'), "favorite_nodes/delete/$nid"));
$result = array_merge($title, $delete);
}
else {
$result = $title;
}
$rows[] = array('data' => $result);
}
}
if (variable_get(FAVORITE_NODES_LIST_EMPTY_TITLES, 0) || !empty($rows)) {
$output .= ''. t('Favorite !types for !user', array(
'!type' => variable_get(FAVORITE_NODES_BLOCK . $type, node_get_types('name', $type)),
'!user' => theme('username', $account))) ."
\n";
$output .= theme('table', $header, $rows);
$output .= theme('pager');
}
return $output;
}
function favorite_nodes_views_tables() {
$tables['usernode_favorite_nodes'] = array(
'name' => 'favorite_nodes',
'join' => array(
'left' => array(
'table' => 'usernode',
'field' => 'uid',
),
'right' => array(
'field' => 'uid',
),
),
);
$tables['favorite_nodes'] = array(
'name' => 'favorite_nodes',
'provider' => 'internal',
'join' => array(
'left' => array(
'table' => 'node',
'field' => 'nid',
),
'right' => array(
'field' => 'nid',
),
),
'fields' => array(
'last' => array(
'name' => t('Favorite Nodes: Time Added'),
'sortable' => true,
'handler' => views_handler_field_dates(),
'option' => 'string',
'help' => t('Display the date/time the favorite node was added.'),
),
'count' => array(
'name' => t('Favorite Nodes: Count'),
'handler' => 'favorite_nodes_handler_user_count',
'help' => t('Number of times this node was added to favorites by any user.'),
'sortable' => FALSE,
'notafield' => TRUE,
),
),
'sorts' => array(
'last' => array(
'name' => t('Favorite Nodes: Time Added'),
'help' => t('Sort by the date/time the favorite node was added.'),
),
),
'filters' => array(
'uid' => array(
'field' => 'uid',
'name' => t('Favorite Nodes: User ID'),
'operator' => 'views_handler_operator_eqneq',
'handler' => 'views_handler_filter_favorite_nodes',
'list-type' => 'select',
'list' => array(
'uid_current' => t('Currently Logged In User'),
'uid_all' => t('All Users'),
),
'help' => t('This allows you to filter based on favorites nodes.'),
),
'last' => array(
'name' => t('Favorite Nodes: Time Added'),
'operator' => 'views_handler_operator_gtlt',
'value' => views_handler_filter_date_value_form(),
'handler' => 'views_handler_filter_timestamp',
'option' => 'string',
'help' => t('This filter allows favorite nodes to be filtered by the date and time the user added them. Enter dates in the format: CCYY-MM-DD HH:MM:SS. Enter \'now\' to use the current time. You may enter a delta (in seconds) to the option that will be added to the time; this is most useful when combined with now.'),
),
),
);
return $tables;
}
function views_handler_filter_favorite_nodes($op, $filter, $filterinfo, &$query) {
global $user;
$table_data = _views_get_tables();
$joininfo = $table_data['favorite_nodes']['join'];
$joininfo['type'] = 'inner';
$table_num = $query->add_table('favorite_nodes', FALSE, 1, $joininfo);
$table = $query->get_table_name('favorite_nodes', $table_num);
$query->set_distinct();
switch($filter['value']) {
case 'uid_current':
$query->add_where("$table.uid = ***CURRENT_USER***");
break;
case 'uid_all':
// No special processing needed, since we do an inner join anyways
break;
}
}
function favorite_nodes_views_arguments() {
$args['user_id'] = array(
'name' => t("Favorite Nodes: User ID"),
'handler' => 'favorite_nodes_handler_argument_uid',
'help' => t('User ID for Favorite node.'),
);
$args['node_id'] = array(
'name' => t("Favorite Nodes: Node ID"),
'handler' => 'favorite_nodes_handler_argument_nid',
'help' => t('Node ID for Favorite node. Requires the usernode module!'),
);
return $args;
}
function favorite_nodes_handler_argument_uid($op, &$query, $argtype, $arg = '') {
switch ($op) {
case 'sort':
// no luck using add_orderby method.
$query->orderby[] = ' num_nodes '. $argtype;
break;
case 'filter':
list($and_or, $uids) = _views_break_phrase($arg);
$and_or = strtoupper($and_or);
// Similar to taxonomy AND/OR query.
if ($and_or == 'OR') {
$query->ensure_table('favorite_nodes');
$cond = array_fill(0, count($uids), "favorite_nodes.uid = %d");
$query->add_where(implode(" $and_or ", $cond), $uids);
}
else {
foreach ((array)$uids as $uid) {
$num = $query->add_table('favorite_nodes');
$tablename = $query->get_table_name('favorite_nodes', $num);
$query->add_where("$tablename.uid = %d", $uid);
}
}
break;
}
}
function favorite_nodes_handler_argument_nid($op, &$query, $argtype, $arg = '') {
switch ($op) {
case 'filter':
$nid = intval($arg);
$table_data = _views_get_tables();
$joininfo = $table_data['usernode_favorite_nodes']['join'];
$joininfo['type'] = 'inner';
$joininfo['extra'] = array('nid' => $nid);
$query->add_table("usernode_favorite_nodes", true, 1, $joininfo);
break;
}
}
function favorite_nodes_handler_user_count($fieldinfo, $fielddata, $value, $data) {
return db_result(db_query("SELECT COUNT(*) FROM {favorite_nodes} WHERE nid = %d", $data->nid));
}