diff --git a/flag.inc b/flag.inc
index 3c34917..7886c83 100644
--- a/flag.inc
+++ b/flag.inc
@@ -193,6 +193,7 @@ class flag_flag {
         'flag' => array(DRUPAL_AUTHENTICATED_RID),
         'unflag' => array(DRUPAL_AUTHENTICATED_RID),
       ),
+      'weight' => 0,
     );
 
     // Merge in options from the current link type.
@@ -1828,4 +1829,3 @@ class FlagNonGlobalCookieStorage extends FlagCookieStorage {
     }
   }
 }
-
diff --git a/flag.module b/flag.module
index 4660912..d971a9a 100644
--- a/flag.module
+++ b/flag.module
@@ -1121,10 +1121,18 @@ function flag_theme() {
       'variables' => array('types' => array('all'), 'global_types' => TRUE),
       'file' => 'flag.tokens.inc',
     ),
-    'flag_admin_page' => array(
+    'flag_admin_listing' => array(
+      'render element' => 'form',
+      'file' => 'includes/flag.admin.inc',
+    ),
+    'flag_admin_listing_disabled' => array(
       'variables' => array('flags' => NULL, 'default_flags' => NULL),
       'file' => 'includes/flag.admin.inc',
     ),
+    'flag_admin_page' => array(
+      'variables' => array('flags' => NULL, 'default_flags' => NULL, 'flag_admin_listing' => NULL),
+      'file' => 'includes/flag.admin.inc',
+    ),
     'flag_form_roles' => array(
       'render element' => 'element',
       'file' => 'includes/flag.admin.inc',
@@ -1420,6 +1428,9 @@ function flag_get_flags($content_type = NULL, $content_subtype = NULL, $account
       }
     }
 
+    // Sort the list of flags by weight.
+    uasort($flags, '_flag_compare_weight');
+
     // Allow modules implementing hook_flag_alter(&$flag) to modify each flag.
     foreach ($flags as $flag) {
       drupal_alter('flag', $flag);
@@ -1453,6 +1464,16 @@ function flag_get_flags($content_type = NULL, $content_subtype = NULL, $account
 }
 
 /**
+ * Comparison function for uasort().
+ */
+function _flag_compare_weight($flag1, $flag2) {
+  if ($flag1->weight == $flag2->weight) {
+    return 0;
+  }
+  return $flag1->weight < $flag2->weight ? -1 : 1;
+}
+
+/**
  * Utility function: Checks whether a flag applies to a certain type, and
  * possibly subtype, of content.
  *
diff --git a/includes/flag.admin.inc b/includes/flag.admin.inc
index e44224b..27543a4 100644
--- a/includes/flag.admin.inc
+++ b/includes/flag.admin.inc
@@ -11,18 +11,59 @@
 function flag_admin_page() {
   $flags = flag_get_flags();
   $default_flags = flag_get_default_flags(TRUE);
-  return theme('flag_admin_page', array('flags' => $flags, 'default_flags' => $default_flags));
+  $flag_admin_listing = drupal_get_form('flag_admin_listing', $flags);
+  return theme('flag_admin_page', array('flags' => $flags, 'default_flags' => $default_flags, 'flag_admin_listing' => $flag_admin_listing));
 }
 
 /**
- * Theme the output for the main flag administration page.
+ * A form for ordering the weights of all the active flags in the system.
  */
-function theme_flag_admin_page($variables) {
-  $flags = $variables['flags'];
-  $default_flags = $variables['default_flags'];
+function flag_admin_listing($form, &$form_state, $flags) {
+  $form['#flags'] = $flags;
+  $form['#tree'] = TRUE;
+
+  foreach ($flags as $flag) {
+    $form['flags'][$flag->name]['weight'] = array(
+      '#type' => 'weight',
+      '#delta' => count($flags) + 5,
+      '#default_value' => $flag->weight,
+      '#attributes' => array('class' => array('flag-weight')),
+    );
+  }
+
+  $form['actions'] = array(
+    '#type' => 'actions',
+  );
+
+  $form['actions']['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Save flag order'),
+  );
+
+  return $form;
+}
+
+/**
+ * Submit handler for the flag_admin_listing form. Save flag weight ordering.
+ */
+function flag_admin_listing_submit($form, &$form_state) {
+  foreach ($form['#flags'] as $flag) {
+    if ($flag->weight != $form_state['values']['flags'][$flag->name]['weight']) {
+      $flag->weight = $form_state['values']['flags'][$flag->name]['weight'];
+      $flag->save();
+    }
+  }
+}
+
+/**
+ * Theme the output of the normal, database flags into a table.
+ */
+function theme_flag_admin_listing($variables) {
+  $form = $variables['form'];
+  $flags = $form['#flags'];
+
   $output = '';
 
-  // Build out the list of normal, database flags.
   foreach ($flags as $flag) {
     $ops = array(
       'flags_edit' =>  array('title' => t('edit'), 'href' => $flag->admin_path('edit')),
@@ -31,23 +72,43 @@ function theme_flag_admin_page($variables) {
     );
 
     $roles = array_flip(array_intersect(array_flip(user_roles()), $flag->roles['flag']));
-    $rows[] = array(
+    $row = array(
       $flag->name,
+      drupal_render($form['flags'][$flag->name]['weight']),
       $flag->content_type,
       empty($flag->roles['flag']) ? '<em>' . t('No roles') . '</em>' : implode(', ', $roles),
       $flag->types ? implode(', ', $flag->types) : '-',
       $flag->global ? t('Yes') : t('No'),
       theme('links', array('links' => $ops)),
     );
+    $rows[] = array(
+      'data' => $row,
+      'class' => array('draggable'),
+    );
   }
   if (!$flags) {
     $rows[] = array(
-      array('data' => t('No flags are currently defined.'), 'colspan' => 6),
+      array('data' => t('No flags are currently defined.'), 'colspan' => 7),
     );
   }
+  else {
+    drupal_add_tabledrag('flag-admin-listing-table', 'order', 'sibling', 'flag-weight');
+  }
 
-  $header = array(t('Flag'), t('Flag type'), t('Roles'), t('Node types'), t('Global?'), t('Operations'));
-  $output .= theme('table', array('header' => $header, 'rows' => $rows));
+  $header = array(t('Flag'),t('Weight'), t('Flag type'), t('Roles'), t('Node types'), t('Global?'), t('Operations'));
+  $output .= theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('id' => 'flag-admin-listing-table')));
+  $output .= drupal_render_children($form);
+
+  return $output;
+}
+
+/**
+ * Theme the list of disabled flags into a table.
+ */
+function theme_flag_admin_listing_disabled($variables) {
+  $flags = $variables['flags'];
+  $default_flags = $variables['default_flags'];
+  $output = '';
 
   // Build a list of disabled, module-based flags.
   $rows = array();
@@ -81,6 +142,21 @@ function theme_flag_admin_page($variables) {
     $output .= theme('table', array('header' => $header, 'rows' => $rows));
   }
 
+  return $output;
+}
+
+/**
+ * Theme the output for the main flag administration page.
+ */
+function theme_flag_admin_page($variables) {
+  $flags = $variables['flags'];
+  $default_flags = $variables['default_flags'];
+
+  $output = '';
+
+  $output .= drupal_render($variables['flag_admin_listing']);
+  $output .= theme('flag_admin_listing_disabled', array('flags' => $flags, 'default_flags' => $default_flags));
+
   if (!module_exists('views')) {
     $output .= '<p>' . t('The <a href="@views-url">Views</a> module is not installed, or not enabled. It is recommended that you install the Views module to be able to easily produce lists of flagged content.', array('@views-url' => url('http://drupal.org/project/views'))) . '</p>';
   }
@@ -154,9 +230,13 @@ function flag_add_form($form, &$form_state) {
     '#options' => $types,
   );
 
-  $form['submit'] = array(
+  $form['actions'] = array(
+    '#type' => 'actions',
+  );
+
+  $form['actions']['submit'] = array(
     '#type' => 'submit',
-    '#value' => t('Submit'),
+    '#value' => t('Add flag'),
   );
 
   return $form;
@@ -416,9 +496,13 @@ function flag_form($form, &$form_state, $flag) {
     '#access' => empty($flag->locked['unflag_confirmation']),
   );
 
-  $form['submit'] = array(
+  $form['actions'] = array(
+    '#type' => 'actions',
+  );
+
+  $form['actions']['submit'] = array(
     '#type' => 'submit',
-    '#value' => t('Submit'),
+    '#value' => t('Save flag'),
     // We put this button on the form before calling $flag->options_form()
     // to give the flag handler a chance to remove it (e.g. flag_broken).
     '#weight' => 999,
