'admin/user/bio',
'title' => t('User biographies'),
'description' => t('User biographies'),
'callback' => 'drupal_get_form',
'callback arguments' => array('bio_settings'),
);
}
else {
// Add bio node menu tab only on user account page, but not if bio node
// editing in the user account edit form is enabled and Subform element
// module exists.
if (variable_get('bio_profile', 0) && (arg(0) == 'user') && (is_numeric(arg(1))) && (!variable_get('bio_edit_form', 0) || !module_exists('subform_element'))) {
$type = bio_get_type();
$nid = bio_for_user(arg(1));
$type = bio_get_type();
$nid = bio_for_user(arg(1));
// Determine access based on whether user has a bio.
if ($nid) {
$node = node_load($nid);
$access = node_access('update', $node);
}
else {
$node = (object) array('type' => $type, 'uid' => arg(1));
$access = (($user->uid == arg(1)) && node_access('create', $type)) || user_access('administer nodes');
}
$items[] = array(
'path' => 'user/'. arg(1) .'/bio',
'title' => node_get_types('name', $type),
'callback' => 'node_page_edit',
'callback arguments' => array($node),
'type' => MENU_LOCAL_TASK,
'access' => $access,
);
}
elseif (variable_get('bio_profile', 0) && (arg(0) == 'node') && is_numeric(arg(1)) && !arg(2)) {
// If we're about to visit a bio node page, but we've got "use bios for profiles" selected,
// redirect to the user page.
$node = node_load(arg(1));
if (user_access('access user profiles') && $node->type == bio_get_type()) {
drupal_goto('user/'. $node->uid);
}
}
}
return $items;
}
/**
* Implementation of hook_form_alter().
*/
function bio_form_alter($form_id, &$form) {
if (arg(0) == 'user' && $form_id == bio_get_type() .'_node_form' && (!variable_get('bio_edit_form', 0) || !module_exists('subform_element'))) {
// We're editing the bio in the user area... be sure we end up here when we
// finish submission, and disallow changing the author.
$account = user_load(array('uid' => arg(1)));
// We're editing the bio in the user area... be sure we end up here when we
// finish submission, and disallow changing the author.
$account = user_load(array('uid' => arg(1)));
$form['#redirect'] = "user/$account->uid";
if (isset($form['author']['name'])) {
$form['author']['name']['#default_value'] = $account->name;
$form['author']['name']['#value'] = $account->name;
$form['author']['name']['#disabled'] = TRUE;
unset($form['author']['name']['#autocomplete_path']);
$form['author']['name']['#description'] = t('This field is disabled. You cannot alter the author of this entry from within the user area.');
}
}
// Display CCK fields on the user registration form, if they've been
// marked as such.
if ($form_id == 'user_register' && variable_get('bio_regstration_form', 0) && module_exists('content')) {
$widget_types = _content_widget_types();
$fields = _bio_get_fields();
$default_values = variable_get('bio_regstration_form_fields', array());
// Create a dummy node to pass along to the cck hooks.
$node = new stdClass();
$node->type = bio_get_type();
foreach ($fields as $field_name => $field) {
if ($field['required'] || !empty($default_values[$field_name])) {
$node_field = content_default_value($node, $field, array());
// Figure out what widget function to call.
$module = $widget_types[$field['widget']['type']]['module'];
$function = $module .'_widget';
// Get the form field and add it to the form.
$cck_field = $function('prepare form values', $node, $field, $node_field);
$cck_field = $function('form', $node, $field, $node_field);
$form = array_merge($form, $cck_field);
}
}
// Add custom validate/submit handlers.
$form['#submit']['bio_user_register_submit'] = array();
$form['#validate']['bio_user_register_validate'] = array();
}
}
/**
* Validate handler for user registration form. Validate CCK fields.
*/
function bio_user_register_validate($form_id, $form_values) {
// Create a dummy node to pass along to CCK.
$node = new stdClass();
$node->type = bio_get_type();
foreach ($form_values as $field_name => $value) {
if (preg_match('/^field_/', $field_name)) {
$node->$field_name = $form_values[$field_name];
}
}
// Call validation routines on the CCK fields.
content_validate($node);
}
/**
* Submit handler for user registration form. Automatically creates a bio node
* on registration if any bio fields are set to show on the registration form.
*/
function bio_user_register_submit($form_id, $form_values) {
// Create bio node for this user.
$node = new StdClass;
$node->type = bio_get_type();
$node->uid = db_result(db_query("SELECT uid FROM {users} WHERE name = '%s'", $form_values['name']));
$node->title = $form_values['name'];
$node->name = $form_values['name'];
node_object_prepare($node);
$node_options = variable_get('node_options_'. $node->type, array('status', 'promote'));
foreach (array('status', 'promote', 'sticky') as $key) {
$node->$key = in_array($key, $node_options);
}
// Always use the default revision setting.
$node->revision = in_array('revision', $node_options);
foreach ($form_values as $field_name => $value) {
if (preg_match('/^field_/', $field_name)) {
$node->$field_name = $form_values[$field_name];
}
}
// Create the node.
$node = node_submit($node);
node_save($node);
// Give us a nice log message.
if ($node->nid) {
watchdog('content', t('Bio: added %user bio upon registration.', array('%user' => $node->name)), WATCHDOG_NOTICE, l(t('view'), "node/$node->nid"));
}
}
/**
* Implementation of hook_profile_alter().
*/
function bio_profile_alter(&$account, &$fields) {
// Replace user profile with user bio.
if (variable_get('bio_profile_takeover', 0) && $bio = bio_for_user($account->uid)) {
$bio = node_load($bio);
$typename = node_get_types('name', bio_get_type());
foreach ($fields as $key => $val) {
if ($key != $typename) {
unset($fields[$key]);
}
}
$account->name = $bio->title;
}
}
/**
* Implementation of hook_node_info().
*/
function bio_node_info() {
if (bio_get_type() == 'bio') {
// Create a default bio type that's as simple as possible.
return array(
'bio' => array(
'name' => t('Biography'),
'module' => 'node',
'has_title' => TRUE,
'has_body' => TRUE,
'custom' => TRUE,
'modified' => TRUE,
'locked' => FALSE,
),
);
}
}
/**
* Implementation of hook_nodeapi().
*/
function bio_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
if ($node->type != bio_get_type()) return;
switch ($op) {
case 'validate':
// Ensure this user doesn't already have a bio node.
$account = user_load(array('name' => $node->name));
$nid = bio_for_user($account->uid);
if ($nid && ($nid != $node->nid)) {
form_set_error('name', t('This user already has a @bio. Edit it here or assign this entry to another user.', array('@bio' => node_get_types('name', $node), '@link' => url('node/'. $nid .'/edit'))));
}
break;
case 'insert':
// Record user's bio in bio table.
db_query('INSERT INTO {bio} (nid, uid) VALUES (%d, %d)', $node->nid, $node->uid);
break;
case 'delete':
// Remove the user's entry from the bio table when the user is deleted.
db_query('DELETE FROM {bio} where nid = %d', $node->nid);
break;
}
}
/**
* Implementation hook_user().
*/
function bio_user($op, &$edit, &$account, $category = NULL) {
// If there's no bio for this user, nothing to do here.
if ($op == 'view' && !$nid = bio_for_user($account->uid)) {
return bio_user_register_form();
}
switch ($op) {
case 'view':
// Add bio to main user profile page, if option is enabled and bio is accessible.
if (variable_get('bio_profile', 0) && node_access('view', $node = node_load($nid))) {
$name = node_get_types('name', bio_get_type());
$bio[$name]['bio']['value'] = node_view($node, FALSE, TRUE, FALSE);
return $bio;
}
break;
case 'delete':
node_delete(bio_for_user($account->uid));
break;
case 'form':
// Display bio node form on user account form, if enabled.
if (!variable_get('bio_edit_form', 0) || !module_exists('subform_element')) {
return;
}
$type = bio_get_type();
// Edit existing bio node.
if ($nid = bio_for_user($account->uid)) {
$node = node_load($nid);
$access = node_access('update', $node);
}
// Create new bio node.
else {
$node = (object)array('type' => $type, 'uid' => $account->uid, 'name' => $account->name);
$access = ($user->uid == $account->uid && node_access('create', $type)) || user_access('administer nodes');
}
if ($access) {
$form['bio_node'] = array(
'#type' => 'subform',
'#id' => $type .'_node_form',
'#arguments' => array($node),
'#data_separation' => TRUE,
'#weight' => 20,
'#extra_form' => array('preview' => array('#access' => FALSE), 'submit' => array('#access' => FALSE), 'delete' => array('#access' => FALSE)),
);
// Prepend subform_element form submit handler for bio node.
$form['#submit'] = array('subform_element_submit' => array()) + (array)$form['#submit'];
}
return $form;
break;
}
}
/**
* Implementation of hook_link().
*/
function bio_link($type, $node = NULL, $teaser = FALSE) {
if ($type == 'node' && $node->type != bio_get_type()) {
// Add "View *username*'s biography" link to nodes.
$bio_link = variable_get('bio_link', array($node->type => 1));
if ($bio_link[$node->type] && ($nid = bio_for_user($node->uid))) {
$account = user_load(array('uid' => $node->uid));
return array(
'bio' => array(
'title' => t('by @user', array('@user' => $account->name)),
'href' => 'node/'. $nid,
'attributes' => array(
'title' => t('View @user\'s @bio.', array('@user' => $account->name, '@bio' => node_get_types('name', bio_get_type()))),
),
),
);
}
}
}
/**
* Find bio for given user.
*
* @param $uid
* User ID.
* @return
* Node ID of bio, or FALSE if no bio node was found.
*/
function bio_for_user($uid = NULL) {
static $nid;
if (isset($nid)) {
return $nid;
}
if (is_null($uid)) {
global $user;
$uid = $user->uid;
}
$nid = db_result(db_query('SELECT nid FROM {bio} WHERE uid = %d', $uid));
return $nid;
}
/**
* Menu callback; administration settings page.
*/
function bio_settings() {
// Bio node type.
$types = array();
foreach (node_get_types() as $key => $type) {
$types[$key] = $type->name;
}
$form['bio_nodetype'] = array(
'#type' => 'select',
'#title' => t('Content type for user biographies'),
'#description' => t('The content type for user biographies. Each user may create only one node of this type'),
'#options' => $types,
'#default_value' => bio_get_type(),
);
// Link to author's bio.
$form['bio_link'] = array(
'#type' => 'checkboxes',
'#title' => t('Display bio link'),
'#description' => t("Display a link to author's bio if it is available."),
'#options' => $types,
'#default_value' => variable_get('bio_link', $types),
);
// Bio profile options.
$form['bio_profile'] = array(
'#type' => 'checkbox',
'#title' => t('Use bio for user profiles'),
'#description' => t('View, edit, and display biography information on the user account page.'),
'#default_value' => variable_get('bio_profile', 0),
);
$form['bio_profile_takeover'] = array(
'#type' => 'checkbox',
'#title' => t('Takeover profile.'),
'#description' => t('Display nothing but the bio node on the user profile page.'),
'#default_value' => variable_get('bio_profile_takeover', 0),
);
$form['bio_edit_form'] = array(
'#type' => 'checkbox',
'#title' => t('Show fields on user account edit form'),
'#return_value' => 1,
'#default_value' => variable_get('bio_edit_form', 0),
'#description' => t('Enable this option to display bio fields on the user account edit form. This will automatically create or update a bio record for a user when they edit their user account.'),
);
if (!module_exists('subform_element')) {
$form['bio_edit_form']['#disabled'] = TRUE;
$form['bio_edit_form']['#description'] .= '
'. t('This feature requires the Subform Element module.', array('!subform-link' => 'http://drupal.org/project/subform_element'));
}
// Show fields on the registration form.
if (module_exists('content')) {
$form['bio_regstration_form'] = array(
'#type' => 'checkbox',
'#title' => t('Show fields on registration form'),
'#return_value' => 1,
'#default_value' => variable_get('bio_regstration_form', 0),
'#description' => t('Enable this option to display bio fields on the user registration form. This will automatically create a bio record for a user when they register.'),
);
// Determine the options and default values.
$fields = _bio_get_fields();
$default_values = variable_get('bio_regstration_form_fields', array());
foreach ($fields as $field_name => $properties) {
$options[$field_name] = check_plain($properties['widget']['label']);
// Required fields are always shown on registration form.
if ($properties['required'] || !empty($default_values[$field_name])) {
$default_values[$field_name] = $field_name;
}
else {
$default_vales[$field_name] = 0;
}
}
// Display list of fields.
$form['bio_regstration_form_fields'] = array(
'#type' => 'checkboxes',
'#title' => t('Registration form fields'),
'#options' => $options,
'#default_value' => $default_values,
'#description' => t('Fields checked here will be displayed on the user registration form. Required fields are always shown.'),
'#theme' => 'bio_registration_fields',
);
}
// Strange hack for invalidating Views cache.
$add_a_submit = system_settings_form($form);
$add_a_submit['#validate']['bio_settings_validate_xxx'] = array();
return $add_a_submit;
}
/**
* Theme function for bio registration form options that adds a disabled flag
* to required fields.
*
* @ingroup themeable
*/
function theme_bio_registration_fields($form) {
$fields = _bio_get_fields();
foreach (element_children($form) as $field_name) {
// Disable required fields; they always show up.
if ($fields[$field_name]['required']) {
$form[$field_name]['#attributes'] = array('disabled' => 'disabled');
$form[$field_name]['#value'] = $field_name;
}
}
return drupal_render($form);
}
/**
* Invalidate Views cache when bio settings form is submitted.
*
* This is required in case the bio node type has changed. We need the _xxx
* suffix to keep it from interfering with the #base in system_settings_form().
* Also, we do it in the validate phase because submits were interfering with
* the #base attribute. Yuck.
*
* @todo Less hackish way to do this?
*/
function bio_settings_validate_xxx($form_id, $form_values) {
if (module_exists('views')) {
views_invalidate_cache();
}
}
/**
* Retrieve field info for Bio CCK type.
*/
function _bio_get_fields() {
$bio_nodetype = bio_get_type();
$type = content_types($bio_nodetype);
return $type['fields'];
}
/**
* Short-hand function to return bio node type.
*
* @return $string
* Node type short name currently assigned as the Bio type.
*/
function bio_get_type() {
return variable_get('bio_nodetype', 'bio');
}
/*
* Views integration for Bio module.
*
* Bio module's Views integration works by cloning many features of Views
* module's existing node integration. To avoid a large amount of code being
* loaded on every page, these functions therefore merely call private
* functions in bio_views.inc.
*/
/**
* Implementation of hook_views_table_alter().
*
* @see _bio_views_tables_alter()
*/
function bio_views_tables_alter(&$tables) {
require_once drupal_get_path('module', 'bio') .'/bio_views.inc';
return _bio_views_tables_alter($tables);
}
/**
* Copy of views_handler_filter_isnew($op, $filter, $filterinfo, &$query)
*
* @see _bio_handler_filter_isnew()
*/
function bio_handler_filter_isnew($op, $filter, $filterinfo, &$query) {
require_once drupal_get_path('module', 'bio') .'/bio_views.inc';
return _bio_handler_filter_isnew($op, $filter, $filterinfo, $query);
}
/**
* Implementation of hook_views_query_alter().
*
* @see _bio_views_query_alter()
*/
function bio_views_query_alter(&$query, $view, $summary, $level) {
require_once drupal_get_path('module', 'bio') .'/bio_views.inc';
return _bio_views_query_alter($query, $view, $summary, $level);
}
/**
* Implementation of hook_views_default_views().
*
* @see _bio_views_default_views()
*/
function bio_views_default_views() {
require_once drupal_get_path('module', 'bio') .'/bio_views.inc';
return _bio_views_default_views();
}