diff --git realname.admin.inc realname.admin.inc
index 365dc8a..dfa7d50 100644
--- realname.admin.inc
+++ realname.admin.inc
@@ -215,7 +215,6 @@ function realname_admin_bypass_submit($form, &$form_state) {
 function realname_admin_module($form_state) {
   $form = array();
   // Get the list of modules we support.
-  include_once(drupal_get_path('module', 'realname') .'/realname_supported.inc');
   $supported_modules = realname_supported_modules();
 
   $choices = $show_types = array();
@@ -274,9 +273,13 @@ function realname_admin_module_submit($form, &$form_state) {
 
     $show_types = $form_state['values']['show_types'];
     if ($show_types[$module]) {
-      include_once(drupal_get_path('module', 'realname') .'/realname_'. $module .'.inc');
-      // This module uses types, so let's see what types are allowed.
-      $types = call_user_func('realname_'. $module .'_get_types');
+      $module_info = realname_supported_modules($module);
+      if (isset($module_info['file'])) {
+        $path = !empty($module_info['path']) ? $module_info['path'] : drupal_get_path('module', $module);
+        require_once($path .'/'. $module_info['file']);
+      }
+        // This module uses types, so let's see what types are allowed.
+      $types = (array) module_invoke($module, 'realname_get_types');
       if (count($types) > 1) {
         $form_state['storage']['types'] = $types;
         return;
@@ -297,113 +300,126 @@ function realname_admin_module_submit($form, &$form_state) {
 
 function realname_admin_fields() {
   $form = array();
-  $current = variable_get('realname_fields', array());
   $module = variable_get('realname_profile_module', NULL);
-  $type = variable_get('realname_profile_type', NULL);
   // Do we have a module set yet?
   if (!$module) {
     drupal_goto('admin/user/realname/module');
   }
 
-  $what = t('You are using the %module module to provide fields.', array('%module' => $module));
-  if ($type) {
-    $what .= t('The %type type is the source of data.', array('%type' => $type));
-  }
-
-  $form['heading'] = array(
-    '#type' => 'item',
-    '#value' => $what,
-    );
-
-  include_once(drupal_get_path('module', 'realname') .'/realname_'. $module .'.inc');
-  $profile_fields = call_user_func('realname_'. $module .'_get_fields', $current, $type);
-  $fields = $profile_fields['fields'];
-  $links = $profile_fields['links'];
-  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>',
+  $module_info = $module ? realname_supported_modules($module) : NULL;
+  if (isset($module_info['fields']) && !$module_info['fields']) {
+    $form['heading'] = array(
+      '#type' => 'item',
+      '#value' => t("You are using the %module module to provide data and it doesn't utilize fields.", array('%module' => $module)),
       );
+  }
+  else {
+    if (isset($module_info['file'])) {
+      $path = !empty($module_info['path']) ? $module_info['path'] : drupal_get_path('module', $module);
+      require_once($path .'/'. $module_info['file']);
+    }
+    $current = variable_get('realname_fields', array());
+    $type = (!isset($module_info['type']) || !$module_info['type']) ? variable_get('realname_profile_type', NULL) : NULL;
+    $profile_fields = (array) module_invoke($module, 'realname_get_fields', $current, $type);
 
-    $form['field_name_'. $i] = array(
-      '#type' => 'hidden',
-      '#value' => $f_name,
-      );
+    $what = t('You are using the %module module to provide fields.', array('%module' => $module));
+    if ($type) {
+      $what .= t('The %type type is the source of data.', array('%type' => $type));
+    }
 
-    $form['field_title_'. $i] = array(
+    $form['heading'] = array(
       '#type' => 'item',
-      '#value' => $values['title'],
-      '#prefix' => '<td>',
-      '#suffix' => '</td>',
+      '#value' => $what,
       );
 
-    $form['field_weight_'. $i] = array(
-      '#type' => 'weight',
-      '#delta' => 10,
-      '#default_value' => $values['weight'],
-      '#prefix' => '<td>',
-      '#suffix' => '</td></tr>',
-      );
+    $fields = $profile_fields['fields'];
+    $links = $profile_fields['links'];
+    uasort($fields, '_realname_sort');
 
-    ++$i;
-  }
-
-  $form['end_table'] = array(
-    '#type' => 'markup',
-    '#value' => '</table>',
-    );
+    $form['start_table'] = array(
+      '#type' => 'markup',
+      '#value' => '<table><tr><th>Select</th><th>Field name</th><th>Weight</th></tr>',
+      );
 
-  $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'),
-    );
+    $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;
+    }
 
-  // If there were any URL fields, give a home page option.
-  if ($links) {
-    $links[''] = t('');
-    asort($links);
-    $form['homepage'] = array(
-      '#type' => 'fieldset',
-      '#title' => t('Homepage options'),
-      '#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.'),
-      '#collapsible' => TRUE,
-      '#collapsed' => count($links) == 0,
+    $form['end_table'] = array(
+      '#type' => 'markup',
+      '#value' => '</table>',
       );
 
-    $form['homepage']['realname_homepage'] = array(
-      '#type' => 'select',
-      '#options' => $links,
-      '#title' => t('Link to homepage'),
-      '#description' => t('Select a personal homepage link, if appropriate.'),
-      '#default_value' => variable_get('realname_homepage', NULL),
+    $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['homepage']['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),
+    // If there were any URL fields, give a home page option.
+    if ($links) {
+      $links[''] = t('');
+      asort($links);
+      $form['homepage'] = array(
+        '#type' => 'fieldset',
+        '#title' => t('Homepage options'),
+        '#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.'),
+        '#collapsible' => TRUE,
+        '#collapsed' => count($links) == 0,
+        );
+
+      $form['homepage']['realname_homepage'] = array(
+        '#type' => 'select',
+        '#options' => $links,
+        '#title' => t('Link to homepage'),
+        '#description' => t('Select a personal homepage link, if appropriate.'),
+        '#default_value' => variable_get('realname_homepage', NULL),
+        );
+
+      $form['homepage']['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'),
       );
   }
 
-  $form['submit'] = array(
-    '#type' => 'submit',
-    '#value' => t('Save'),
-    );
-
   return $form;
 }
 
diff --git realname.api.php realname.api.php
new file mode 100644
index 0000000..0b928f8
--- /dev/null
+++ realname.api.php
@@ -0,0 +1,172 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Hooks provided by the RealName module.
+ */
+
+/**
+ * @addtogroup hooks
+ * @{
+ */
+
+ /**
+  * Define RealName support and options.
+  *
+  * This hook enables modules to register RealName support.
+  *
+  * @return
+  *   An array of options that the module support. The item is an associative array
+  *   that may contain the following key-value pairs:
+  *   - "name": Required. The name of the module.
+  *   - "types": Whether the module supports types.
+  *   - "fields": Whether the module uses fields.
+  *   - "file": A file that will be included before the module is used by RealName;
+  *     this allows callback functions to be in separate files. The file should
+  *     be relative to the implementing module's directory unless otherwise
+  *     specified by the "file path" option.
+  *   - "file path": The path to the folder containing the file specified in
+  *     "file". This defaults to the path to the module implementing the hook.
+  */
+function hook_realname() {
+  return array(
+    'name'   => 'Content Profile',
+    'types'  => TRUE,
+    'fields' => TRUE,
+    'file'   => 'realname_content_profile.inc',
+    'path'   => drupal_get_path('module', 'realname'),
+  );
+}
+
+/**
+ * Loads the profile fields.
+ *
+ * @param $account
+ *   An user object.
+ * @param $type
+ *   The type used - if supported by the module.
+ */
+function hook_load_profile(&$account, $type = NULL) {
+  $profile = content_profile_load($type, $account->uid);
+  if (!$profile) {
+    return;
+  }
+  $fields = content_fields(NULL, $type);
+  foreach ($fields as $field_name => $field_attributes) {
+    if (isset($profile->$field_name)) {
+      $values = array();
+      $contents = $profile->$field_name;
+      foreach ($contents as $content) {
+        if (isset($content['value'])) {
+          $values[] = $content['value'];
+        }
+        else {
+          $values[] = content_format($field_name, $content);
+        }
+      }
+      if (empty($account->{$field_name})) {
+        switch (count($values)) {
+          case 0:
+            $account->{$field_name} = NULL;
+            break;
+          case 1:
+            $account->{$field_name} = $values[0];
+            break;
+          default:
+            $account->{$field_name} = $values;
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Gets available types.
+ *
+ * Supplies the types supported by the module if the module supports types.
+ *
+ * @return
+ *   An array keyed by type with info.
+ */
+function hook_realname_get_types() {
+  return content_profile_get_types('names');
+}
+
+/**
+ * Gets available fields.
+ *
+ * Supplies the fields supported by the module if the module supports fields.
+ *
+ * @param $current
+ *   An array with the currently used fields keyed by field.
+ * @param $type
+ *   An array containing the current type.
+ * @return
+ *   An associative array with two keys:
+ *   - "fields": Required. An array keyed by field name of fields as
+ *     associative arrays containing:
+ *     - "title": The title of the field
+ *     - "weight": The weight of the field
+ *     - "selected": A boolean value of whether the field is slected or not
+ *   - "links": Required. An array of field labels keyed by field name
+ */
+function hook_realname_get_fields($current, $type = NULL) {
+  $fields = $links = array();
+  $all_fields = content_fields(NULL, $type);
+  if ($all_fields) {
+    foreach ($all_fields as $field_name => $field_attributes) {
+      // If it's not they type we are looking for, then skip the field.
+      if ($field_attributes['type_name'] != $type) {
+        continue;
+      }
+      switch ($field_attributes['type']) {
+        case 'text':
+          if ($field_attributes['multiple']) {
+            drupal_set_message(t('The RealName module does not currently support fields with multiple values, such as @fld.', array('@fld' => $field_name)), 'warning');
+          }
+          else {
+            $selected = array_key_exists($field_name, $current);
+            $fields[$field_name] = array(
+              'title' => $field_attributes['widget']['label'],
+              'weight' => $selected ? $current[$field_name] : 0,
+              'selected' => $selected,
+              );
+          }
+          break;
+
+        case 'link':
+          $links[$field_name] = $field_attributes['widget']['label'];
+      }
+    }
+  }
+  else {
+    drupal_set_message(t('The !type content type has no fields to use.', array('!type' => $type)), 'error');
+  }
+
+  if (variable_get('realname_use_title', FALSE)) {
+    $fields['title'] = array(
+      'title' => t('Node title'),
+      'weight' => isset($current['title']) ? $current['title']['weight'] : 0,
+      'selected' => array_key_exists('title', $current),
+      );
+  }
+
+  return array('fields' => $fields, 'links' => $links);
+}
+
+/**
+ * Gets a name for a user
+ *
+ * Modules not supporting fields for name data has to
+ * implement this hook instead
+ *
+ * @param $account
+ *   An user object.
+ * @return
+ *   A string with the name or NULL.
+ */
+function hook_realname_make($account) {
+  $info = _connector_information_fetch($account);
+  return !empty($info['real name']) ? $info['real name'] : NULL;
+}
\ No newline at end of file
diff --git realname.module realname.module
index 6d3ae05..ec805fa 100644
--- realname.module
+++ realname.module
@@ -411,10 +411,15 @@ function realname_user($op, &$edit, &$account, $category = NULL) {
 
     case 'insert':
     case 'after_update':
-      $account->realname = _realname_make_name($account);
-      // If we delete it first, then drupal_write_record is always an insert.
-      db_query("DELETE FROM {realname} WHERE uid=%d", $account->uid);
-      drupal_write_record('realname', $account);
+      if ($module = variable_get('realname_profile_module', NULL)) {
+        $module_info = realname_supported_modules($module);
+      }
+      if (!isset($module_info['cache']) || $module_info['cache']) {
+        $account->realname = _realname_make_name($account);
+        // If we delete it first, then drupal_write_record is always an insert.
+        db_query("DELETE FROM {realname} WHERE uid=%d", $account->uid);
+        drupal_write_record('realname', $account);
+      }
   }
 }
 
@@ -707,6 +712,47 @@ function realname_privatemsg_autocomplete($string) {
 //* Module Functions
 //********************************************************************
 
+function _realname_include() {
+  static $not_run = TRUE;
+
+  if ($not_run) {
+    $path = drupal_get_path('module', 'realname');
+    if (module_exists('content_profile')) {
+      require_once("$path/realname_content_profile.inc");
+    }
+    if (module_exists('profile')) {
+      require_once("$path/realname_profile.inc");
+    }
+    $not_run = TRUE;
+  }
+}
+
+function realname_supported_modules($module = NULL) {
+  static $modules;
+
+  _realname_include();
+
+  if (!isset($modules)) {
+    foreach (module_implements('realname') as $value) {
+      $options = call_user_func($value .'_realname');
+      if (isset($options) && is_array($options)) {
+        $modules[$value] = $options;
+      }
+    }
+  }
+
+  if ($module) {
+    if (array_key_exists($module, $modules)) {
+      return $modules[$module];
+    }
+    else {
+      return FALSE;
+    }
+  }
+
+  return $modules;
+}
+
 /**
  * Retreive calculated user name. Try static cache first, DB next and on failure call
  * helper function to calculate realname and populate DB.
@@ -732,15 +778,23 @@ function realname_make_name(&$account) {
     return $users[$account->uid];
   }
 
-  $result = _realname_make_name($account);
-  if (empty($result)) {
-    return $account->name;
+  if ($module = variable_get('realname_profile_module', NULL)) {
+    $module_info = realname_supported_modules($module);
   }
-  if (!db_result(db_query("SELECT uid FROM {realname} WHERE uid=%d", $account->uid))) { 
-    db_query("INSERT INTO {realname} (uid, realname) VALUES(%d, '%s')", $account->uid, $result);
+  if (!isset($module_info['cache']) || $module_info['cache']) {
+    $result = _realname_make_name($account);
+    if (empty($result)) {
+      return $account->name;
+    }
+    if (!db_result(db_query("SELECT uid FROM {realname} WHERE uid=%d", $account->uid))) { 
+      db_query("INSERT INTO {realname} (uid, realname) VALUES(%d, '%s')", $account->uid, $result);
+    }
+    else {
+      db_query("UPDATE {realname} SET realname='%s' where uid=%d", $result, $account->uid);
+    }
   }
   else {
-    db_query("UPDATE {realname} SET realname='%s' where uid=%d", $result, $account->uid);
+    $result = _realname_make_name($account);
   }
   return $result;
 }
@@ -755,41 +809,65 @@ function realname_make_name(&$account) {
  *   The constructed "real name" string.
  */
 function _realname_make_name(&$account) {
-  static $fields, $pattern_saved, $homepage, $use_theme, $type, $module, $profile_privacy;
-  $users = &drupal_static('users',array());
+  static $fields, $pattern_saved, $homepage, $use_theme, $type, $module, $module_info, $profile_privacy;
   $links = &drupal_static('links',array());
   $edit = &drupal_static('edit',array());
 
   // Get our controlling variables (static makes it once per page load).
-  if (!isset($fields)) {
-    $fields = variable_get('realname_fields', array());
-    // Are there any fields assigned yet?
-    if (!$fields) {
-      // No, so just return the name.
-      return $account->name;
-    }
-    $pattern_saved = variable_get('realname_pattern', ' ');
-    $homepage = variable_get('realname_homepage', NULL);
-    $use_theme = variable_get('realname_theme', TRUE);
+  if (!isset($module)) {
     $module = variable_get('realname_profile_module', NULL);
-    $type = variable_get('realname_profile_type', NULL);
-    $profile_privacy = module_exists('profile_privacy');
-    if ($module && module_exists($module)) {
-      include_once(drupal_get_path('module', 'realname') .'/realname_'. $module .'.inc');
-    }
-    else {
-      drupal_set_message(t('No module is available for RealName.'), 'error');
-      return $account->name;
+    if ($module) {
+      $module_info = realname_supported_modules($module);
+      if (!$module_info || !module_exists($module)) {
+        unset($module_info);
+        $module = FALSE;
+      }
+      else {
+        if (isset($module_info['file'])) {
+          $path = !empty($module_info['path']) ? $module_info['path'] : drupal_get_path('module', $module);
+          require_once($path .'/'. $module_info['file']);
+        }
+        if (!isset($module_info['fields']) || $module_info['fields']) {
+          $fields = variable_get('realname_fields', array());
+          // Are there any fields assigned yet?
+          if (!$fields) {
+            // No, so just return the name.
+            return $account->name;
+          }
+          $pattern_saved = variable_get('realname_pattern', ' ');
+        }
+        else {
+          $fields = FALSE;
+        }
+        $homepage = variable_get('realname_homepage', NULL);
+        $use_theme = variable_get('realname_theme', TRUE);
+        if (isset($module_info['type']) && $module_info['type']) {
+          $type = variable_get('realname_profile_type', NULL);
+        }
+        else {
+          $type = FALSE;
+        }
+        $profile_privacy = module_exists('profile_privacy');
+      }
     }
   }
-  $pattern = $pattern_saved;
 
-  // Has the module been set up yet?
-  if ($fields) {
+  if (!$module) {
+    drupal_set_message(t('No module is available for RealName.'), 'error');
+    $string = $account->name;
+  }
+  else if (is_array($fields) && empty($fields)) {
+    $string = $account->name;
+  }
+  else if ($fields === FALSE) {
+    $string = module_invoke($module, 'realname_make', $account);
+  }
+  else if ($fields) {
+    $pattern = $pattern_saved;
+
     // Has the profile been loaded?
     if (!isset($account->{key($fields)})) {
-      $load_func = $module .'_load_profile';
-      if (!function_exists($load_func)) {
+      if (!module_hook($module, 'load_profile')) {
         drupal_set_message(t('The profile load function (!module) was not found.', array('!module' => $load_func)), 'error');
         return $account->name;
       }
@@ -834,11 +912,12 @@ function _realname_make_name(&$account) {
     }
 
     $string = trim(strtr($pattern, $stuff));
-    $users[$account->uid] = $string;
   }
-  else {
+
+  if (empty($string)) {
     $string = $account->name;
   }
+
   return html_entity_decode(filter_xss_admin($string));
 }
 
diff --git realname_content_profile.inc realname_content_profile.inc
index 0f7f649..26fa7c9 100644
--- realname_content_profile.inc
+++ realname_content_profile.inc
@@ -6,6 +6,19 @@
  */
 
 /**
+ * Implementation of hook_realname().
+ */
+function content_profile_realname() {
+  return array(
+    'name'   => 'Content Profile',
+    'types'  => TRUE,
+    'fields' => TRUE,
+    'file'   => 'realname_content_profile.inc',
+    'path'   => drupal_get_path('module', 'realname'),
+  );
+}
+
+/**
  * Implementation of hook_profile_load();
  */
 function content_profile_load_profile(&$account, $type = NULL) {
@@ -45,11 +58,11 @@ function content_profile_load_profile(&$account, $type = NULL) {
 //  $account->title = $profile->title; // http://drupal.org/node/606364
 }
 
-function realname_content_profile_get_types() {
+function content_profile_realname_get_types() {
   return content_profile_get_types('names');
 }
 
-function realname_content_profile_get_fields($current, $type) {
+function content_profile_realname_get_fields($current, $type) {
   $fields = $links = array();
   $all_fields = content_fields(NULL, $type);
   if ($all_fields) {
diff --git realname_profile.inc realname_profile.inc
index da6cb4c..d6562c1 100644
--- realname_profile.inc
+++ realname_profile.inc
@@ -5,7 +5,20 @@
  * Realname module support for Profile (core) module.
  */
 
-function realname_profile_get_fields($current) {
+/**
+ * Implementation of hook_realname().
+ */
+function profile_realname() {
+  return array(
+    'name'   => 'Core Profile',
+    'types'  => FALSE,
+    'fields' => TRUE,
+    'file'   => 'realname_profile.inc',
+    'path'   => drupal_get_path('module', 'realname'),
+  );
+}
+
+function profile_realname_get_fields($current) {
   $fields = $links = array();
   $result = db_query("SELECT name, type, title FROM {profile_fields}");
   while ($field = db_fetch_array($result)) {
@@ -13,7 +26,7 @@ function realname_profile_get_fields($current) {
       case 'selection':
       case 'textfield':
         $name = $field['name'];
-        $selected = array_key_exists($name, $current);
+        $selected = array_key_exists($name, (array) $current);
         $fields[$name] = array(
           'title' => $field['title'],
           'weight' => $selected ? $current[$name] : 0,
diff --git realname_supported.inc realname_supported.inc
deleted file mode 100644
index 8c03208..0000000
--- realname_supported.inc
+++ /dev/null
@@ -1,20 +0,0 @@
-<?php
-// $Id: realname_supported.inc,v 1.1.2.2 2008/11/03 20:10:34 nancyw Exp $
-/**
- * @file
- * Realname module support list.
- */
-
-function realname_supported_modules() {
-  $list = array(
-    'content_profile' => array(
-      'name' => 'Content Profile',
-      'types' => TRUE,
-      ),
-    'profile' => array(
-      'name' => 'Core Profile',
-      'types' => FALSE,
-      ),
-    );
-  return $list;
-}
