diff --git a/election.views.inc b/election.views.inc
index 6bd7698..b81692a 100644
--- a/election.views.inc
+++ b/election.views.inc
@@ -261,10 +261,32 @@ function election_views_data() {
     ),
   );
 
+  $data['election']['uid'] = array(
+    'title' => t('Author UID'),
+    'help' => t('The UID of the user who created the election.'),
+    'relationship' => array(
+      'title' => t('Author'),
+      'help' => t('Relate elections to the users who created them.'),
+      'handler' => 'views_handler_relationship',
+      'base' => 'users',
+      'field' => 'uid',
+      'label' => t('author'),
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_user_name',
+    ),
+    'argument' => array(
+      'handler' => 'views_handler_argument_numeric',
+    ),
+    'field' => array(
+      'handler' => 'views_handler_field_user',
+    ),
+  );
+
   $data['election']['view_election'] = array(
     'field' => array(
       'title' => t('Link'),
-      'help' => t('Provide a simple link to the election.'),
+      'help' => t('A link to the election.'),
       'handler' => 'views_handler_field_election_link',
     ),
   );
@@ -272,7 +294,7 @@ function election_views_data() {
   $data['election']['edit_election'] = array(
     'field' => array(
       'title' => t('Edit link'),
-      'help' => t('Provide a simple link to edit the election.'),
+      'help' => t('A link to edit the election.'),
       'handler' => 'views_handler_field_election_link_edit',
     ),
   );
@@ -280,7 +302,7 @@ function election_views_data() {
   $data['election']['delete_election'] = array(
     'field' => array(
       'title' => t('Delete link'),
-      'help' => t('Provide a simple link to delete the election.'),
+      'help' => t('A link to delete the election.'),
       'handler' => 'views_handler_field_election_link_delete',
     ),
   );
diff --git a/election_candidate/election-candidate.admin.inc b/election_candidate/election-candidate.admin.inc
index d0da3ae..6d697b8 100644
--- a/election_candidate/election-candidate.admin.inc
+++ b/election_candidate/election-candidate.admin.inc
@@ -6,123 +6,20 @@
  */
 
 /**
- * Form builder function for the main administrative election candidate list.
+ * Page callback for managing election candidates.
  */
-function election_candidate_manage_form($form, $form_state, stdClass $election) {
-
+function election_candidate_manage_page(stdClass $election) {
   drupal_set_title(t('Manage candidates'), PASS_THROUGH);
-  drupal_set_breadcrumb(
-    _election_build_breadcrumb($election)
-  );
-
-  $post_name = election_get_post_name($election->type);
-
-  // Build the sortable table header.
-  $header = array(
-    'created' => array('data' => t('Nominated'), 'field' => 'ec.created', 'sort' => 'desc'),
-    'post_title' => array('data' => drupal_ucfirst($post_name), 'field' => 'ep.title'),
-    'first_name' => array('data' => t('First name'), 'field' => 'ec.first_name'),
-    'last_name' => array('data' => t('Last name'), 'field' => 'ec.last_name'),
-    'username' => array('data' => t('Username'), 'field' => 'ec.username'),
-    'cstatus' => array('data' => t('Status'), 'field' => 'ec.cstatus'),
-    'published' => array('data' => t('Published'), 'field' => 'ec.published'),
-    'operations' => array('data' => t('Operations')),
-  );
-
-  // Build the query, adding a pager and sorter.
-  $query = db_select('election_candidate', 'ec')
-    ->extend('PagerDefault')
-    ->extend('TableSort')
-    ->fields('ec', array('candidate_id'));
-  $query->leftJoin('election_post', 'ep', 'ec.post_id=ep.post_id');
-  $query->condition('ec.election_id', $election->election_id)
-    ->limit(50)
-    ->orderByHeader($header);
-  $result = $query->execute();
-
-  // Get array of candidates.
-  $candidate_ids = $result->fetchCol();
-  $candidates = election_candidate_load_multiple($candidate_ids);
-
-  $destination = drupal_get_destination();
-
-  $default_post_title = '<em class="deleted-post">' . t('Deleted?') . '</em>';
-
-  $options = array();
-  foreach ($candidates as $id => $candidate) {
-
-    $post_title = $default_post_title;
-    if (!empty($candidate->post_id) && ($post = election_post_load($candidate->post_id))) {
-      $post_title = check_plain($post->title);
-    }
-
-    $account = user_load($candidate->uid);
-
-    $options[$candidate->candidate_id] = array(
-      'created' => format_date($candidate->created, 'short'),
-      'post_title' => truncate_utf8($post_title, 40, TRUE, TRUE),
-      'first_name' => check_plain($candidate->first_name),
-      'last_name' => check_plain($candidate->last_name),
-      'username' => $account ? theme('username', array('account' => $account)) : t('Anonymous'),
-      'cstatus' => theme('election_candidate_status', array('candidate' => $candidate)),
-      'published' => $candidate->published ? t('Yes') : t('No'),
-    );
-
-    $operations = array();
-    $candidate_uri_path = election_candidate_uri_path($candidate);
-
-    if (election_candidate_access('view', $candidate)) {
-      $operations['view'] = l(
-        t('view'),
-        $candidate_uri_path
-      );
-    }
-
-    if (election_candidate_access('view details', $candidate)) {
-      $operations['view_details'] = l(
-        t('details'),
-        $candidate_uri_path . '/details'
-      );
-    }
-
-    if (election_candidate_access('update', $candidate)) {
-      $operations['edit'] = l(
-        t('edit'),
-        $candidate_uri_path . '/edit',
-        array('query' => $destination)
-      );
-    }
-
-    if (count($operations)) {
-      // Render an unordered list of operations links.
-      $options[$candidate->candidate_id]['operations'] = array(
-        'data' => array(
-          '#theme' => 'item_list',
-          '#items' => $operations,
-          '#attributes' => array('class' => array('operations')),
-        ),
-      );
-    }
-
-  }
-
-  $form['election_candidates'] = array(
-    '#theme' => 'table',
-    '#header' => $header,
-    '#rows' => $options,
-    '#empty' => t('No candidates available.'),
-  );
-
-  $form['pager'] = array('#markup' => theme('pager'));
-
-  return $form;
+  drupal_set_breadcrumb(_election_build_breadcrumb($election));
+  return views_embed_view('election_candidates_admin', 'embed', $election->election_id);
 }
 
 /**
- * Display total numbers of candidates per post.
+ * Page callback to display total numbers of candidates per post.
  */
 function election_candidate_totals_page(stdClass $election) {
 
+  drupal_set_title(t('Candidate totals'), PASS_THROUGH);
   drupal_set_breadcrumb(_election_build_breadcrumb($election));
 
   $totals = db_query("SELECT IFNULL(cstatus, 'all') AS cstatus, COUNT(DISTINCT candidate_id) FROM {election_candidate} WHERE election_id = :eid GROUP BY cstatus WITH ROLLUP", array(':eid' => $election->election_id))->fetchAllKeyed();
diff --git a/election_candidate/election-candidate.download.inc b/election_candidate/election-candidate.download.inc
index 20d5dab..09c6daa 100644
--- a/election_candidate/election-candidate.download.inc
+++ b/election_candidate/election-candidate.download.inc
@@ -9,6 +9,7 @@
  */
 function election_candidate_download_form($form, &$form_state, stdClass $election) {
 
+  drupal_set_title(t('Download candidates'), PASS_THROUGH);
   drupal_set_breadcrumb(_election_build_breadcrumb($election));
 
   $candidate_field_instances = field_info_instances('election_candidate');
diff --git a/election_candidate/election_candidate.info b/election_candidate/election_candidate.info
index e831ea2..e8cf5c0 100644
--- a/election_candidate/election_candidate.info
+++ b/election_candidate/election_candidate.info
@@ -10,6 +10,7 @@ files[] = election-candidate.controller.inc
 files[] = election-candidate-type.controller.inc
 files[] = election-candidate-type-ui.controller.inc
 files[] = views/handlers/views_handler_field_election_candidate_link.inc
+files[] = views/handlers/views_handler_field_election_candidate_link_edit.inc
 files[] = views/handlers/views_handler_field_election_candidate_link_nominate.inc
 files[] = views/handlers/views_handler_field_election_candidate_fullname.inc
 files[] = views/handlers/views_handler_field_election_candidate_cstatus.inc
diff --git a/election_candidate/election_candidate.module b/election_candidate/election_candidate.module
index fb2b895..f168093 100644
--- a/election_candidate/election_candidate.module
+++ b/election_candidate/election_candidate.module
@@ -259,8 +259,8 @@ function election_candidate_menu() {
 
   $items['election/%election/candidates-admin'] = array(
     'title' => 'Manage candidates',
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('election_candidate_manage_form', 1),
+    'page callback' => 'election_candidate_manage_page',
+    'page arguments' => array(1),
     'access callback' => 'election_candidate_access_per_election',
     'access arguments' => array('edit', 1),
     'file' => 'election-candidate.admin.inc',
@@ -884,7 +884,7 @@ function election_candidate_view($candidate, $view_mode = 'full') {
 
   // Remove previously built content, if it exists.
   $candidate->content = array();
-  
+
   // Display a link to the election.
   $candidate->content['election'] = array(
     '#theme' => 'election_info_item',
@@ -900,7 +900,7 @@ function election_candidate_view($candidate, $view_mode = 'full') {
     '#value' => l($post->title, election_post_uri_path($post)),
     '#html' => TRUE,
   );
-  
+
   // Display the candidate's status.
   $candidate->content['status'] = array(
     '#theme' => 'election_info_item',
@@ -1220,6 +1220,13 @@ function election_candidate_action_info() {
       'behavior' => array('changes_property'),
       'triggers' => array('election_candidate_presave'),
     ),
+    'election_candidate_unpublish_action' => array(
+      'type' => 'election_candidate',
+      'label' => t('Unpublish candidate'),
+      'configurable' => FALSE,
+      'behavior' => array('changes_property'),
+      'triggers' => array('election_candidate_presave'),
+    ),
   );
 }
 
@@ -1233,6 +1240,15 @@ function election_candidate_publish_action($candidate, $context = array()) {
 }
 
 /**
+ * Unpublishes a candidate.
+ *
+ * @ingroup actions
+ */
+function election_candidate_unpublish_action($candidate, $context = array()) {
+  $candidate->published = 0;
+}
+
+/**
  * Check whether an election type supports candidates.
  */
 function election_candidate_check_support(stdClass $election) {
diff --git a/election_candidate/election_candidate.views.inc b/election_candidate/election_candidate.views.inc
index 6ab544b..c9e0b7d 100644
--- a/election_candidate/election_candidate.views.inc
+++ b/election_candidate/election_candidate.views.inc
@@ -88,6 +88,28 @@ function election_candidate_views_data() {
     ),
   );
 
+  $data['election_candidate']['uid'] = array(
+    'title' => t('User UID'),
+    'help' => t('The UID of the user associated with the candidate.'),
+    'relationship' => array(
+      'title' => t('User'),
+      'help' => t('Relate candidates to users.'),
+      'handler' => 'views_handler_relationship',
+      'base' => 'users',
+      'field' => 'uid',
+      'label' => t('user'),
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_user_name',
+    ),
+    'argument' => array(
+      'handler' => 'views_handler_argument_numeric',
+    ),
+    'field' => array(
+      'handler' => 'views_handler_field_user',
+    ),
+  );
+
   $data['election_candidate']['fullname'] = array(
     'title' => t('Name'),
     'help' => t('The full name of the candidate ($Firstname $Lastname).'),
@@ -97,6 +119,64 @@ function election_candidate_views_data() {
     ),
   );
 
+  $data['election_candidate']['first_name'] = array(
+    'title' => t('First name'),
+    'help' => t('The first name(s) of the candidate.'),
+    'field' => array(
+      'click sortable' => TRUE,
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_string',
+    ),
+    'sort' => array(
+      'handler' => 'views_handler_sort',
+    ),
+  );
+
+  $data['election_candidate']['last_name'] = array(
+    'title' => t('Last name'),
+    'help' => t('The last name(s) of the candidate.'),
+    'field' => array(
+      'click sortable' => TRUE,
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_string',
+    ),
+    'sort' => array(
+      'handler' => 'views_handler_sort',
+    ),
+  );
+
+  $data['election_candidate']['created'] = array(
+    'title' => t('Created date'),
+    'help' => t('The date when the candidate was created (or nomination date).'),
+    'field' => array(
+      'handler' => 'views_handler_field_date',
+      'click sortable' => TRUE,
+    ),
+    'sort' => array(
+      'handler' => 'views_handler_sort_date',
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_date',
+    ),
+  );
+
+  $data['election_candidate']['changed'] = array(
+    'title' => t('Updated date'),
+    'help' => t('The date when the candidate was last updated.'),
+    'field' => array(
+      'handler' => 'views_handler_field_date',
+      'click sortable' => TRUE,
+    ),
+    'sort' => array(
+      'handler' => 'views_handler_sort_date',
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_date',
+    ),
+  );
+
   $data['election_candidate']['view_link'] = array(
     'field' => array(
       'title' => t('Profile link'),
@@ -105,6 +185,14 @@ function election_candidate_views_data() {
     ),
   );
 
+  $data['election_candidate']['edit_link'] = array(
+    'field' => array(
+      'title' => t('Edit link'),
+      'help' => t('A link to edit the candidate.'),
+      'handler' => 'views_handler_field_election_candidate_link_edit',
+    ),
+  );
+
   $data['election_post']['nominate_link'] = array(
     'field' => array(
       'title' => t('Nomination form link'),
diff --git a/election_candidate/views/election-candidates-admin.inc b/election_candidate/views/election-candidates-admin.inc
new file mode 100644
index 0000000..bfb194a
--- /dev/null
+++ b/election_candidate/views/election-candidates-admin.inc
@@ -0,0 +1,193 @@
+<?php
+/**
+ * @file
+ * View listing candidates in an election, for administrative use.
+ */
+
+$view = new view();
+$view->name = 'election_candidates_admin';
+$view->description = 'An administrative list of election candidates.';
+$view->tag = 'election';
+$view->base_table = 'election_candidate';
+$view->human_name = 'Election candidates admin';
+$view->core = 7;
+$view->api_version = '3.0';
+$view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */
+
+/* Display: Master */
+$handler = $view->new_display('default', 'Master', 'default');
+$handler->display->display_options['title'] = 'Manage candidates';
+$handler->display->display_options['use_more_always'] = FALSE;
+$handler->display->display_options['access']['type'] = 'perm';
+$handler->display->display_options['access']['perm'] = 'view published elections';
+$handler->display->display_options['cache']['type'] = 'none';
+$handler->display->display_options['query']['type'] = 'views_query';
+$handler->display->display_options['query']['options']['distinct'] = TRUE;
+$handler->display->display_options['query']['options']['slave'] = TRUE;
+$handler->display->display_options['query']['options']['query_comment'] = FALSE;
+$handler->display->display_options['exposed_form']['type'] = 'basic';
+$handler->display->display_options['pager']['type'] = 'full';
+$handler->display->display_options['pager']['options']['items_per_page'] = '50';
+$handler->display->display_options['pager']['options']['offset'] = '0';
+$handler->display->display_options['pager']['options']['id'] = '0';
+$handler->display->display_options['style_plugin'] = 'table';
+$handler->display->display_options['style_options']['columns'] = array(
+  'views_bulk_operations' => 'views_bulk_operations',
+  'created' => 'created',
+  'title' => 'title',
+  'first_name' => 'first_name',
+  'last_name' => 'last_name',
+  'name' => 'name',
+  'cstatus' => 'cstatus',
+  'published' => 'published',
+  'view_link' => 'view_link',
+  'edit_link' => 'view_link',
+);
+$handler->display->display_options['style_options']['default'] = 'created';
+$handler->display->display_options['style_options']['info'] = array(
+  'views_bulk_operations' => array(
+    'align' => '',
+    'separator' => '',
+    'empty_column' => 0,
+  ),
+  'created' => array(
+    'sortable' => 1,
+    'default_sort_order' => 'desc',
+    'align' => '',
+    'separator' => '',
+    'empty_column' => 0,
+  ),
+  'title' => array(
+    'sortable' => 1,
+    'default_sort_order' => 'asc',
+    'align' => '',
+    'separator' => '',
+    'empty_column' => 0,
+  ),
+  'first_name' => array(
+    'sortable' => 1,
+    'default_sort_order' => 'asc',
+    'align' => '',
+    'separator' => '',
+    'empty_column' => 0,
+  ),
+  'last_name' => array(
+    'sortable' => 1,
+    'default_sort_order' => 'asc',
+    'align' => '',
+    'separator' => '',
+    'empty_column' => 0,
+  ),
+  'name' => array(
+    'sortable' => 1,
+    'default_sort_order' => 'asc',
+    'align' => '',
+    'separator' => '',
+    'empty_column' => 0,
+  ),
+  'cstatus' => array(
+    'align' => '',
+    'separator' => '',
+    'empty_column' => 0,
+  ),
+  'published' => array(
+    'sortable' => 1,
+    'default_sort_order' => 'asc',
+    'align' => '',
+    'separator' => '',
+    'empty_column' => 0,
+  ),
+  'view_link' => array(
+    'align' => 'views-align-center',
+    'separator' => ' &middot; ',
+    'empty_column' => 0,
+  ),
+  'edit_link' => array(
+    'align' => '',
+    'separator' => '',
+    'empty_column' => 0,
+  ),
+);
+$handler->display->display_options['style_options']['empty_table'] = TRUE;
+/* No results behavior: Global: Text area */
+$handler->display->display_options['empty']['area']['id'] = 'area';
+$handler->display->display_options['empty']['area']['table'] = 'views';
+$handler->display->display_options['empty']['area']['field'] = 'area';
+$handler->display->display_options['empty']['area']['label'] = 'No candidates found';
+$handler->display->display_options['empty']['area']['empty'] = TRUE;
+$handler->display->display_options['empty']['area']['content'] = 'No candidates found.';
+$handler->display->display_options['empty']['area']['format'] = 'filtered_html';
+/* Relationship: Election candidate: User */
+$handler->display->display_options['relationships']['uid']['id'] = 'uid';
+$handler->display->display_options['relationships']['uid']['table'] = 'election_candidate';
+$handler->display->display_options['relationships']['uid']['field'] = 'uid';
+/* Field: Election candidate: Created date */
+$handler->display->display_options['fields']['created']['id'] = 'created';
+$handler->display->display_options['fields']['created']['table'] = 'election_candidate';
+$handler->display->display_options['fields']['created']['field'] = 'created';
+$handler->display->display_options['fields']['created']['label'] = 'Nominated';
+$handler->display->display_options['fields']['created']['date_format'] = 'short';
+/* Field: Election post: Title */
+$handler->display->display_options['fields']['title']['id'] = 'title';
+$handler->display->display_options['fields']['title']['table'] = 'election_post';
+$handler->display->display_options['fields']['title']['field'] = 'title';
+$handler->display->display_options['fields']['title']['label'] = 'Position';
+$handler->display->display_options['fields']['title']['alter']['max_length'] = '30';
+$handler->display->display_options['fields']['title']['alter']['trim'] = TRUE;
+$handler->display->display_options['fields']['title']['link_to_post'] = 0;
+/* Field: Election candidate: First name */
+$handler->display->display_options['fields']['first_name']['id'] = 'first_name';
+$handler->display->display_options['fields']['first_name']['table'] = 'election_candidate';
+$handler->display->display_options['fields']['first_name']['field'] = 'first_name';
+/* Field: Election candidate: Last name */
+$handler->display->display_options['fields']['last_name']['id'] = 'last_name';
+$handler->display->display_options['fields']['last_name']['table'] = 'election_candidate';
+$handler->display->display_options['fields']['last_name']['field'] = 'last_name';
+/* Field: User: Name */
+$handler->display->display_options['fields']['name']['id'] = 'name';
+$handler->display->display_options['fields']['name']['table'] = 'users';
+$handler->display->display_options['fields']['name']['field'] = 'name';
+$handler->display->display_options['fields']['name']['relationship'] = 'uid';
+$handler->display->display_options['fields']['name']['label'] = 'User';
+/* Field: Election candidate: Status */
+$handler->display->display_options['fields']['cstatus']['id'] = 'cstatus';
+$handler->display->display_options['fields']['cstatus']['table'] = 'election_candidate';
+$handler->display->display_options['fields']['cstatus']['field'] = 'cstatus';
+/* Field: Election candidate: Published */
+$handler->display->display_options['fields']['published']['id'] = 'published';
+$handler->display->display_options['fields']['published']['table'] = 'election_candidate';
+$handler->display->display_options['fields']['published']['field'] = 'published';
+$handler->display->display_options['fields']['published']['not'] = 0;
+/* Field: Election candidate: Profile link */
+$handler->display->display_options['fields']['view_link']['id'] = 'view_link';
+$handler->display->display_options['fields']['view_link']['table'] = 'election_candidate';
+$handler->display->display_options['fields']['view_link']['field'] = 'view_link';
+$handler->display->display_options['fields']['view_link']['label'] = 'Actions';
+$handler->display->display_options['fields']['view_link']['text'] = 'view';
+/* Field: Election candidate: Edit link */
+$handler->display->display_options['fields']['edit_link']['id'] = 'edit_link';
+$handler->display->display_options['fields']['edit_link']['table'] = 'election_candidate';
+$handler->display->display_options['fields']['edit_link']['field'] = 'edit_link';
+$handler->display->display_options['fields']['edit_link']['text'] = 'edit';
+/* Contextual filter: Election: Election ID */
+$handler->display->display_options['arguments']['election_id']['id'] = 'election_id';
+$handler->display->display_options['arguments']['election_id']['table'] = 'election';
+$handler->display->display_options['arguments']['election_id']['field'] = 'election_id';
+$handler->display->display_options['arguments']['election_id']['default_argument_type'] = 'fixed';
+$handler->display->display_options['arguments']['election_id']['summary']['number_of_records'] = '0';
+$handler->display->display_options['arguments']['election_id']['summary']['format'] = 'default_summary';
+$handler->display->display_options['arguments']['election_id']['summary_options']['items_per_page'] = '25';
+$handler->display->display_options['arguments']['election_id']['specify_validation'] = TRUE;
+$handler->display->display_options['arguments']['election_id']['validate']['type'] = 'numeric';
+$handler->display->display_options['arguments']['election_id']['validate']['fail'] = 'empty';
+/* Filter criterion: Election: Published or admin */
+$handler->display->display_options['filters']['published_or_admin']['id'] = 'published_or_admin';
+$handler->display->display_options['filters']['published_or_admin']['table'] = 'election';
+$handler->display->display_options['filters']['published_or_admin']['field'] = 'published_or_admin';
+$handler->display->display_options['filters']['published_or_admin']['group'] = 1;
+
+/* Display: Embed */
+$handler = $view->new_display('embed', 'Embed', 'embed');
+$handler->display->display_options['defaults']['hide_admin_links'] = FALSE;
+
+$views[$view->name] = $view;
diff --git a/election_candidate/views/election-candidates.inc b/election_candidate/views/election-candidates.inc
index 25e0261..7247cba 100644
--- a/election_candidate/views/election-candidates.inc
+++ b/election_candidate/views/election-candidates.inc
@@ -7,7 +7,7 @@
 $view = new view();
 $view->name = 'election_candidates';
 $view->description = 'A list of candidates (intended for the public / all viewers of the election).';
-$view->tag = 'default';
+$view->tag = 'election';
 $view->base_table = 'election_candidate';
 $view->human_name = 'Election candidates';
 $view->core = 7;
diff --git a/election_candidate/views/handlers/views_handler_field_election_candidate_link_edit.inc b/election_candidate/views/handlers/views_handler_field_election_candidate_link_edit.inc
new file mode 100644
index 0000000..a151722
--- /dev/null
+++ b/election_candidate/views/handlers/views_handler_field_election_candidate_link_edit.inc
@@ -0,0 +1,39 @@
+<?php
+/**
+ * @file
+ * Field handler to present a link to edit the candidate.
+ */
+
+class views_handler_field_election_candidate_link_edit extends views_handler_field_election_candidate_link {
+
+  /**
+   * Overrides parent::construct().
+   */
+  public function construct() {
+    parent::construct();
+    $this->additional_fields['election_id'] = 'election_id';
+    $this->additional_fields['type'] = 'type';
+    $this->additional_fields['uid'] = 'uid';
+  }
+
+  /**
+   * Overrides parent::render_link().
+   */
+  public function render_link($data, $values) {
+    // Ensure user has access to edit this candidate.
+    $candidate = new stdClass();
+    $candidate->candidate_id = $this->get_value($values, 'candidate_id');
+    $candidate->election_id = $this->get_value($values, 'election_id');
+    $candidate->type = $this->get_value($values, 'type');
+    $candidate->uid = $this->get_value($values, 'uid');
+    if (!entity_access('update', 'election_candidate', $candidate)) {
+      return;
+    }
+    $this->options['alter']['make_link'] = TRUE;
+    $this->options['alter']['path'] = "election-candidate/{$candidate->candidate_id}/edit";
+    $this->options['alter']['query'] = drupal_get_destination();
+    $text = !empty($this->options['text']) ? $this->options['text'] : t('Edit');
+    return $text;
+  }
+
+}
diff --git a/election_post/election-post.admin.inc b/election_post/election-post.admin.inc
index 30daa67..7d864c4 100644
--- a/election_post/election-post.admin.inc
+++ b/election_post/election-post.admin.inc
@@ -281,98 +281,15 @@ function election_post_form_delete_confirm_submit($form, &$form_state) {
 }
 
 /**
- * Form builder function for the administrative list of election posts.
+ * Page callback for managing election posts.
  */
-function election_post_manage_form($form, &$form_state, stdClass $election) {
-
-  $title = election_post_manage_page_title($election);
-  drupal_set_title($title, PASS_THROUGH);
-  drupal_set_breadcrumb(
-    _election_build_breadcrumb($election)
-  );
-
-  $form['#election'] = $election;
-
-  // Build the sortable table header.
-  $header = array(
-    'title' => array(
-      'data' => t('Title'),
-      'field' => 'ep.title',
-      'sort' => 'asc',
-    ),
-    'changed' => array('data' => t('Last updated'), 'field' => 'ep.changed'),
-    'operations' => array('data' => t('Operations')),
-  );
-
-  // Build the posts query, adding a pager and sorter.
-  $query = db_select('election_post', 'ep')
-    ->extend('PagerDefault')
-    ->extend('TableSort')
-    ->fields('ep', array('post_id'))
-    ->condition('election_id', $election->election_id);
-
-  $query->limit(50)->orderByHeader($header);
-
-  // Get an array of post IDs.
-  $post_ids = $query->execute()->fetchCol();
-
-  $posts = election_post_load_multiple($post_ids);
-  $form['#posts'] = $posts;
-
-  $destination = drupal_get_destination();
-
-  $rows = array();
-  foreach ($posts as $id => $post) {
-
-    $rows[$post->post_id] = array(
-      'title' => l($post->title, election_post_uri_path($post)),
-      'changed' => format_date($post->changed, 'short'),
-      'operations' => array(),
-    );
-
-    $operations = array();
-    if (entity_access('update', 'election_post', $post)) {
-      $operations['edit'] = l(
-        t('edit'),
-        election_post_uri_path($post) . '/edit',
-        array('query' => $destination)
-      );
-    }
-    if (entity_access('delete', 'election_post', $post)) {
-      $operations['delete'] = l(
-        t('delete'),
-        election_post_uri_path($post) . '/delete',
-        array('query' => $destination)
-      );
-    }
-
-    if (count($operations)) {
-      // Render an unordered list of operations links.
-      $rows[$post->post_id]['operations'] = array(
-        'data' => array(
-          '#theme' => 'item_list',
-          '#items' => $operations,
-          '#attributes' => array('class' => array('operations')),
-        ),
-      );
-    }
-
-  }
-
-  $form['election_posts'] = array(
-    '#theme' => 'table',
-    '#header' => $header,
-    '#rows' => $rows,
-    '#empty' => t('No @posts available.', array('@posts' => election_get_post_name($election->type, TRUE))),
-  );
-
-  $form['pager'] = array('#markup' => theme('pager'));
-
-  return $form;
-
+function election_post_manage_page(stdClass $election) {
+  $posts_name = election_get_post_name($election->type, TRUE);
+  drupal_set_title(t('Manage @posts', array('@posts' => $posts_name)), PASS_THROUGH);
+  drupal_set_breadcrumb(_election_build_breadcrumb($election));
+  return views_embed_view('election_posts_admin', 'embed', $election->election_id);
 }
 
-
 /**
  * Page callback for editing an election post.
  *
diff --git a/election_post/election_post.info b/election_post/election_post.info
index d4558f0..1782f4b 100644
--- a/election_post/election_post.info
+++ b/election_post/election_post.info
@@ -7,3 +7,4 @@ files[] = election-post.controller.inc
 files[] = views/handlers/views_handler_argument_election_post_postid.inc
 files[] = views/handlers/views_handler_field_election_post.inc
 files[] = views/handlers/views_handler_field_election_post_link.inc
+files[] = views/handlers/views_handler_field_election_post_link_edit.inc
diff --git a/election_post/election_post.module b/election_post/election_post.module
index 3c19a6e..8dc8cde 100644
--- a/election_post/election_post.module
+++ b/election_post/election_post.module
@@ -29,8 +29,8 @@ function election_post_menu() {
   $items['election/%election/posts'] = array(
     'title callback' => 'election_post_manage_page_title',
     'title arguments' => array(1),
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('election_post_manage_form', 1),
+    'page callback' => 'election_post_manage_page',
+    'page arguments' => array(1),
     'file' => 'election-post.admin.inc',
     'access callback' => 'election_access',
     'access arguments' => array('update', 1),
diff --git a/election_post/election_post.views.inc b/election_post/election_post.views.inc
index 353d2b3..1ab7002 100644
--- a/election_post/election_post.views.inc
+++ b/election_post/election_post.views.inc
@@ -67,6 +67,36 @@ function election_post_views_data() {
     ),
   );
 
+  $data['election_post']['created'] = array(
+    'title' => t('Created date'),
+    'help' => t('The date when the post was created.'),
+    'field' => array(
+      'handler' => 'views_handler_field_date',
+      'click sortable' => TRUE,
+    ),
+    'sort' => array(
+      'handler' => 'views_handler_sort_date',
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_date',
+    ),
+  );
+
+  $data['election_post']['changed'] = array(
+    'title' => t('Updated date'),
+    'help' => t('The date when the post was last updated.'),
+    'field' => array(
+      'handler' => 'views_handler_field_date',
+      'click sortable' => TRUE,
+    ),
+    'sort' => array(
+      'handler' => 'views_handler_sort_date',
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_date',
+    ),
+  );
+
   $data['election_post']['view_link'] = array(
     'field' => array(
       'title' => t('Link'),
@@ -75,6 +105,14 @@ function election_post_views_data() {
     ),
   );
 
+  $data['election_post']['edit_link'] = array(
+    'field' => array(
+      'title' => t('Edit link'),
+      'help' => t('A link to edit the post.'),
+      'handler' => 'views_handler_field_election_post_link_edit',
+    ),
+  );
+
   return $data;
 
 }
diff --git a/election_post/views/election-posts-admin.inc b/election_post/views/election-posts-admin.inc
new file mode 100644
index 0000000..9f011b3
--- /dev/null
+++ b/election_post/views/election-posts-admin.inc
@@ -0,0 +1,142 @@
+<?php
+/**
+ * @file
+ * View listing election posts for administrative use.
+ */
+
+$view = new view();
+$view->name = 'election_posts_admin';
+$view->description = 'An administrative list of election posts.';
+$view->tag = 'election';
+$view->base_table = 'election_post';
+$view->human_name = 'Election posts admin';
+$view->core = 7;
+$view->api_version = '3.0';
+$view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */
+
+/* Display: Master */
+$handler = $view->new_display('default', 'Master', 'default');
+$handler->display->display_options['title'] = 'Posts';
+$handler->display->display_options['use_ajax'] = TRUE;
+$handler->display->display_options['use_more_always'] = FALSE;
+$handler->display->display_options['access']['type'] = 'perm';
+$handler->display->display_options['access']['perm'] = 'view published elections';
+$handler->display->display_options['cache']['type'] = 'none';
+$handler->display->display_options['query']['type'] = 'views_query';
+$handler->display->display_options['query']['options']['distinct'] = TRUE;
+$handler->display->display_options['query']['options']['slave'] = TRUE;
+$handler->display->display_options['query']['options']['query_comment'] = FALSE;
+$handler->display->display_options['exposed_form']['type'] = 'basic';
+$handler->display->display_options['pager']['type'] = 'full';
+$handler->display->display_options['pager']['options']['items_per_page'] = '25';
+$handler->display->display_options['style_plugin'] = 'table';
+$handler->display->display_options['style_options']['columns'] = array(
+  'title' => 'title',
+  'created' => 'created',
+  'changed' => 'changed',
+  'view_link' => 'view_link',
+  'edit_link' => 'view_link',
+);
+$handler->display->display_options['style_options']['default'] = 'title';
+$handler->display->display_options['style_options']['info'] = array(
+  'title' => array(
+    'sortable' => 1,
+    'default_sort_order' => 'asc',
+    'align' => '',
+    'separator' => '',
+    'empty_column' => 0,
+  ),
+  'created' => array(
+    'sortable' => 1,
+    'default_sort_order' => 'desc',
+    'align' => '',
+    'separator' => '',
+    'empty_column' => 0,
+  ),
+  'changed' => array(
+    'sortable' => 1,
+    'default_sort_order' => 'desc',
+    'align' => '',
+    'separator' => '',
+    'empty_column' => 0,
+  ),
+  'view_link' => array(
+    'align' => '',
+    'separator' => ' · ',
+    'empty_column' => 0,
+  ),
+  'edit_link' => array(
+    'align' => '',
+    'separator' => '',
+    'empty_column' => 0,
+  ),
+);
+$handler->display->display_options['style_options']['empty_table'] = TRUE;
+/* No results behavior: Global: Text area */
+$handler->display->display_options['empty']['area']['id'] = 'area';
+$handler->display->display_options['empty']['area']['table'] = 'views';
+$handler->display->display_options['empty']['area']['field'] = 'area';
+$handler->display->display_options['empty']['area']['label'] = 'There are currently no posts in this election';
+$handler->display->display_options['empty']['area']['content'] = 'There are currently no posts in this election.';
+$handler->display->display_options['empty']['area']['format'] = 'filtered_html';
+/* Field: Election post: Title */
+$handler->display->display_options['fields']['title']['id'] = 'title';
+$handler->display->display_options['fields']['title']['table'] = 'election_post';
+$handler->display->display_options['fields']['title']['field'] = 'title';
+$handler->display->display_options['fields']['title']['element_label_colon'] = FALSE;
+$handler->display->display_options['fields']['title']['link_to_post'] = 1;
+/* Field: Election post: Created date */
+$handler->display->display_options['fields']['created']['id'] = 'created';
+$handler->display->display_options['fields']['created']['table'] = 'election_post';
+$handler->display->display_options['fields']['created']['field'] = 'created';
+$handler->display->display_options['fields']['created']['label'] = 'Created';
+$handler->display->display_options['fields']['created']['date_format'] = 'short';
+/* Field: Election post: Updated date */
+$handler->display->display_options['fields']['changed']['id'] = 'changed';
+$handler->display->display_options['fields']['changed']['table'] = 'election_post';
+$handler->display->display_options['fields']['changed']['field'] = 'changed';
+$handler->display->display_options['fields']['changed']['label'] = 'Updated';
+$handler->display->display_options['fields']['changed']['date_format'] = 'short';
+/* Field: Election post: Link */
+$handler->display->display_options['fields']['view_link']['id'] = 'view_link';
+$handler->display->display_options['fields']['view_link']['table'] = 'election_post';
+$handler->display->display_options['fields']['view_link']['field'] = 'view_link';
+$handler->display->display_options['fields']['view_link']['label'] = 'Actions';
+$handler->display->display_options['fields']['view_link']['element_wrapper_type'] = 'span';
+$handler->display->display_options['fields']['view_link']['element_wrapper_class'] = 'election-action-link election-action-link-view';
+$handler->display->display_options['fields']['view_link']['element_default_classes'] = FALSE;
+$handler->display->display_options['fields']['view_link']['hide_empty'] = TRUE;
+$handler->display->display_options['fields']['view_link']['text'] = 'view';
+/* Field: Election post: Edit link */
+$handler->display->display_options['fields']['edit_link']['id'] = 'edit_link';
+$handler->display->display_options['fields']['edit_link']['table'] = 'election_post';
+$handler->display->display_options['fields']['edit_link']['field'] = 'edit_link';
+$handler->display->display_options['fields']['edit_link']['label'] = '';
+$handler->display->display_options['fields']['edit_link']['element_label_colon'] = FALSE;
+$handler->display->display_options['fields']['edit_link']['text'] = 'edit';
+/* Sort criterion: Election post: Title */
+$handler->display->display_options['sorts']['title']['id'] = 'title';
+$handler->display->display_options['sorts']['title']['table'] = 'election_post';
+$handler->display->display_options['sorts']['title']['field'] = 'title';
+/* Contextual filter: Election: Election ID */
+$handler->display->display_options['arguments']['election_id']['id'] = 'election_id';
+$handler->display->display_options['arguments']['election_id']['table'] = 'election';
+$handler->display->display_options['arguments']['election_id']['field'] = 'election_id';
+$handler->display->display_options['arguments']['election_id']['default_action'] = 'not found';
+$handler->display->display_options['arguments']['election_id']['default_argument_type'] = 'fixed';
+$handler->display->display_options['arguments']['election_id']['summary']['number_of_records'] = '0';
+$handler->display->display_options['arguments']['election_id']['summary']['format'] = 'default_summary';
+$handler->display->display_options['arguments']['election_id']['summary_options']['count'] = FALSE;
+$handler->display->display_options['arguments']['election_id']['summary_options']['items_per_page'] = '25';
+$handler->display->display_options['arguments']['election_id']['specify_validation'] = TRUE;
+$handler->display->display_options['arguments']['election_id']['validate']['type'] = 'numeric';
+/* Filter criterion: Election: Published or admin */
+$handler->display->display_options['filters']['published_or_admin']['id'] = 'published_or_admin';
+$handler->display->display_options['filters']['published_or_admin']['table'] = 'election';
+$handler->display->display_options['filters']['published_or_admin']['field'] = 'published_or_admin';
+
+/* Display: Embed */
+$handler = $view->new_display('embed', 'Embed', 'embed');
+$handler->display->display_options['defaults']['hide_admin_links'] = FALSE;
+
+$views[$view->name] = $view;
diff --git a/election_post/views/election-posts.inc b/election_post/views/election-posts.inc
index eef0acb..2db156e 100644
--- a/election_post/views/election-posts.inc
+++ b/election_post/views/election-posts.inc
@@ -7,7 +7,7 @@
 $view = new view;
 $view->name = 'election_posts';
 $view->description = 'A list of posts (positions / questions) per election.';
-$view->tag = 'default';
+$view->tag = 'election';
 $view->base_table = 'election_post';
 $view->human_name = 'Election posts';
 $view->core = 7;
diff --git a/election_post/views/handlers/views_handler_field_election_post_link_edit.inc b/election_post/views/handlers/views_handler_field_election_post_link_edit.inc
new file mode 100644
index 0000000..0cb038e
--- /dev/null
+++ b/election_post/views/handlers/views_handler_field_election_post_link_edit.inc
@@ -0,0 +1,38 @@
+<?php
+/**
+ * @file
+ * Field handler to present a link to edit the post.
+ */
+
+class views_handler_field_election_post_link_edit extends views_handler_field_election_post_link {
+
+  /**
+   * Overrides parent::construct().
+   */
+  public function construct() {
+    parent::construct();
+    $this->additional_fields['election_id'] = 'election_id';
+    $this->additional_fields['type'] = 'type';
+    $this->additional_fields['vstatus_inheritance'] = 'vstatus_inheritance';
+  }
+
+  /**
+   * Overrides parent::render_link().
+   */
+  public function render_link($data, $values) {
+    // Ensure user has access to edit this post.
+    $post = new stdClass();
+    $post->post_id = $this->get_value($values, 'post_id');
+    $post->election_id = $this->get_value($values, 'election_id');
+    $post->type = $this->get_value($values, 'type');
+    $post->vstatus_inheritance = $this->get_value($values, 'vstatus_inheritance');
+    if (!entity_access('update', 'election_post', $post)) {
+      return;
+    }
+    $this->options['alter']['make_link'] = TRUE;
+    $this->options['alter']['path'] = "election-post/{$post->post_id}/edit";
+    $this->options['alter']['query'] = drupal_get_destination();
+    $text = !empty($this->options['text']) ? $this->options['text'] : t('Edit');
+    return $text;
+  }
+}
diff --git a/election_results/election_results.module b/election_results/election_results.module
index 18a237f..3f3e35d 100644
--- a/election_results/election_results.module
+++ b/election_results/election_results.module
@@ -73,9 +73,9 @@ function election_results_access($op, stdClass $post, $account = NULL) {
  * Implements hook_entity_load().
  */
 function election_results_entity_load($entities, $type) {
-  $ballot_counts = &drupal_static(__FUNCTION__, array());
   // Add 'ballot_count' property to posts.
   if ($type == 'election_post') {
+    $ballot_counts = &drupal_static(__FUNCTION__, array());
     if (count(array_diff_key($entities, $ballot_counts))) {
       $ballot_counts = db_query(
         'SELECT post_id, COUNT(DISTINCT ballot_id) AS ballot_count FROM {election_ballot} WHERE post_id IN(:pids) GROUP BY post_id',
@@ -149,24 +149,3 @@ function election_results_page(stdClass $post) {
   return $output;
 
 }
-
-/**
- * Implements hook_form_FORM_ID_alter().
- *
- * Alter the form at election/%election/posts.
- */
-function election_results_form_election_post_manage_form_alter(&$form) {
-  $election = $form['#election'];
-  $posts = $form['#posts'];
-  foreach ($form['election_posts']['#rows'] as $post_id => &$row) {
-    $post = $posts[$post_id];
-    $path = election_post_uri_path($post);
-    // Add a 'results' link.
-    if (election_results_access('view', $post)) {
-      $row['operations']['data']['#items']['results'] = l(
-        t('results (@count)', array('@count' => $post->ballot_count)),
-        $path . '/results'
-      );
-    }
-  }
-}
diff --git a/views/all-elections.inc b/views/all-elections.inc
index 0382001..0554b47 100644
--- a/views/all-elections.inc
+++ b/views/all-elections.inc
@@ -4,10 +4,10 @@
  * View listing all elections.
  */
 
-$view = new view;
+$view = new view();
 $view->name = 'elections';
 $view->description = 'A publicly viewable list of elections';
-$view->tag = 'default';
+$view->tag = 'election';
 $view->base_table = 'election';
 $view->human_name = 'Elections';
 $view->core = 7;
