Spent the morning looking through the modules section and reading up on Views. I'd like to implement a view that will display a user's read items and one that displays the unread items. Does any such module exist already? If not could such a view be created with a combination of existing modules, or would I have to create an entirely new module from scratch?

I considered CCK, but I don't think that could work, what is really needed is some sort of xref table for users and nodes. My understanding is that CCK is just a single value per node. Correct?

Comments

sfeldkamp’s picture

Well it seems like I ought to be able to do this by enabling the tracker module and some sort of Argument Handling Code in the Views module. I'll post the solution if I figure it out. Any help in the meantime is appreciated...

sfeldkamp’s picture

And I'll post the solution here in case anyone else is struggling against this sort of thing...

In the views_user.inc file in views/modules:

I added the following sub-array to the filters array. This defines the filter for the Views_UI.module.

'uid_history' => array(
      	'name' => t('Node: Current User'),     //Display Name of the filter
      	'help' => t('This allows you to filter by whether or not the current user has viewed the node.'),    //Help text for explaining what the filter does
      	'operator' => array('0' => t('Unread By'),'1' => t('Read By')),    //an array of options for the operator.  Value / Display Name.  So if the user selects 'Unread By' the variable $Filter[' operator'] is 0.
      	'list' => 'views_handler_filter_usercurrent',   // a function that returns an array of with a description and the current user's uid
      	'list-type' => 'select',   // specifies that filter value array should be output as a select box.
      	'handler' => 'views_handler_filter_uid_history',   // the function that get's called to modify the query before it's executed.
      ),

then I created this function

/*	
 * Filter by whether or not the user has read the node.
 */
 function views_handler_filter_uid_history($op, $filter, $filterinfo, &$query) {
  $table_data = _views_get_tables();    // I think this get's the tables currently joined together for the query
  $joininfo = $table_data['history']['join'];   // this specifies the main join which is always going to be on node.nid = this_tables.nid.  In this case it was history.nid.
  $joininfo['extra'] = array('uid' => $filter['value']);   // this adds a second condition of the join, namely that the records in history should have history.uid = the current user's uid that was passed in.
  $tblnum = $query->add_table("history",false,1,$joininfo);  // I think that this actually joins the table
  $table = $query->get_table_name('history',$tablenum);  // This appears to set a variable for the history table, it's probably superflous.
 
 if ($filter['operator'] == 1) {  // since all joins are left joins by default I can look for either matching records (like an inner join) if filter is set to display the users' read items
  	$query->add_where("$table.timestamp is not null");
  } 
  else {   // or I can look for nodes where there is no matching history record to get the ones that are unread
  	$query->add_where("$table.timestamp is null");
  }
}

In the end the solution didn't have anything to do with the tracker module (I think history table is populated regardless of whether or not that module is enabled) or Arguments since the variable current user's uid was not passed in through the url (or added programmatically to the $arguments array). Not bad for my first ever PHP code block.

Edit: One final note: apparently history records are discarded after 30days if the node hasn't been updated. I'll add in some logic so that it only looks for unread items from the past 30 days or so. You could also do this with a secondary filter or other criteria in Views.