| 1 |
<?php
|
| 2 |
// $Id: bio_views.inc,v 1.1.2.7 2008/03/19 18:46:38 dww Exp $
|
| 3 |
|
| 4 |
/**
|
| 5 |
* @file
|
| 6 |
* Views integration for Bio module.
|
| 7 |
*
|
| 8 |
* The Bio module integrates with Views by re-exposing the Bio node for an
|
| 9 |
* author as part of any Views query.
|
| 10 |
*
|
| 11 |
* For example, it is possible to perform queries like:
|
| 12 |
* - Find all blog posts by authors who have Bio nodes tagged with the term
|
| 13 |
* "kayaking."
|
| 14 |
* - Find all the Bio nodes by authors who have a first name (where "first
|
| 15 |
* name" is a field) like "joe."
|
| 16 |
* - Find all the forum posts by the most popular authors, ranked by most
|
| 17 |
* viewed Bio pages.
|
| 18 |
*
|
| 19 |
* This file also provides two filters:
|
| 20 |
* - Node: Type is Bio node:
|
| 21 |
* This is useful for shipping premade views that rely on Bio, but are not
|
| 22 |
* tied to a particular type of node acting as the Bio node (e.g. on one site
|
| 23 |
* it might be "Biography," and on another "profile").
|
| 24 |
* - Bio: Author has Bio node:
|
| 25 |
* This is useful for only returning results where the author has created a
|
| 26 |
* Bio node. That way, if you are exposing Bio fields (e.g. the "interests"
|
| 27 |
* taxonomy), you can be sure that a Bio node exists for every other node
|
| 28 |
* returned in the query.
|
| 29 |
*
|
| 30 |
* See the README for more information on creating Views with Bio information.
|
| 31 |
*/
|
| 32 |
|
| 33 |
/**
|
| 34 |
* Real implementation of hook_views_table_alter().
|
| 35 |
*/
|
| 36 |
function _bio_views_tables_alter(&$tables) {
|
| 37 |
// Amass some data to use later.
|
| 38 |
$bio_type = bio_get_type();
|
| 39 |
$bio_name = node_get_types('name', $bio_type);
|
| 40 |
|
| 41 |
if (module_exists('taxonomy')) {
|
| 42 |
$vocabs = array_keys(taxonomy_get_vocabularies($bio_type));
|
| 43 |
}
|
| 44 |
|
| 45 |
// Fetch some CCK info if CCK is installed.
|
| 46 |
$bio_fields = array();
|
| 47 |
if (module_exists('content')) {
|
| 48 |
$content_type_info = content_types($bio_type);
|
| 49 |
if (is_array($content_type_info['fields'])) {
|
| 50 |
$bio_fields = array_keys($content_type_info['fields']);
|
| 51 |
}
|
| 52 |
}
|
| 53 |
|
| 54 |
// The first step is to copy the node table and alias it as the "node" table.
|
| 55 |
// This allows us to access all node table data. Later, we can point other
|
| 56 |
// modules at the "bio" table and it will behave just like the node table.
|
| 57 |
$old_node = $tables['node'];
|
| 58 |
// TODO: Not sure what this does, remove it.
|
| 59 |
unset($old_node['provider']);
|
| 60 |
$old_node['join'] = array(
|
| 61 |
// TODO: Default option is left. I think inner is probably better?
|
| 62 |
//'type' => 'inner',
|
| 63 |
'left' => array(
|
| 64 |
'table' => 'node',
|
| 65 |
'field' => 'uid'
|
| 66 |
),
|
| 67 |
'right' => array(
|
| 68 |
'field' => 'uid'
|
| 69 |
),
|
| 70 |
'extra' => array(
|
| 71 |
// TODO: Will I need to specify bio.type instead of type?
|
| 72 |
'type' => $bio_type,
|
| 73 |
),
|
| 74 |
);
|
| 75 |
|
| 76 |
// Remove some fields, filters, and sorts that don't make sense for a joined
|
| 77 |
// Bio table.
|
| 78 |
|
| 79 |
// Node: Type.
|
| 80 |
unset($old_node['fields']['type']);
|
| 81 |
// Node: Type.
|
| 82 |
unset($old_node['filters']['type']);
|
| 83 |
// Node: Author is anonymous.
|
| 84 |
unset($old_node['filters']['anon']);
|
| 85 |
// Node: Author is current user.
|
| 86 |
unset($old_node['filters']['currentuid']);
|
| 87 |
// Node: Current user authored or commented.
|
| 88 |
unset($old_node['filters']['currentuidtouched']);
|
| 89 |
// Node: Type.
|
| 90 |
unset($old_node['sorts']['type']);
|
| 91 |
// Node: Random.
|
| 92 |
unset($old_node['sorts']['random']);
|
| 93 |
|
| 94 |
// For bio_node, nid is a real column.
|
| 95 |
unset($old_node['fields']['nid']['notafield']);
|
| 96 |
|
| 97 |
// Prefix descriptions with "Bio:" to differentiate them from standard stuff.
|
| 98 |
_bio_rename_table_labels($old_node, $bio_name);
|
| 99 |
|
| 100 |
// Save our worked up node table back in the array.
|
| 101 |
$tables['bio'] = $old_node;
|
| 102 |
|
| 103 |
// Bio copies all other tables and renames them bio_foo. This allows us to
|
| 104 |
// re-expose all the data of the Bio node in a forward compatible,
|
| 105 |
// transparent manner. We assume all tables connect to node (via
|
| 106 |
// intermediate tables). For now, a safe assumption.
|
| 107 |
|
| 108 |
// Without this copy, Apache would spin off and die a horrible death.
|
| 109 |
$table_copy = $tables;
|
| 110 |
foreach ($table_copy as $name => $data) {
|
| 111 |
|
| 112 |
// We can skip the node and bio tables. Other tables can be skipped, too.
|
| 113 |
// TODO: Is there a use case for including comments? Comment stats are
|
| 114 |
// pretty useful, but do we really need: "show me the comments on the
|
| 115 |
// profiles of authors who wrote a blog post about foo?"
|
| 116 |
if (in_array($name, array('node', 'bio', 'users', 'users_roles', 'comments', 'book', 'book_parent_node', 'temp_search_results'))) {
|
| 117 |
continue;
|
| 118 |
}
|
| 119 |
|
| 120 |
// skip anything that joins against UID, we don't need that (e.g. profile_xxx)
|
| 121 |
if ($data['join']['left']['table'] == 'node' && $data['join']['left']['field'] == 'uid') {
|
| 122 |
continue;
|
| 123 |
}
|
| 124 |
|
| 125 |
// we should skip tables that don't relate to bio node types specifically
|
| 126 |
// e.g. taxonomy vocabs that don't apply, cck fields that aren't in the bio node type, etc.
|
| 127 |
|
| 128 |
// Skip unneeded taxonomy vocabularies.
|
| 129 |
if (strpos($name, 'term_node_') === 0) {
|
| 130 |
$vid = substr($name, 10);
|
| 131 |
if (!in_array($vid, $vocabs)) {
|
| 132 |
continue;
|
| 133 |
}
|
| 134 |
}
|
| 135 |
// Skip fields not assigned to the Bio node type.
|
| 136 |
elseif (strpos($name, 'node_data_') === 0) {
|
| 137 |
$field = substr($name, 10);
|
| 138 |
if (!in_array($field, $bio_fields)) {
|
| 139 |
continue;
|
| 140 |
}
|
| 141 |
}
|
| 142 |
|
| 143 |
// If the table joins directly to node, make it's new join point "bio."
|
| 144 |
// If it joins against something else, assume that we'll create a "bio_X"
|
| 145 |
// for it at some point.
|
| 146 |
if ($data['join']['left']['table'] == 'node') {
|
| 147 |
$data['join']['left']['table'] = 'bio';
|
| 148 |
}
|
| 149 |
else {
|
| 150 |
$data['join']['left']['table'] = 'bio_'. $data['join']['left']['table'];
|
| 151 |
}
|
| 152 |
_bio_rename_table_labels($data, $bio_name);
|
| 153 |
$tables["bio_$name"] = $data;
|
| 154 |
}
|
| 155 |
|
| 156 |
// Now that all the bio_* tables are ready, add some other useful filters to
|
| 157 |
// the mix.
|
| 158 |
|
| 159 |
// Node: Type is Bio node -- cribbed from views_node.inc.
|
| 160 |
$tables['node']['filters']['biotype'] = array(
|
| 161 |
'field' => 'type',
|
| 162 |
'name' => t('Node: Type is Bio node'),
|
| 163 |
'operator' => array('=' => t('Is'), '!=' => t('Is not')),
|
| 164 |
'value' => _bio_provide_hidden_form($bio_type, $bio_name),
|
| 165 |
'help' => t('This allows you to filter by whether or not the node is a bio node. Select "Is" to limit to bio nodes, select "is not" to limit to all other content types'),
|
| 166 |
);
|
| 167 |
|
| 168 |
// Bio: Author has a Bio -- limits the results (e.g. blog posts) to those
|
| 169 |
// where the author has a Bio. Relies on http://drupal.org/node/142504.
|
| 170 |
$tables['bio']['filters']['author_has_bio'] = array(
|
| 171 |
'field' => 'uid',
|
| 172 |
'name' => t('Bio: Author has a Bio'),
|
| 173 |
'operator' => array('IS NOT' => t('Does'), 'IS' => t('Does not')),
|
| 174 |
'value' => _bio_provide_hidden_form(NULL, t('Have a bio node')),
|
| 175 |
'help' => t('Filter in only nodes for which the author has or does not have a bio node.'),
|
| 176 |
'handler' => 'views_handler_filter_null',
|
| 177 |
);
|
| 178 |
|
| 179 |
// Override the default handler on the "is new" filter, as it needs some very
|
| 180 |
// specific table names.
|
| 181 |
$tables['bio_history']['filters']['timestamp']['handler'] = 'bio_handler_filter_isnew';
|
| 182 |
}
|
| 183 |
|
| 184 |
/**
|
| 185 |
* Helper function to rename Node: Title => Bio: Node: Title, etc.
|
| 186 |
*/
|
| 187 |
function _bio_rename_table_labels(&$table, $bio_name) {
|
| 188 |
foreach (array('fields', 'sorts', 'filters') as $section) {
|
| 189 |
if (is_array($table[$section])) {
|
| 190 |
foreach ($table[$section] as $id => $object) {
|
| 191 |
$table[$section][$id]['name'] = $bio_name .': '. $object['name'];
|
| 192 |
}
|
| 193 |
}
|
| 194 |
}
|
| 195 |
}
|
| 196 |
|
| 197 |
/**
|
| 198 |
* Used to force the value of certain form fields by converting to markup.
|
| 199 |
*/
|
| 200 |
function _bio_provide_hidden_form($value, $markup) {
|
| 201 |
$form['text'] = array(
|
| 202 |
'#type' => 'markup',
|
| 203 |
'#value' => $markup,
|
| 204 |
);
|
| 205 |
$form['value'] = array(
|
| 206 |
'#type' => 'value',
|
| 207 |
'#value' => $value,
|
| 208 |
);
|
| 209 |
|
| 210 |
return $form;
|
| 211 |
}
|
| 212 |
|
| 213 |
/**
|
| 214 |
* Custom filter for new content. Copied directly from views_node.inc and modified to use bio_* tables.
|
| 215 |
*/
|
| 216 |
function _bio_handler_filter_isnew($op, $filter, $filterinfo, &$query) {
|
| 217 |
global $user;
|
| 218 |
if (!$user || !$user->uid) {
|
| 219 |
return;
|
| 220 |
}
|
| 221 |
|
| 222 |
// Hey, Drupal kills old history, so nodes that haven't been updated
|
| 223 |
// since NODE_NEW_LIMIT are bzzzzzzzt outta here!
|
| 224 |
|
| 225 |
$limit = time() - NODE_NEW_LIMIT;
|
| 226 |
|
| 227 |
$query->ensure_table('bio_history');
|
| 228 |
if (module_exists('comment')) {
|
| 229 |
$query->ensure_table('bio_node_comment_statistics');
|
| 230 |
$clause = ("OR bio_node_comment_statistics.last_comment_timestamp > (***CURRENT_TIME*** - $limit)");
|
| 231 |
$clause2 = "OR bio_history.timestamp < bio_node_comment_statistics.last_comment_timestamp";
|
| 232 |
}
|
| 233 |
|
| 234 |
// NULL means a history record doesn't exist. That's clearly new content.
|
| 235 |
// Unless it's very very old content. Everything in the query is already
|
| 236 |
// type safe cause none of it is coming from outside here.
|
| 237 |
$query->add_where("(bio_history.timestamp IS NULL AND (bio.changed > (***CURRENT_TIME***-$limit) $clause)) OR bio_history.timestamp < bio.changed $clause2");
|
| 238 |
}
|
| 239 |
|
| 240 |
/**
|
| 241 |
* Real implementation of hook_views_query_alter().
|
| 242 |
*
|
| 243 |
* For any bio_* table, we need to make sure the bio_nid is added.
|
| 244 |
*/
|
| 245 |
function _bio_views_query_alter(&$query, $view, $summary, $level) {
|
| 246 |
// See if we need to add the Bio module.
|
| 247 |
if (_bio_should_add_nid($query, $view)) {
|
| 248 |
$query->ensure_table('bio');
|
| 249 |
$query->add_field('nid', 'bio', 'bio_nid');
|
| 250 |
}
|
| 251 |
}
|
| 252 |
|
| 253 |
/**
|
| 254 |
* Helper function to determine if we need bio.nid in the query.
|
| 255 |
*
|
| 256 |
* @todo This looks like a bit of a hack. What happens if I install the biology
|
| 257 |
* module? :P
|
| 258 |
*/
|
| 259 |
function _bio_should_add_nid($query, $view) {
|
| 260 |
foreach ($view->field as $field) {
|
| 261 |
if (strpos($field['tablename'], 'bio') === 0) {
|
| 262 |
return true;
|
| 263 |
}
|
| 264 |
}
|
| 265 |
|
| 266 |
foreach ($view->filter as $filter) {
|
| 267 |
if (strpos($filter['tablename'], 'bio') === 0) {
|
| 268 |
return true;
|
| 269 |
}
|
| 270 |
}
|
| 271 |
|
| 272 |
return false;
|
| 273 |
}
|
| 274 |
|
| 275 |
/**
|
| 276 |
* Real implemenation of hook_views_default_tables().
|
| 277 |
*
|
| 278 |
* Default views are:
|
| 279 |
* - recent_biographies:
|
| 280 |
* A listing of teasers of recent Bio nodes, regradless of what the Bio node
|
| 281 |
* type is.
|
| 282 |
* - author_tracker:
|
| 283 |
* Just like the usual tracker, but using Bio node titles instead of the user
|
| 284 |
* name for the "author" column.
|
| 285 |
*
|
| 286 |
* These Views are disabled by default.
|
| 287 |
*/
|
| 288 |
function _bio_views_default_views() {
|
| 289 |
// A little set up to make these views look nicer :-)
|
| 290 |
$bio_type = bio_get_type();
|
| 291 |
$bio_name = node_get_types('name', $bio_type);
|
| 292 |
|
| 293 |
$view = new stdClass();
|
| 294 |
$view->disabled = true;
|
| 295 |
$view->name = 'recent_biographies';
|
| 296 |
$view->description = 'A list of recently created biographies, from the bio module. The url changes to whatever your bio node type is, as does the title.';
|
| 297 |
$view->access = array(
|
| 298 |
);
|
| 299 |
$view->view_args_php = '';
|
| 300 |
$view->page = TRUE;
|
| 301 |
$view->page_title = "Recent $bio_name Entries";
|
| 302 |
$view->page_header = '';
|
| 303 |
$view->page_header_format = '1';
|
| 304 |
$view->page_footer = '';
|
| 305 |
$view->page_footer_format = '1';
|
| 306 |
$view->page_empty = '';
|
| 307 |
$view->page_empty_format = '1';
|
| 308 |
$view->page_type = 'teaser';
|
| 309 |
$view->url = $bio_type;
|
| 310 |
$view->use_pager = TRUE;
|
| 311 |
$view->nodes_per_page = '10';
|
| 312 |
$view->sort = array(
|
| 313 |
array(
|
| 314 |
'tablename' => 'node',
|
| 315 |
'field' => 'created',
|
| 316 |
'sortorder' => 'DESC',
|
| 317 |
'options' => 'normal',
|
| 318 |
),
|
| 319 |
);
|
| 320 |
$view->argument = array(
|
| 321 |
);
|
| 322 |
$view->field = array(
|
| 323 |
);
|
| 324 |
$view->filter = array(
|
| 325 |
array(
|
| 326 |
'tablename' => 'node',
|
| 327 |
'field' => 'biotype',
|
| 328 |
'operator' => '=',
|
| 329 |
'options' => '',
|
| 330 |
'value' => 'bio',
|
| 331 |
),
|
| 332 |
);
|
| 333 |
$view->exposed_filter = array(
|
| 334 |
);
|
| 335 |
$view->requires = array(node);
|
| 336 |
$views[$view->name] = $view;
|
| 337 |
|
| 338 |
$view = new stdClass();
|
| 339 |
$view->disabled = true;
|
| 340 |
$view->name = 'tracker_bio';
|
| 341 |
$view->description = 'Shows all new activity on system using the bio node title as the author name.';
|
| 342 |
$view->access = array(
|
| 343 |
);
|
| 344 |
$view->view_args_php = '';
|
| 345 |
$view->page = TRUE;
|
| 346 |
$view->page_title = 'Recent posts';
|
| 347 |
$view->page_header = '';
|
| 348 |
$view->page_header_format = '1';
|
| 349 |
$view->page_footer = '';
|
| 350 |
$view->page_footer_format = '1';
|
| 351 |
$view->page_empty = '';
|
| 352 |
$view->page_empty_format = '1';
|
| 353 |
$view->page_type = 'table';
|
| 354 |
$view->url = 'tracker';
|
| 355 |
$view->use_pager = TRUE;
|
| 356 |
$view->nodes_per_page = '25';
|
| 357 |
$view->menu = TRUE;
|
| 358 |
$view->menu_title = 'Recent posts';
|
| 359 |
$view->menu_tab = FALSE;
|
| 360 |
$view->menu_tab_weight = '0';
|
| 361 |
$view->menu_tab_default = FALSE;
|
| 362 |
$view->menu_tab_default_parent = NULL;
|
| 363 |
$view->menu_parent_tab_weight = '0';
|
| 364 |
$view->menu_parent_title = '';
|
| 365 |
$view->sort = array(
|
| 366 |
array(
|
| 367 |
'tablename' => 'node_comment_statistics',
|
| 368 |
'field' => 'last_comment_timestamp',
|
| 369 |
'sortorder' => 'DESC',
|
| 370 |
'options' => 'normal',
|
| 371 |
),
|
| 372 |
);
|
| 373 |
$view->argument = array(
|
| 374 |
array(
|
| 375 |
'type' => 'uid',
|
| 376 |
'argdefault' => '2',
|
| 377 |
'title' => 'recent posts for %1',
|
| 378 |
'options' => '',
|
| 379 |
'wildcard' => '',
|
| 380 |
'wildcard_substitution' => '',
|
| 381 |
),
|
| 382 |
);
|
| 383 |
$view->field = array(
|
| 384 |
array(
|
| 385 |
'tablename' => 'node',
|
| 386 |
'field' => 'type',
|
| 387 |
'label' => 'Type',
|
| 388 |
),
|
| 389 |
array(
|
| 390 |
'tablename' => 'node',
|
| 391 |
'field' => 'title',
|
| 392 |
'label' => 'Title',
|
| 393 |
'handler' => 'views_handler_field_nodelink_with_mark',
|
| 394 |
'options' => 'link',
|
| 395 |
),
|
| 396 |
array(
|
| 397 |
'tablename' => 'bio',
|
| 398 |
'field' => 'title',
|
| 399 |
'label' => 'Author',
|
| 400 |
'handler' => 'views_handler_field_nodelink',
|
| 401 |
'options' => 'link',
|
| 402 |
),
|
| 403 |
array(
|
| 404 |
'tablename' => 'node_comment_statistics',
|
| 405 |
'field' => 'comment_count',
|
| 406 |
'label' => 'Replies',
|
| 407 |
'handler' => 'views_handler_comments_with_new',
|
| 408 |
),
|
| 409 |
array(
|
| 410 |
'tablename' => 'node_comment_statistics',
|
| 411 |
'field' => 'last_comment_timestamp',
|
| 412 |
'label' => 'Last Post',
|
| 413 |
'handler' => 'views_handler_field_since',
|
| 414 |
),
|
| 415 |
);
|
| 416 |
$view->filter = array(
|
| 417 |
array(
|
| 418 |
'tablename' => 'node',
|
| 419 |
'field' => 'status',
|
| 420 |
'operator' => '=',
|
| 421 |
'options' => '',
|
| 422 |
'value' => '1',
|
| 423 |
),
|
| 424 |
array(
|
| 425 |
'tablename' => 'node',
|
| 426 |
'field' => 'biotype',
|
| 427 |
'operator' => '!=',
|
| 428 |
'options' => '',
|
| 429 |
'value' => 'bio',
|
| 430 |
),
|
| 431 |
);
|
| 432 |
$view->exposed_filter = array(
|
| 433 |
);
|
| 434 |
$view->requires = array(node_comment_statistics, node, bio);
|
| 435 |
$views[$view->name] = $view;
|
| 436 |
|
| 437 |
return $views;
|
| 438 |
}
|
| 439 |
|
| 440 |
/**
|
| 441 |
* Real implemenation of hook_views_tables().
|
| 442 |
*
|
| 443 |
* Exposes data from the {user} table, such as the full username, account
|
| 444 |
* status, e-mail address, etc, to views of the corresponding bio nodes.
|
| 445 |
*/
|
| 446 |
function _bio_views_tables() {
|
| 447 |
$tables['bio'] = array(
|
| 448 |
'name' => 'bio',
|
| 449 |
'join' => array(
|
| 450 |
'type' => 'inner',
|
| 451 |
'left' => array(
|
| 452 |
'table' => 'node',
|
| 453 |
'field' => 'nid'
|
| 454 |
),
|
| 455 |
'right' => array(
|
| 456 |
'field' => 'nid'
|
| 457 |
),
|
| 458 |
),
|
| 459 |
);
|
| 460 |
$tables['bio_users'] = array(
|
| 461 |
'name' => 'users',
|
| 462 |
'join' => array(
|
| 463 |
'type' => 'inner',
|
| 464 |
'left' => array(
|
| 465 |
'table' => 'bio',
|
| 466 |
'field' => 'uid'
|
| 467 |
),
|
| 468 |
'right' => array(
|
| 469 |
'field' => 'uid'
|
| 470 |
),
|
| 471 |
),
|
| 472 |
'fields' => array(
|
| 473 |
'name' => array(
|
| 474 |
'name' => t('Bio: User: Username'),
|
| 475 |
'uid' => 'uid',
|
| 476 |
'addlfields' => array('uid'),
|
| 477 |
'sortable' => TRUE,
|
| 478 |
'help' => t('The username of the user associated with a given bio.'),
|
| 479 |
'handler' => 'views_handler_field_username',
|
| 480 |
),
|
| 481 |
'mail' => array(
|
| 482 |
'name' => t('Bio: User: E-mail'),
|
| 483 |
'handler' => 'views_handler_field_email',
|
| 484 |
'help' => t('The e-mail address of the user associated with a given bio.'),
|
| 485 |
'sortable' => TRUE,
|
| 486 |
),
|
| 487 |
'status' => array(
|
| 488 |
'name' => t('Bio: User: Account status'),
|
| 489 |
'help' => t('The account status of the user associated with a given bio.'),
|
| 490 |
'handler' => 'bio_views_handler_field_user_status',
|
| 491 |
'sortable' => TRUE,
|
| 492 |
),
|
| 493 |
'picture' => array(
|
| 494 |
'name' => t('Bio: User: Picture'),
|
| 495 |
'field' => 'uid',
|
| 496 |
'help' => t('The picture of the user associated with a given bio.'),
|
| 497 |
'handler' => 'views_handler_field_userpic',
|
| 498 |
'sortable' => FALSE,
|
| 499 |
),
|
| 500 |
'signature' => array(
|
| 501 |
'name' => t('Bio: User: Signature'),
|
| 502 |
'help' => t('The signature of the user associated with a given bio.'),
|
| 503 |
'sortable' => FALSE,
|
| 504 |
),
|
| 505 |
'created' => array(
|
| 506 |
'name' => t('Bio: User: Created time'),
|
| 507 |
'help' => t("The creation time of the user associated with a given bio. The option field may be used to specify the custom date format as it's required by the date() function or if 'as time ago' has been chosen to customize the granularity of the time interval."),
|
| 508 |
'handler' => views_handler_field_dates(),
|
| 509 |
'option' => 'string',
|
| 510 |
'sortable' => TRUE,
|
| 511 |
),
|
| 512 |
'access' => array(
|
| 513 |
'name' => t('Bio: User: Access time'),
|
| 514 |
'help' => t("The last access time of the user associated with a given bio. The option field may be used to specify the custom date format as it's required by the date() function or if 'as time ago' has been chosen to customize the granularity of the time interval."),
|
| 515 |
'handler' => views_handler_field_dates(),
|
| 516 |
'option' => 'string',
|
| 517 |
'sortable' => TRUE,
|
| 518 |
),
|
| 519 |
'login' => array(
|
| 520 |
'name' => t('Bio: User: Login time'),
|
| 521 |
'help' => t("The last login time of the user associated with a given bio. The option field may be used to specify the custom date format as it's required by the date() function or if 'as time ago' has been chosen to customize the granularity of the time interval."),
|
| 522 |
'handler' => views_handler_field_dates(),
|
| 523 |
'option' => 'string',
|
| 524 |
'sortable' => TRUE,
|
| 525 |
),
|
| 526 |
),
|
| 527 |
);
|
| 528 |
return $tables;
|
| 529 |
}
|
| 530 |
|
| 531 |
function bio_views_handler_field_user_status($fieldinfo, $fielddata, $value, $data) {
|
| 532 |
return $value == 0 ? t('Blocked') : t('Active');
|
| 533 |
}
|
| 534 |
|
| 535 |
if (!function_exists('views_handler_field_email')) {
|
| 536 |
function views_handler_field_email($fieldinfo, $fielddata, $value, $data) {
|
| 537 |
return l($value, 'mailto:' . $value);
|
| 538 |
}
|
| 539 |
}
|