You are here

realname.module in Real Name 5

The RealName module allows the admin to choose fields from the user profile that will be used to add a "realname" element (method) to a user object. Hook_user is used to automatically add this to any user object that is loaded.

@copyright Copyright (c) 2007-2008 Nancy Wichmann. All rights reserved.

File

realname.module
View source
<?php

/**
 * @file
 * The RealName module allows the admin to choose fields from the user profile
 * that will be used to add a "realname" element (method) to a user object.
 * Hook_user is used to automatically add this to any user object that is loaded.
 *
 * @copyright Copyright (c) 2007-2008 Nancy Wichmann.  All rights reserved.
 */
define('MODULE_VERSION', '$Id$');
if (module_exists('token')) {
  include_once drupal_get_path('module', 'realname') . '/token_realname.inc';
}

//********************************************************************

//* Drupal Hooks

//********************************************************************/

/**
 * Implementation of hook_help().
 */
function realname_help($path, $args = NULL) {
  switch ($path) {
    case 'admin/user/realname':
      $output = t('This page displays the status of and settings for the RealName module.');
      $output .= '<p>Version: ' . MODULE_VERSION . '</p>';
      return $output;
    case 'admin/help#realname':
      return t('This simple module adds a "realname" element (method) to a user object when that object is loaded.');
  }
}

/**
 * Implementation of hook_perm().
 */
function realname_perm() {
  return array(
    'use realname',
  );
}

/**
 * Implementation of hook_menu().
 */
function realname_menu($may_cache) {
  global $user;
  $items = array();
  if ($may_cache) {
    $items[] = array(
      'path' => 'admin/user/realname',
      'title' => t('RealName'),
      'description' => t("Configure which fields are used to create a user's RealName."),
      'access' => user_access('administer users'),
      'callback' => 'drupal_get_form',
      'callback arguments' => array(
        'realname_admin_settings',
      ),
      'type' => MENU_NORMAL_ITEM,
    );
    $items[] = array(
      'path' => 'admin/user/realname/fields',
      'title' => t('Fields'),
      'access' => user_access('administer users'),
      'callback' => 'drupal_get_form',
      'callback arguments' => array(
        'realname_admin_fields',
      ),
      'type' => MENU_DEFAULT_LOCAL_TASK,
      'weight' => 0,
    );
    $items[] = array(
      'path' => 'admin/user/realname/bypass',
      'title' => t('Bypass Forms'),
      'access' => user_access('administer users'),
      'callback' => 'drupal_get_form',
      'callback arguments' => array(
        'realname_admin_bypass',
      ),
      'type' => MENU_LOCAL_TASK,
      'weight' => 2,
    );

    // CCK Userref intercept.
    $items[] = array(
      'path' => 'realname/userref/autocomplete',
      'title' => t('RealName user reference autocomplete'),
      'callback' => 'realname_userref_autocomplete',
      'access' => user_access('access content'),
      'type' => MENU_CALLBACK,
    );

    // Privatemsg intercept.
    $items[] = array(
      'path' => 'realname/privatemsg/autocomplete',
      'title' => t('Realname Privatemsg autocomplete'),
      'callback' => 'realname_privatemsg_autocomplete',
      'access' => user_access('access private messages'),
      'type' => MENU_CALLBACK,
    );
  }
  else {

    // If desired, load the theme override file.
    if (variable_get('realname_theme', TRUE)) {
      include_once drupal_get_path('module', 'realname') . '/realname_theme.inc';
    }
  }
  return $items;
}

/**
 * Implementation of hook_user().
 */
function realname_user($op, &$edit, &$account, $category = NULL) {
  if ($op == 'load') {
    $account->realname = realname_make_name($account);

    // If theme then replace name with realname.
    if (variable_get('realname_theme', TRUE) && $account->realname) {

      //Store it for places where it needed
      if (!isset($account->realname_save) && is_object($account)) {
        $account->realname_save = $account->name;

        //        $account->name = $account->realname;
      }
    }
  }
}

/**
 * Implementation of hook_nodeapi().
 */
function realname_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
  if (!user_access('use realname')) {
    return;
  }
  if (!variable_get('realname_nodeapi', FALSE)) {
    return;
  }
  switch ($op) {
    case 'view':

      // Node is being loaded.
      // Save the username that is already there.
      $node->realname_save = $node->name;
      $account = user_load(array(
        'uid' => $node->uid,
      ));
      $node->realname = $node->name = realname_make_name($account);
      $node->homepage = isset($account->homepage) ? $account->homepage : NULL;
      break;
    case 'prepare':

      // Node is about to be edited.
      // Reset the username or save will fail.
      if (isset($node->realname_save)) {
        $node->name = $node->realname_save;
      }
      break;
  }
}

/**
 * Implementation of hook_comment().
 */
function realname_comment(&$comment, $op) {
  switch ($op) {
    case 'view':
      if (!$comment->homepage) {
        $account = user_load(array(
          'uid' => $comment->uid,
        ));
        realname_make_name($account);
        $comment->homepage = isset($account->homepage) ? $account->homepage : NULL;
      }
      break;
  }
  return;
}

/**
 * Implementation of hook_form_alter().
 * Intercepts the contact forms to show the realname.
 */
function realname_form_alter($form_id, &$form) {
  global $user;
  if (!user_access('use realname')) {
    return;
  }

  //  drupal_set_message($form_id);
  if (substr($form_id, -10) == '_node_form') {

    //    drupal_set_message(print_r($form, TRUE));
    foreach ($form as $name => $elements) {
      if (substr($name, 0, 6) == 'field_') {
        if (isset($form[$name]['uids'])) {
          $fields = content_fields();
          $field = $fields[$name];
          $options = _userreference_potential_references($field);
          foreach ($options as $uid => $optname) {
            $account = user_load(array(
              'uid' => $uid,
            ));
            $options[$uid] = realname_make_name($account);
          }
          asort($options);
          if (!$field['required']) {
            $options = array(
              'none' => t('<none>'),
            ) + $options;
          }
          $form[$name]['uids']['#options'] = $options;
        }
        else {
          foreach ($elements as $key => $value) {
            if (is_numeric($key)) {
              foreach ($value as $key1 => $value1) {
                if (isset($form[$name][$key]['user_name']['#autocomplete_path'])) {
                  $path = 'realname/userref/autocomplete/' . $name;
                  $form[$name][$key]['user_name']['#autocomplete_path'] = $path;
                }
              }
            }
          }
        }
      }
    }
  }
  $bypass_forms = variable_get('realname_bypass_forms', array(
    array(
      'name' => 'comment_form',
      'fields' => array(
        'name',
      ),
    ),
  ));
  foreach ($bypass_forms as $bypass) {

    // Is it a form the admin wants bypassed?
    if ($form_id == $bypass['name']) {
      $field_name = '$form[\'' . implode("']['", $bypass['fields']) . "']['#default_value']";
      if (!isset($user->realname)) {
        $user = user_load(array(
          'uid' => $user->uid,
        ));
      }
      $value = $user->uid ? $user->realname_save : variable_get('anonymous', 'Anonymous');
      eval($field_name . ' = $value;');
    }
  }

  // We will go ahead and fall through in case there is any other special processing.
  switch ($form_id) {

    //    case 'comment_form':
    //      if (!isset($user->realname)) {
    //        $user = user_load(array('uid' => $user->uid));
    //      }
    //      $form['author']['#default_value'] = $user->realname_save;
    //      break;
    case 'privatemsg_new_form':

      //      drupal_set_message(print_r($form['header']['recipient']['#autocomplete_path'], true));
      $form['header']['recipient']['#autocomplete_path'] = 'realname/privatemsg/autocomplete';
      break;
    case 'user_edit':
    case 'user_profile_form':
      if (variable_get('realname_theme', TRUE)) {
        $form['account']['name']['#default_value'] = $form['_account']['#value']->realname_save;
      }
      break;
    case 'contact_mail_user':
      if (!isset($user->realname)) {
        $user = user_load(array(
          'uid' => $user->uid,
        ));
      }
      $form['from']['#value'] = check_plain($user->realname) . ' &lt;' . check_plain($user->mail) . '&gt;';
      break;
    case 'contact_mail_page':
      if (!isset($user->realname)) {
        $user = user_load(array(
          'uid' => $user->uid,
        ));
      }
      $form['name']['#default_value'] = $user->uid ? $user->realname : '';
      break;
  }
}

/**
 * Intercept Privatemsg autocomplete results for usernames.
 */
function realname_privatemsg_autocomplete($string) {
  $names = explode(',', $string);

  //  for ($i = 0; $i < count($names); $i++) {
  //    $names[$i] = trim($names[$i]);
  //  }
  $names = array_map('trim', $names);
  $search = array_pop($names);
  if ($search != '') {
    $sql = "SELECT uid, name FROM {users} u WHERE status <> 0 AND LOWER(name) LIKE LOWER('%s%%') AND ";
    $sql .= variable_get('privatemsg_default_allow', 1) ? '(data NOT LIKE \'%%:16:"privatemsg_allow";i:0%%\' OR data IS NULL)' : 'data LIKE \'%%:16:"privatemsg_allow";i:1%%\'';
    $sql .= ' ORDER BY name ASC';
    $result = db_query_range($sql, $search, 0, 10);
    $prefix = count($names) ? implode(', ', $names) . ', ' : '';
    $matches = array();
    while ($user = db_fetch_object($result)) {
      $account = user_load(array(
        'uid' => $user->uid,
      ));
      $matches[$prefix . $user->name] = realname_make_name($account);
    }
    print drupal_to_js($matches);
    exit;
  }
}

/**
 * CCK Userref intercept; Change autocomplete suggestions to realnames.
 */
function realname_userref_autocomplete($field_name, $string = '') {
  $fields = content_fields();
  $field = $fields[$field_name];
  $matches = array();
  if ($string !== '') {
    $list = _userreference_potential_references($field, $string);
    foreach ($list as $uid => $name) {
      $account = user_load(array(
        'uid' => $uid,
      ));
      $matches[$name] = realname_make_name($account);
    }
  }
  print drupal_to_js($matches);
  exit;
}

//********************************************************************

//* Module Functions

//********************************************************************

/**
 * Using selected fields, build the "real name" field in the object.
 *
 * @param
 *   $account - the user object to update.
 *
 * @return
 *   The constructed "real name" string.
 */
function realname_make_name(&$account) {

  // For some strange reason, using a static variable with "theme" in the name sends D5 into a stupor.
  static $fields, $pattern_saved, $homepage, $use_theme, $profile_privacy;
  static $users = array();
  static $links = array();
  static $edit = array();
  if (isset($users[$account->uid])) {
    $account->homepage = isset($links[$account->uid]) ? $links[$account->uid] : NULL;
    return $users[$account->uid];
  }

  // Get our controlling variables (static makes it once per page load).
  if (!isset($fields)) {
    $fields = variable_get('realname_fields', array());
    $pattern_saved = variable_get('realname_pattern', ' ');
    $homepage = variable_get('realname_homepage', NULL);
    $use_theme = variable_get('realname_theme', TRUE);
    $profile_privacy = module_exists('profile_privacy');
  }
  $pattern = $pattern_saved;

  // Has the profile been loaded?
  if (!isset($account->{key($fields)})) {
    profile_load_profile($account);
    if ($profile_privacy) {
      profile_privacy_user('load', $edit, $account);
    }
  }
  $stuff = array();
  $i = 0;
  foreach ($fields as $name => $weight) {
    ++$i;
    $private = 'private_' . $name;

    // This will let you see that a user is using Profile Privacy.
    //    if (isset($account->{$private})) {
    //      drupal_set_message("$account->name ($account->uid) has marked the $name field as private.");
    //    }
    $private_field = isset($account->{$private}) ? $account->{$private} : FALSE;
    if (isset($account->{$name}) && !empty($account->{$name}) && !$private_field) {
      $stuff['%' . $i] = $account->{$name};
    }
    else {

      // If there is no value, remove the patterm piece, except the first.
      $pattern = str_replace('%' . $i, NULL, $pattern);
    }
  }

  // If no fields set, use username.
  if (count($stuff) == 0) {
    $stuff['%1'] = $account->name;
    $pattern = '%1';
  }
  if ($homepage && $account->{$homepage}) {
    $links[$account->uid] = $account->homepage = $account->{$homepage};
  }
  $string = trim(strtr($pattern, $stuff));

  //  $string = drupal_validate_utf8($string) ? htmlspecialchars($string, ENT_COMPAT) : '';
  $users[$account->uid] = $string;
  return $string;
}

/**
 * Provides array sorting function for uasort.
 *  @link http://us2.php.net/manual/en/function.uasort.php PHP Manual @end-link
 *
 * @param
 *   $a - the first array to be compared.
 *
 * @param
 *   $b - the second array to be compared.
 *
 * @return
 *   integer indicating ordering.
 */
function _realname_sort($a, $b) {

  // Sort first by weight.
  $ret = $a['weight'] - $b['weight'];
  if ($ret == 0) {

    // The two are equal, so use the title.
    $ret = strcmp($a['title'], $b['title']);
  }
  return $ret;
}
function realname_admin_bypass() {
  $form = array();
  $current = variable_get('realname_bypass_forms', array(
    array(
      'name' => 'comment_form',
      'fields' => array(
        'name',
      ),
    ),
  ));
  $rows = count($current);
  $bypass_list = NULL;
  foreach ($current as $bypass) {
    $bypass_list .= $bypass['name'] . ' ' . implode(' ', $bypass['fields']) . "\n";
  }
  $form['warning'] = array(
    '#type' => 'markup',
    '#value' => '<div class="messages warning">' . t('<strong>WARNING</strong>: This form may cause errors if the instructions below are not followed or if you give an invalid form name or field name. Please do not remove the "comment_form" line.') . '</div>',
  );
  $form['bypass_forms'] = array(
    '#type' => 'textarea',
    '#title' => t('Bypass these forms'),
    '#rows' => max(array(
      $rows + 1,
      5,
    )),
    '#default_value' => $bypass_list,
    '#description' => t('Enter one form per line. Each line should start with the form name. That should be followed by the name of the field to be reset to the username. If the field is a child field, include its full parent path, separated by spaces. For example: mymodule_form fieldset_1 fieldset_2 name'),
    '#required' => TRUE,
  );
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Bypass these forms'),
  );
  return $form;
}
function realname_admin_bypass_submit($form_id, $form_values) {
  $bypass_list = explode("\n", $form_values['bypass_forms']);
  $bypass_forms = array();
  foreach ($bypass_list as $line) {
    $line = trim($line);
    if ($line) {
      $pieces = explode(' ', $line);
      $form_info = array(
        'name' => array_shift($pieces),
      );
      $form_info['fields'] = $pieces;
      $bypass_forms[] = $form_info;
    }
  }
  variable_set('realname_bypass_forms', $bypass_forms);
  drupal_set_message(t('Information saved for !count forms.', array(
    '!count' => count($bypass_forms),
  )), 'status');
}

/**
 * Displays the admin settings form.
 */
function realname_admin_settings() {
  $form = $fields = $links = array();
  $current = variable_get('realname_fields', array());
  $result = db_query("SELECT * FROM {profile_fields}");
  while ($field = db_fetch_array($result)) {
    switch ($field['type']) {
      case 'textfield':
        $name = $field['name'];
        $selected = array_key_exists($name, $current);
        $fields[$name] = array(
          'title' => $field['title'],
          'weight' => $selected ? $current[$name] : 0,
          'selected' => $selected,
        );
        break;
      case 'url':
        $links[$field['name']] = $field['title'];
        break;
      default:
        break;
    }
  }
  uasort($fields, '_realname_sort');
  $form['start_table'] = array(
    '#type' => 'markup',
    '#value' => '<table><tr><th>Select</th><th>Field name</th><th>Weight</th></tr>',
  );
  $i = 0;
  foreach ($fields as $f_name => $values) {
    $form['field_select_' . $i] = array(
      '#type' => 'checkbox',
      '#default_value' => $values['selected'],
      '#prefix' => '<tr><td align="center">',
      '#suffix' => '</td>',
    );
    $form['field_name_' . $i] = array(
      '#type' => 'hidden',
      '#value' => $f_name,
    );
    $form['field_title_' . $i] = array(
      '#type' => 'item',
      '#value' => $values['title'],
      '#prefix' => '<td>',
      '#suffix' => '</td>',
    );
    $form['field_weight_' . $i] = array(
      '#type' => 'weight',
      '#delta' => 10,
      '#default_value' => $values['weight'],
      '#prefix' => '<td>',
      '#suffix' => '</td></tr>',
    );
    ++$i;
  }
  $form['end_table'] = array(
    '#type' => 'markup',
    '#value' => '</table>',
  );
  $form['realname_pattern'] = array(
    '#type' => 'textfield',
    '#field_prefix' => '<strong>' . t('Name Pattern') . '</strong> ',
    '#description' => t('The determines how the fields will be used to create the "Real name." Use "%1" to refer to the first field, "%2" to refer to the second, etc..'),
    '#size' => 30,
    '#default_value' => variable_get('realname_pattern', '%1'),
  );
  $form['realname_theme'] = array(
    '#type' => 'checkbox',
    '#title' => '<strong>' . t('Override username theme') . '</strong>',
    '#description' => t('If this option is selected, the standard username theme function will be overriden to use the "Real name."'),
    '#default_value' => variable_get('realname_theme', TRUE),
  );
  $form['realname_max_username'] = array(
    '#type' => 'textfield',
    '#field_prefix' => '<strong>' . t('Maximum allowed username length') . '</strong> ',
    '#description' => t('Long usernames may "break" some tables or other displays; this setting limits the maximum length. Note that the core recommendation is 20.'),
    '#size' => 6,
    '#default_value' => variable_get('realname_max_username', 20),
  );
  $form['realname_nodeapi'] = array(
    '#type' => 'checkbox',
    '#title' => '<strong>' . t('Show realname in nodes') . '</strong>',
    '#description' => t('If this option is selected, the "Real name" will be used on node displays.'),
    '#default_value' => variable_get('realname_nodeapi', FALSE),
  );
  $form['realname_notver'] = array(
    '#type' => 'checkbox',
    '#title' => '<strong>' . t('Show "Not verified" for anonymous users') . '</strong>',
    '#description' => t('Drupal core adds "Not verified" for anonymous users, this option allows that to be turned off.'),
    '#default_value' => variable_get('realname_notver', TRUE),
  );

  // If there were any URL fields, give a home page option.
  if ($links) {
    $links[''] = t('');
    asort($links);
    $form['realname_homepage'] = array(
      '#type' => 'select',
      '#options' => $links,
      '#title' => t('Link to homepage'),
      '#description' => t('There were URL fields in the profile. If one of these is a personal homepage link, you may choose to link to it rather than the user profile. Choose which field to use.'),
      '#default_value' => variable_get('realname_homepage', NULL),
    );
    $form['realname_nofollow'] = array(
      '#type' => 'checkbox',
      '#title' => t('Spam link deterrent'),
      '#description' => t('If enabled, Drupal will add rel="nofollow" to all links, as a measure to reduce the effectiveness of spam links. Note: this will also prevent valid links from being followed by search engines, therefore it is likely most effective when enabled for anonymous users.'),
      '#default_value' => variable_get('realname_nofollow', FALSE),
    );
  }
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Save'),
  );
  return $form;
}

/**
 * Form submit handler.
 */
function realname_admin_settings_submit($form_id, $form_values) {
  $i = 0;
  $fields = array();

  // Run the form values to get all the fields they want.
  while (isset($form_values['field_select_' . $i])) {
    if ($form_values['field_select_' . $i]) {
      $fields[] = array(
        'title' => $form_values['field_name_' . $i],
        'weight' => $form_values['field_weight_' . $i],
      );
    }
    ++$i;
  }

  // A little hoop jumping to sort right.
  uasort($fields, '_realname_sort');
  $realname_fields = array();
  foreach ($fields as $key => $values) {
    $realname_fields[$values['title']] = $values['weight'];
  }

  // Okay, save the stuff.
  variable_set('realname_fields', $realname_fields);
  variable_set('realname_pattern', $form_values['realname_pattern']);
  variable_set('realname_theme', $form_values['realname_theme']);
  variable_set('realname_max_username', $form_values['realname_max_username']);
  variable_set('realname_nodeapi', $form_values['realname_nodeapi']);
  variable_set('realname_notver', $form_values['realname_notver']);
  variable_set('realname_nofollow', $form_values['realname_nofollow']);
  variable_set('realname_homepage', $form_values['realname_homepage']);
  drupal_set_message(t('Configuration has been updated.'), 'status');
}

Functions

Namesort descending Description
realname_admin_bypass
realname_admin_bypass_submit
realname_admin_settings Displays the admin settings form.
realname_admin_settings_submit Form submit handler.
realname_comment Implementation of hook_comment().
realname_form_alter Implementation of hook_form_alter(). Intercepts the contact forms to show the realname.
realname_help Implementation of hook_help().
realname_make_name Using selected fields, build the "real name" field in the object.
realname_menu Implementation of hook_menu().
realname_nodeapi Implementation of hook_nodeapi().
realname_perm Implementation of hook_perm().
realname_privatemsg_autocomplete Intercept Privatemsg autocomplete results for usernames.
realname_user Implementation of hook_user().
realname_userref_autocomplete CCK Userref intercept; Change autocomplete suggestions to realnames.
_realname_sort Provides array sorting function for uasort. @link http://us2.php.net/manual/en/function.uasort.php PHP Manual @end-link

Constants

Namesort descending Description
MODULE_VERSION @file The RealName module allows the admin to choose fields from the user profile that will be used to add a "realname" element (method) to a user object. Hook_user is used to automatically add this to any user object that is loaded.