diff --git a/privatemsg.admin.inc b/privatemsg.admin.inc
index 534bdea..74a10c8 100644
--- a/privatemsg.admin.inc
+++ b/privatemsg.admin.inc
@@ -120,18 +120,38 @@ function privatemsg_admin_settings() {
     '#description' => t('Choose the number of conversations that should be listed per page.'),
   );
 
-  $form['privatemsg_listing']['privatemsg_display_fields'] = array(
-    '#type' => 'checkboxes',
+  $form['privatemsg_listing']['privatemsg_fields'] = array(
+    '#type' => 'fieldset',
     '#title' => t('Configure fields'),
-    '#description' => t('Select which columns/fields should be displayed in the message listings. Subject and Last updated cannot be disabled.'),
-    '#options' => array(
-      'participants'    => t('Participants'),
-      'thread_started'  => t('Started'),
-      'count'           => t('Messages'),
+    '#description' => t('Select which columns/fields should be displayed in the message listings.'),
+    '#collapsible' => FALSE,
+    '#theme' => 'privatemsg_admin_settings_display_fields',
+    'privatemsg_display_fields' => array(
+      '#tree' => TRUE,
+    ),
+    'privatemsg_display_fields_weights' => array(
+      '#tree' => TRUE,
     ),
-    '#default_value' => variable_get('privatemsg_display_fields', array('participants')),
   );
 
+  foreach (privatemsg_get_headers() as $key => $header) {
+    $form['privatemsg_listing']['privatemsg_fields']['privatemsg_display_fields'][$key] = array(
+      '#type' => 'checkbox',
+      '#title' => $header['#title'],
+      '#return_value' => $key,
+      '#default_value' => $header['#enabled'],
+      '#disabled' => $header['#locked'],
+      '#weight' => $header['#weight'],
+    );
+
+    $form['privatemsg_listing']['privatemsg_fields']['privatemsg_display_fields_weights'][$key] = array(
+      '#type' => 'weight',
+      '#title' => t('!field weight', array('!field' => $header['#title'])),
+      '#default_value' => $header['#weight'],
+      '#delta' => 20,
+    );
+  }
+
   $form['privatemsg_listing']['privatemsg_url_prefix'] = array(
     '#type' => 'textfield',
     '#title' => t('Base URL path'),
@@ -226,6 +246,8 @@ function privatemsg_admin_settings() {
  */
 function privatemsg_admin_settings_submit($form, &$form_state) {
   // Only rebuild menu if url prefix has changed.
+  dpm($form_state['values']);
+  dpm($_POST);
   if ($form_state['values']['privatemsg_url_prefix'] != $form['privatemsg_listing']['privatemsg_url_prefix']['#default_value']) {
     menu_rebuild();
   }
diff --git a/privatemsg.api.php b/privatemsg.api.php
index 0922740..098b7c5 100644
--- a/privatemsg.api.php
+++ b/privatemsg.api.php
@@ -669,4 +669,47 @@ function hook_privatemsg_recipient_type_info_alter(&$types) {
 
 /**
  * @}
- */
\ No newline at end of file
+ */
+
+/**
+ * Declare headers for message listings.
+ *
+ * @return
+ *   An array keyed by an identifier. All header definition keys for theme_table
+ *   and tablesortort_sql() and the following additional keys:
+ *     - #enabled: TRUE if the header should be enabled by default. FALSE by
+ *                 default.
+ *     - #locked: TRUE if it the header should be locked and can not be
+ *                enabled or disabled in the user interface.
+ *     - #weight: The default weight which can be changed in the user interface.
+ *     - #title: A title used in the administrative user interface. Defaults to
+ *               data.
+ *     - #access: Control if the header is accessible, TRUE or FALSE.
+ *     - #theme: Optionally define a theme function for the field. Defaults to
+ *               'privatemsg_list_field_$key'.
+ *
+ * @see theme_table
+ * @ingroup theming
+ */
+function hook_privatemsg_header_info() {
+  return array(
+    'subject' => array(
+      'data'    => t('Subject'),
+      'field'   => 'subject',
+      'class'   => 'privatemsg-header-subject',
+      '#enabled' => TRUE,
+      '#locked'  => TRUE,
+      '#weight'  => -20,
+    ),
+  );
+}
+
+/**
+ * Alter the defined header structure.
+ *
+ * @param $headers
+ *   All headers returned by hook_privatemsg_header_info().
+ */
+function hook_privatemsg_header_info_alter(&$headers) {
+
+}
\ No newline at end of file
diff --git a/privatemsg.install b/privatemsg.install
index ea05b70..3768f16 100644
--- a/privatemsg.install
+++ b/privatemsg.install
@@ -129,6 +129,7 @@ function privatemsg_uninstall() {
   variable_del('privatemsg_per_page');
   variable_del('privatemsg_display_loginmessage');
   variable_del('privatemsg_display_fields');
+  variable_del('privatemsg_display_fields_weights');
   variable_del('privatemsg_display_link_self');
   variable_del('privatemsg_view_default_amount');
   variable_del('privatemsg_view_max_amount');
diff --git a/privatemsg.module b/privatemsg.module
index 3b09803..9ef4e7a 100644
--- a/privatemsg.module
+++ b/privatemsg.module
@@ -686,14 +686,8 @@ function privatemsg_theme() {
       'path'                  => drupal_get_path('module', 'privatemsg'),
       'arguments'        => array('form'),
     ),
-    // Define pattern for header/field templates. The theme system will register all
+    // Define pattern for field templates. The theme system will register all
     // theme functions that start with the defined pattern.
-    'privatemsg_list_header'  => array(
-      'file'                  => 'privatemsg.theme.inc',
-      'path'                  => drupal_get_path('module', 'privatemsg'),
-      'pattern'               => 'privatemsg_list_header__',
-      'arguments'             => array(),
-    ),
     'privatemsg_list_field'   => array(
       'file'                  => 'privatemsg.theme.inc',
       'path'                  => drupal_get_path('module', 'privatemsg'),
@@ -710,6 +704,12 @@ function privatemsg_theme() {
       'path'                  => drupal_get_path('module', 'privatemsg'),
       'arguments'             => array('recipient' => NULL, 'options' => array()),
     ),
+    // Admin settings theme callbacks.
+    'privatemsg_admin_settings_display_fields' => array(
+      'file'                  => 'privatemsg.theme.inc',
+      'path'                  => drupal_get_path('module', 'privatemsg'),
+      'arguments'             => array('element' => array()),
+    ),
   );
 }
 
@@ -1000,7 +1000,7 @@ function privatemsg_sql_list(&$fragments, $account, $argument = 'list') {
   $fragments['primary_table'] = '{pm_message} pm';
 
   // Load enabled columns.
-  $fields = array_filter(variable_get('privatemsg_display_fields', array('participants')));
+  $fields = privatemsg_get_enabled_headers();
 
   // Required columns.
   $fragments['select'][]      = 'pmi.thread_id';
@@ -1048,7 +1048,7 @@ function privatemsg_sql_list(&$fragments, $account, $argument = 'list') {
   // tablesort_sql() generates a ORDER BY string. However, the "ORDER BY " part
   // is not needed and added by the query builder. Discard the first 9
   // characters of the string.
-  $order_by = drupal_substr(tablesort_sql(_privatemsg_list_headers(FALSE, array_merge(array('subject', 'last_updated'), $fields))), 9);
+  $order_by = drupal_substr(tablesort_sql(privatemsg_get_headers()), 9);
   $fragments['order_by'][]  = $order_by;
 }
 
@@ -2329,59 +2329,6 @@ function privatemsg_views_api() {
 }
 
 /**
- * Returns a table header definition based on the submitted keys.
- *
- * Uses @link theming theme patterns @endlink to theme single headers.
- *
- * @param $has_posts
- *   TRUE when there is at least one row. Decides if the select all checkbox
- *   should be displayed.
- * @param $keys
- *   Array with the keys which are present in the query/should be displayed.
- * @return
- *   Array with header defintions for tablesort_sql and theme('table').
- */
-function _privatemsg_list_headers($has_posts, $keys) {
-  $select_header = $has_posts ? theme('table_select_header_cell') : '';
-  $select_header['#weight'] = -50;
-
-  // theme() doesn't include the theme file for patterns, we need to do it manually.
-  include_once drupal_get_path('module', 'privatemsg') .'/privatemsg.theme.inc';
-
-  $header = array($select_header);
-  foreach ($keys as $key) {
-    // First, try to load a specific theme for that header, if not present, use the default.
-    if ($return = theme(array('privatemsg_list_header__'. $key, 'privatemsg_list_header'))) {
-      // The default theme returns nothing, only store the value if we have something.
-      $header[$key] = $return;
-    }
-  }
-  if (count($header) == 1) {
-    // No header definition returned, fallback to the default.
-    $header += _privatemsg_list_headers_fallback($keys);
-  }
-  return $header;
-}
-
-/**
- * Table header definition for themes that don't support theme patterns.
- *
- * @return
- *   Array with the correct headers.
- */
-function _privatemsg_list_headers_fallback($keys) {
-  $header = array();
-  foreach ($keys as $key) {
-    $theme_function = 'phptemplate_privatemsg_list_header__' . $key;
-    if (function_exists($theme_function)) {
-      $header[$key] = $theme_function();
-    }
-  }
-
-  return $header;
-}
-
-/**
  * Formats a row in the message list.
  *
  * Uses @link theming theme patterns @endlink to theme single fields.
@@ -2398,9 +2345,11 @@ function _privatemsg_list_thread($thread) {
     // Set the css class in the tr tag.
     $row['class'] = 'privatemsg-unread';
   }
-  foreach ($thread as $key => $data) {
+  $enabled_headers = privatemsg_get_enabled_headers();
+  $headers = privatemsg_get_headers();
+  foreach ($enabled_headers as $key) {
     // First, try to load a specific theme for that field, if not present, use the default.
-    if ($return = theme(array('privatemsg_list_field__'. $key, 'privatemsg_list_field'), $thread)) {
+    if ($return = theme($headers[$key]['#theme'], $thread)) {
       // The default theme returns nothing, only store the value if we have something.
       $row['data'][$key] = $return;
     }
@@ -2504,6 +2453,7 @@ function privatemsg_recipient_get_types() {
   }
   return $types;
 }
+
 /**
  * Return a single recipient type information.
  * @param $type
@@ -2731,3 +2681,135 @@ function privatemsg_user_autocomplete($fragment, $names, $limit) {
   }
   return $suggestions;
 }
+
+/**
+ * Returns an array of defined column headers for message listings.
+ *
+ * @param $visible_only
+ *   Disabled and denied headers and properties starting with # are removed.
+ *
+ * @return
+ *   Array of headers.
+ *
+ * @see hook_privatemsg_header_info()
+ *
+ * @ingroup types
+ */
+function privatemsg_get_headers($visible_only = FALSE) {
+  static $headers = NULL;
+
+  if ($headers === NULL) {
+    $headers = module_invoke_all('privatemsg_header_info');
+    if (!is_array($headers)) {
+      $headers = array();
+    }
+
+    $weights = variable_get('privatemsg_display_fields_weights', array());
+    $enabled = variable_get('privatemsg_display_fields', array('subject', 'participants', 'last_updated'));
+
+    // Apply defaults and configurations.
+    foreach ($headers as $key => &$header) {
+      // Apply defaults.
+      $header += array(
+        '#enabled' => FALSE,
+        '#weight' => 0,
+        '#title' => $header['data'],
+        '#access' => TRUE,
+        '#locked' => FALSE,
+        '#theme' => 'privatemsg_list_field__' . $key,
+      );
+      if (empty($header['#locked']) && isset($enabled[$key])) {
+        $header['#enabled'] = (bool)$enabled[$key];
+      }
+      if (isset($weights[$key])) {
+        $header['#weight'] =  $weights[$key];
+      }
+    }
+
+    drupal_alter('privatemsg_header_info', $headers);
+    uasort($headers, 'element_sort');
+  }
+  if ($visible_only) {
+    // Remove all attributes prefixed with a # and disabled headers.
+    $headers_visible = $headers;
+    foreach ($headers_visible as $header_key => &$header) {
+      if (!$header['#enabled'] || !$header['#access']) {
+        unset($headers_visible[$header_key]);
+      }
+      else {
+        foreach ($header as $key => $value) {
+          if ($key[0] == '#') {
+            unset($header[$key]);
+          }
+        }
+      }
+    }
+    return $headers_visible;
+  }
+  else {
+    return $headers;
+  }
+}
+
+/**
+ * Returns an array of enabled header keys.
+ *
+ * @return
+ *   A indexed array with the header keys as value, ordered by their weight.
+ */
+function privatemsg_get_enabled_headers() {
+  static $header_keys = NULL;
+
+  if ($header_keys === NULL) {
+    $header_keys = array();
+    $headers = privatemsg_get_headers();
+    foreach ($headers as $key => $header) {
+      if ($header['#enabled']) {
+        $header_keys[] = $key;
+      }
+    }
+  }
+  return $header_keys;
+}
+
+/**
+ * Implements hook_privatemsg_header_info().
+ */
+function privatemsg_privatemsg_header_info() {
+  return array(
+    'subject' => array(
+      'data'    => t('Subject'),
+      'field'   => 'subject',
+      'class'   => 'privatemsg-header-subject',
+      '#enabled' => TRUE,
+      '#locked'  => TRUE,
+      '#weight'  => -20,
+    ),
+    'count' => array(
+      'data'    => t('Messages'),
+      'class'   => 'privatemsg-header-count',
+      '#weight'  => -5,
+    ),
+    'participants' => array(
+      'data'    => t('Participants'),
+      'class'   => 'privatemsg-header-participants',
+      '#weight'  => -15,
+      '#enabled' => TRUE,
+    ),
+    'last_updated' => array(
+      'data'    => t('Last Updated'),
+      'field'   => 'last_updated',
+      'sort'    => 'desc',
+      'class'   => 'privatemsg-header-lastupdated',
+      '#enabled' => TRUE,
+      '#locked'  => TRUE,
+      '#weight'  => 20,
+    ),
+    'thread_started' => array(
+      'data'    => t('Started'),
+      'field'   => 'thread_started',
+      'class'   => 'privatemsg-header-threadstarted',
+      '#weight'  => -10,
+    ),
+  );
+}
diff --git a/privatemsg.theme.inc b/privatemsg.theme.inc
index 2f7ac4d..4e766ce 100644
--- a/privatemsg.theme.inc
+++ b/privatemsg.theme.inc
@@ -8,45 +8,33 @@
 /**
  * @defgroup theming Theming documentation
  *
- * It is possible to theme every aspect of privatemsg with theme functions.
+ * It is possible to theme many aspect of privatemsg with theme functions.
  *
  * For the thread list, so called theme patterns are used to allow flexible
  * theming of the table and its columns (including columns added by other
  * modules).
  *
- * Three requirements have to be fulfilled so a new column, with data, is
- * displayed in the private message list:
- *  - A field needs to be returned by the list query, see @link sql Query Builder @endlink.
- *  - A header theme pattern needs to exist for the field.
- *  - A field theme pattern needs to exist for the field.
+ * Columns are defined with hook_privatemsg_header_info(). The default weight
+ * and if they are enabled or not can by set by default but can be overriden in
+ * the admin user interface.
  *
- * For each field in the query, Privatemsg will try to call a theme pattern for
- * the header. That theme function can return a table header definition and
- * has the following structure: phptemplate_privatemsg_header_fieldname.
- * @see theme_privatemsg_list_header()
+ * Additionally, a theme function needs to be defined that defaults to the name
+ * 'privatemsg_list_field__$key', where $key is the name of the header/column.
  *
- * Privatemsg will then do the same for each row, with the field theme pattern.
- * That theme function should return a table field compatible structure, either
- * just a string or an array. The theme function has to have the following
- * name: phptemplate_privatemsg_header_fieldname.
- * @see theme_privatemsg_list_field()
+ * Every theme function will receive the $thread array as single argument, which
+ * is everything that has been returned by the query built in
+ * privatemsg_sql_list(). The theme function should return either a string or a
+ * theme_table() compatible array.
  *
- * To override an already existing theme function, use the following structure:
- * themename_privatemsg_list_field_fieldname. It is not necessary to
- * overwrite the header theme function unless that information needs to be
- * changed too.
- *
- * Modules can use the hook_form_alter() hook to alter the data. The form with
- * id "privatemsg_list" will contain the header, raw and themed field data in
- * the following form:
- * @code
- * $form['#headers']['field_name'] = $header // Array with the header defintion;
- * $form['#data']['thread_id'] = $data // Raw data of that thread
- * $form['#rows']['thread_id'] = $row // Themed fields of that thread
- * @endcode
+ * To change what information is available in that array, it is possible to
+ * either implement hook_privatemsg_sql_list_alter() or alter $form['#data'] of
+ * privatemsg_list(). See privatemsg_filter_form_privatemsg_list_alter() for an
+ * example.
  *
- * Note that the information in #data can be used to populate #rows, but it will
- * not be used by the default theme function theme_privatemsg_list().
+ * To override an already existing theme function, use the following structure:
+ * themename_privatemsg_list_field_fieldname. It is possible to change the
+ * header definition with hook_privatemsg_header_info_alter() but that is often
+ * not necessary.
  */
 
 /**
@@ -55,24 +43,7 @@
  */
 
 /**
- * Default theme function for field theme.
- *
- * To hide all fields that don't have an explicit theme pattern defined, this
- * theme doesn't return anything.
- *
- * @param $thread
- *   Thread row returned by the list query.
- *
- * @return
- *   A theme_table() compatible field definition.
- */
-function theme_privatemsg_list_field($thread) {
-}
-
-/**
  * Theme the participants field.
- *
- * @see theme_privatemsg_list_field()
  */
 function phptemplate_privatemsg_list_field__participants($thread) {
   $participants = _privatemsg_generate_user_array($thread['participants'], -4);
@@ -84,8 +55,6 @@ function phptemplate_privatemsg_list_field__participants($thread) {
 
 /**
  * Theme the subject of the thread.
- *
- * @see theme_privatemsg_list_field()
  */
 function phptemplate_privatemsg_list_field__subject($thread) {
   $field = array();
@@ -102,8 +71,6 @@ function phptemplate_privatemsg_list_field__subject($thread) {
 
 /**
  * Theme the replies field.
- *
- * @see theme_privatemsg_list_field()
  */
 function phptemplate_privatemsg_list_field__count($thread) {
   $field = array();
@@ -119,8 +86,6 @@ function phptemplate_privatemsg_list_field__count($thread) {
 
 /**
  * Theme the last updated column.
- *
- * @see theme_privatemsg_list_field()
  */
 function phptemplate_privatemsg_list_field__last_updated($thread) {
   $field = array();
@@ -131,8 +96,6 @@ function phptemplate_privatemsg_list_field__last_updated($thread) {
 
 /**
  * Theme the thread started column.
- *
- * @see theme_privatemsg_list_field()
  */
 function phptemplate_privatemsg_list_field__thread_started($thread) {
   $field = array();
@@ -142,95 +105,6 @@ function phptemplate_privatemsg_list_field__thread_started($thread) {
 }
 
 /**
- * Define the table header for a specific column.
- *
- * This default theme function is used to ignore columns that should not be
- * displayed. Only columns with a specific theme pattern function are displayed.
- *
- * @return
- *   A theme_table() compatible table header definition. Additionally, the key
- *   "key" should be used to specify which row column should be displayed in
- *   this column.
- */
-function theme_privatemsg_list_header() {
-
-}
-
-/**
- * Define the subject header.
- *
- * @see theme_privatemsg_list_header()
- */
-function phptemplate_privatemsg_list_header__subject() {
-  return array(
-    'data'    => t('Subject'),
-    'field'   => 'subject',
-    'key'     => 'subject',
-    'class'   => 'privatemsg-header-subject',
-    '#weight' => -40,
-  );
-}
-
-/**
- * Define the answers column.
- *
- * @see theme_privatemsg_list_header()
- */
-function phptemplate_privatemsg_list_header__count() {
-  return array(
-    'data'    => t('Messages'),
-    'key'     => 'count',
-    'class'   => 'privatemsg-header-count',
-    '#weight' => -25,
-  );
-}
-
-/**
- * Define the participants column.
- *
- * @see theme_privatemsg_list_header()
- */
-function phptemplate_privatemsg_list_header__participants() {
-  return array(
-    'data'    => t('Participants'),
-    'key'     => 'participants',
-    'class'   => 'privatemsg-header-participants',
-    '#weight' => -30,
-  );
-}
-
-/**
- * Define the last updated column.
- *
- * @see theme_privatemsg_list_header()
- */
-function phptemplate_privatemsg_list_header__last_updated() {
-  return array(
-    'data'    => t('Last Updated'),
-    'field'   => 'last_updated',
-    'key'     => 'last_updated',
-    'sort'    => 'desc',
-    'class'   => 'privatemsg-header-lastupdated',
-    '#weight' => -20,
-  );
-}
-
-/**
- * Define the thread started column.
- *
- * @see theme_privatemsg_list_header()
- */
-function phptemplate_privatemsg_list_header__thread_started() {
-  return array(
-    'data'    => t('Started'),
-    'field'   => 'thread_started',
-    'key'     => 'thread_started',
-    'class'   => 'privatemsg-header-threadstarted',
-    '#weight' => -15,
-  );
-}
-
-/**
  * Theme to display the privatemsg list.
  *
  * This theme builds a table with paging based on the data which has been built
@@ -241,14 +115,8 @@ function theme_privatemsg_list($form) {
 
   drupal_add_css(drupal_get_path('module', 'privatemsg') .'/styles/privatemsg-list.css');
 
-  // Load the table columns.
-  $columns = array_merge(array('subject', 'last_updated'), array_filter(variable_get('privatemsg_display_fields', array('participants'))));
-
-  // Load the themed list headers based on the available data.
-  $headers = _privatemsg_list_headers(!empty($form['#data']), $columns);
-  // sort the headers array based on the #weight property.
-  usort($headers, 'element_sort');
-
+  // Get the headers.
+  $headers = privatemsg_get_headers(TRUE);
   $themed_rows = array();
   // Check if there is atleast a single thread.
   if ($has_posts) {
@@ -259,22 +127,17 @@ function theme_privatemsg_list($form) {
       // Render the checkbox.
       $data[] = array('data' => drupal_render($form['threads'][$thread_id]), 'class' => 'privatemsg-list-select');
 
-      // Store the #rows data in the same order as the header is, the key property of the header refers to the field that belongs to it.
-      foreach ($headers as $header) {
-        if (!empty($header['key'])) {
-          if (isset($row['data'][$header['key']])) {
-            $data[] = $row['data'][$header['key']];
-          }
-          else {
-            // Store a empty value so that the order is still correct.
-            $data[] = '';
-          }
-        }
+      // Store the #rows data in the same order as the header is,
+      // the key property of the header refers to the field that belongs to it.
+      foreach ($headers as $key => $header) {
+        $data[] = isset($row['data'][$key]) ? $row['data'][$key] : '';
       }
       // Replace the data
       $row['data'] = $data;
       $themed_rows[] = $row;
     }
+    // Add select all checkox to header array.
+    array_unshift($headers, theme('table_select_header_cell'));
   }
   else {
     // Display a message if now messages are available.
@@ -330,5 +193,45 @@ function theme_privatemsg_username($recipient, $options) {
 }
 
 /**
+ * Output the admin settings display fields and weight settings as a
+ * drag and drop sortable table.
+ */
+function theme_privatemsg_admin_settings_display_fields($element = array()) {
+  $header = array(
+    array('data' => t('Field'), 'class' => 'field'),
+    array('data' => t('Enable'), 'class' => 'enable'),
+    array('data' => t('Weight'), 'class' => 'weight'),
+  );
+  $rows = array();
+  foreach (element_children($element['privatemsg_display_fields']) as $child) {
+    $row = array();
+
+    // Title.
+    $row[] = array('data' => $element['privatemsg_display_fields'][$child]['#title'], 'class' => 'field');
+    unset($element['privatemsg_display_fields'][$child]['#title']);
+
+    // Enable checkbox.
+    $row[] = array('data' => drupal_render($element['privatemsg_display_fields'][$child]), 'class' => 'enable');
+
+    // Weight selector.
+    unset($element['privatemsg_display_fields_weights'][$child]['#title']);
+    $element['privatemsg_display_fields_weights'][$child]['#attributes']['class'] = 'privatemsg-display-fields-weight';
+    $row[] = array(
+      'data' => drupal_render($element['privatemsg_display_fields_weights'][$child]),
+      'class' => 'weight',
+    );
+
+    $rows[] = array('data' => $row, 'class' => 'draggable');
+  }
+  if (!empty($rows)) {
+    drupal_add_tabledrag('privatemsg-list-display-fields', 'order', 'sibling', 'privatemsg-display-fields-weight');
+    return theme('table', $header, $rows, array('id' => 'privatemsg-list-display-fields')) . drupal_render($element);
+  }
+  else {
+    return drupal_render($element);
+  }
+}
+
+/**
  * @}
  */
diff --git a/privatemsg_attachments/privatemsg_attachments.module b/privatemsg_attachments/privatemsg_attachments.module
index 7d82e9e..51bda0f 100644
--- a/privatemsg_attachments/privatemsg_attachments.module
+++ b/privatemsg_attachments/privatemsg_attachments.module
@@ -106,9 +106,6 @@ function privatemsg_attachments_form_privatemsg_admin_settings_alter(&$form, &$f
 	'#description' => t("Relative path, based on Drupal's configured file attachments path, where private message attachments will be stored."),
     '#weight' => -4,
   );
-
-  // Add tags to the list of possible columns.
-  $form['privatemsg_listing']['privatemsg_display_fields']['#options']['attachment'] = t('Attachment icon');
 }
 
 function _privatemsg_attachments_form($files = array()) {
@@ -388,17 +385,18 @@ function privatemsg_attachments_sql_count(&$fragments, $threads) {
 }
 
 /**
- * Define the header for the attachment column.
- *
- * @see theme_privatemsg_list_header()
+ * Implements hook_privatemsg_header_info().
  */
-function phptemplate_privatemsg_list_header__attachment() {
-   return array(
-    'data' => '&nbsp;',
-    'key' => 'attachment',
-    'class' => 'privatemsg-header-attachment',
-    '#weight' => 0,
+function privatemsg_attachments_privatemsg_header_info() {
+  $a = array(
+    'attachment' => array(
+      'data' => '&nbsp;',
+      'class' => 'privatemsg-header-attachment',
+      '#title' => t('Attachment icon'),
+      '#weight' => -25,
+    ),
   );
+  return $a;
 }
 
 /**
diff --git a/privatemsg_filter/privatemsg_filter.module b/privatemsg_filter/privatemsg_filter.module
index 083aa2f..652acf2 100644
--- a/privatemsg_filter/privatemsg_filter.module
+++ b/privatemsg_filter/privatemsg_filter.module
@@ -154,8 +154,6 @@ function privatemsg_filter_form_privatemsg_admin_settings_alter(&$form, $form_st
     '#title' => t('Choose the default list option'),
     '#description' => t('Choose which of the two lists are shown by default when following the messages link.'),
   );
-  // Add tags to the list of possible columns.
-  $form['privatemsg_listing']['privatemsg_display_fields']['#options']['tags'] = t('Tags');
 
   $form['#submit'][] = 'privatemsg_filter_settings_submit';
 }
@@ -512,7 +510,7 @@ function privatemsg_filter_form_privatemsg_list_alter(&$form, $form_state) {
     $form += privatemsg_filter_dropdown($form_state, $form['#account']);
   }
 
-  $fields = array_filter(variable_get('privatemsg_display_fields', array('participants')));
+  $fields = privatemsg_get_enabled_headers();
   if (privatemsg_user_access('tag private messages') && in_array('tags', $fields) && !empty($form['#data'])) {
     // Load thread id's of the current list.
     $threads = array_keys($form['#data']);
@@ -585,19 +583,17 @@ function privatemsg_filter_privatemsg_thread_operations($type) {
 }
 
 /**
- * Define the header for the tags column.
- *
- * @see theme_privatemsg_list_header()
+ * Implements hook_privatemsg_header_info().
  */
-function phptemplate_privatemsg_list_header__tags() {
-  if (privatemsg_user_access('tag private messages')) {
-    return array(
+function privatemsg_filter_privatemsg_header_info() {
+  return array(
+    'tags' => array(
       'data' => t('Tags'),
-      'key' => 'tags',
       'class' => 'privatemsg-header-tags',
-      '#weight' => -42,
-    );
-  }
+      '#weight' => -23,
+      '#access' => privatemsg_user_access('tag private messages'),
+    ),
+  );
 }
 
 /**
