diff --git a/config/install/pants.settings.yml b/config/install/pants.settings.yml
new file mode 100644
index 0000000..e116507
--- /dev/null
+++ b/config/install/pants.settings.yml
@@ -0,0 +1,2 @@
+pants_type: ''
+pants_recent_block_count: 10
diff --git a/pants.info.yml b/pants.info.yml
new file mode 100644
index 0000000..43f0f05
--- /dev/null
+++ b/pants.info.yml
@@ -0,0 +1,6 @@
+name: Pants
+description: 'Tracks pants status for users.'
+core: 8.x
+dependencies:
+  - user
+type: module
diff --git a/pants.module b/pants.module
index cf8d914..56b8b69 100644
--- a/pants.module
+++ b/pants.module
@@ -31,12 +31,7 @@ function pants_menu() {
   return $items;
 }
 
-/**
- * Pants change menu access callback.
- */
-function pants_change_access() {
-  return user_access('change pants status') || user_access('administer pants');
-}
+
 
 /**
  * Implements hook_permission().
@@ -55,8 +50,8 @@ function pants_permission() {
 /**
  * Implements hook_form_FORM_ID_alter() for user_profile_form().
  */
-function pants_form_user_profile_form_alter(&$form, &$form_state) {
-  if ($form['#user_category'] == 'account' && user_access('change pants status')) {
+function pants_form_user_profile_form_alter(&$form, \Drupal\Core\Form\FormStateInterface &$form_state) {
+  if ($form['#user_category'] == 'account' && \Drupal::currentUser()->hasPermission('change pants status')) {
     $account = $form_state['user'];
     $form['pants_status'] = array(
       '#type' => 'fieldset',
@@ -98,7 +93,7 @@ function pants_user_view($account, $view_mode, $langcode) {
   $account->content['summary']['pants'] = array(
     '#type' => 'user_profile_item',
     '#title' => t('Pants status'),
-    '#markup' => theme('pants_status', array('account' => $account, 'type' => variable_get('pants_type', ''))),
+    '#markup' => _theme('pants_status', array('account' => $account, 'type' => \Drupal::config('pants.settings')->get('pants_type'))),
   );
 }
 
@@ -137,9 +132,9 @@ function theme_pants_status($variables) {
     case '':
       return pants_get($account->uid) ? t('On') : t('Off');
     case 'mchammer':
-      return pants_get($account->uid) ? theme('image', array('path' => 'http://nickyscostumes.com.au/images/uploads/hammerpants.jpg')) : t('Off');
+      return pants_get($account->uid) ? _theme('image', array('path' => 'http://nickyscostumes.com.au/images/uploads/hammerpants.jpg')) : t('Off');
     case 'bellbottoms':
-      return pants_get($account->uid) ? theme('image', array('path' => 'http://ecx.images-amazon.com/images/I/41xXmNdZn8L._SY200_.jpg')) : t('Off');  
+      return pants_get($account->uid) ? _theme('image', array('path' => 'http://ecx.images-amazon.com/images/I/41xXmNdZn8L._SY200_.jpg')) : t('Off');  
   }
 }
 
@@ -149,10 +144,10 @@ function theme_pants_status($variables) {
  * @ingroup themeable
  */
 function theme_pants_change_block($variables) {
-  global $user;
+  $user = \Drupal::currentUser();
 
   $output  = '<div class="pants-status">';
-  $output .= theme('pants_status', array('account' => $user));
+  $output .= _theme('pants_status', array('account' => $user));
   $output .= '</div>';
 
   $output .= l(t('Change'), "pants/change/{$user->uid}", array('attributes' => array('id' => 'pants')));
@@ -168,10 +163,10 @@ function theme_pants_change_block($variables) {
 function theme_pants_recent_block($variables) {
   $items = array();
 
-  $statuses = db_query_range('SELECT u.uid, u.name, p.status, p.changed, changed_by FROM {pants_history} p INNER JOIN {users} u ON p.uid = u.uid ORDER BY changed DESC', 0, variable_get('pants_recent_block_count', 10))->fetchAll();
+  $statuses = db_query_range('SELECT u.uid, u.name, p.status, p.changed, changed_by FROM {pants_history} p INNER JOIN {users} u ON p.uid = u.uid ORDER BY changed DESC', 0, \Drupal::config('pants.settings')->get('pants_recent_block_count'))->fetchAll();
 
   foreach ($statuses as $pants) {
-    $username = theme('username', array('account' => $pants));
+    $username = _theme('username', array('account' => $pants));
     $time = format_interval(time() - $pants->changed);
     if ($pants->status) {
       $items[] = t('!username put pants on @time ago', array('!username' => $username, '@time' => $time));
@@ -181,7 +176,7 @@ function theme_pants_recent_block($variables) {
     }
   }
 
-  $output = theme('item_list', array('items' => $items));
+  $output = _theme('item_list', array('items' => $items));
 
   return $output;
 }
@@ -212,7 +207,7 @@ function pants_block_view($delta = '') {
 
   switch ($delta) {
     case 'change_pants':
-      global $user;
+      $user = \Drupal::currentUser();
 
       $block['subject'] = t('Change pants');
       $block['content'] = array(
@@ -229,7 +224,7 @@ function pants_block_view($delta = '') {
       $block['subject'] = t('Recent pants');
       $block['content'] = array(
         '#theme' => 'pants_recent_block',
-        '#pants' => variable_get('pants_recent_block_count', 10),
+        '#pants' => \Drupal::config('pants.settings')->get('pants_recent_block_count'),
       );
       break;
   }
@@ -237,40 +232,11 @@ function pants_block_view($delta = '') {
   return $block;
 }
 
-/**
- * Form builder; The pants settings form.
- */
-function pants_settings() {
-  $form['pants_type'] = array(
-    '#type' => 'radios',
-    '#title' => t('Pants type'),
-    '#options' => array(
-      '' => t('None (just show on/off status)'),
-      'bellbottoms' => t('Bellbottoms'),
-      'mchammer' => t('MC Hammer'),
-    ),
-    '#default_value' => variable_get('pants_type', ''),
-    '#description' => t('Choose pants type to show on the user profile.'),
-  );
 
-  return system_settings_form($form);
-}
 
 ///// CRUD FUNCTIONS ////
 
-/**
- * Toggles a user's pants setting to the opposite of what it is now.
- *
- * @param stdClass $user
- *   A user object.
- */
-function pants_change($account) {
-  $uid = $account->uid;
-  $status = 1 - pants_get($uid);
-  pants_set($uid, $status);
-  print theme('pants_status', array('account' => $account));
-  exit;
-}
+
 
 /**
  * Returns a user's current pants status.
@@ -298,7 +264,7 @@ function pants_get($uid) {
  *   A 1 or 0 with which to modify the user's pants status.
  */
 function pants_set($uid, $status) {
-  global $user;
+  $user = \Drupal::currentUser();
 
   // Insert or update current row in {pants} table.
   db_merge('pants')
diff --git a/pants.routing.yml b/pants.routing.yml
new file mode 100644
index 0000000..6835e95
--- /dev/null
+++ b/pants.routing.yml
@@ -0,0 +1,14 @@
+pants.change:
+  path: '/pants/change/{user}'
+  defaults:
+    _title: 'Change pants'
+    _content: '\Drupal\pants\Controller\DefaultController::change'
+  requirements:
+    _custom_access: '\Drupal\pants\Controller\DefaultController::changeAccess'
+pants.admin_config_people_pants:
+  path: /admin/config/people/pants
+  defaults:
+    _title: Pants
+    _form: \Drupal\pants\Form\PantsSettings
+  requirements:
+    _permission: 'administer pants'
diff --git a/src/Controller/DefaultController.php b/src/Controller/DefaultController.php
new file mode 100644
index 0000000..9ac5b56
--- /dev/null
+++ b/src/Controller/DefaultController.php
@@ -0,0 +1,36 @@
+<?php /**
+ * @file
+ * Contains \Drupal\pants\Controller\DefaultController.
+ */
+
+namespace Drupal\pants\Controller;
+
+use Drupal\Core\Controller\ControllerBase;
+
+/**
+ * Default controller for the pants module.
+ */
+class DefaultController extends ControllerBase {
+
+/**
+ * Pants change menu access callback.
+ */
+function changeAccess() {
+  return \Drupal::currentUser()->hasPermission('change pants status') || \Drupal::currentUser()->hasPermission('administer pants');
+}
+
+/**
+ * Toggles a user's pants setting to the opposite of what it is now.
+ *
+ * @param stdClass $user
+ *   A user object.
+ */
+function change($account) {
+  $uid = $account->id();
+  $status = 1 - pants_get($uid);
+  pants_set($uid, $status);
+  print _theme('pants_status', array('account' => $account));
+  exit;
+}
+
+}
diff --git a/src/Form/PantsSettings.php b/src/Form/PantsSettings.php
new file mode 100644
index 0000000..23dd0a7
--- /dev/null
+++ b/src/Form/PantsSettings.php
@@ -0,0 +1,58 @@
+<?php /**
+ * @file
+ * Contains \Drupal\pants\Form\PantsSettings.
+ */
+
+namespace Drupal\pants\Form;
+
+use Drupal\Core\Form\ConfigFormBase;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Render\Element;
+
+class PantsSettings extends ConfigFormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getFormId() {
+    return 'pants_settings';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submitForm(array &$form, FormStateInterface $form_state) {
+    $config = $this->config('pants.settings');
+
+    foreach (Element::children($form) as $variable) {
+      $config->set($variable, $form_state->getValue($form[$variable]['#parents']));
+    }
+    $config->save();
+
+    if (method_exists($this, '_submitForm')) {
+      $this->_submitForm($form, $form_state);
+    }
+
+    parent::submitForm($form, $form_state);
+  }
+
+/**
+ * Form builder; The pants settings form.
+ */
+function buildForm(array $form, FormStateInterface $form_state) {
+  $form['pants_type'] = array(
+    '#type' => 'radios',
+    '#title' => t('Pants type'),
+    '#options' => array(
+      '' => t('None (just show on/off status)'),
+      'bellbottoms' => t('Bellbottoms'),
+      'mchammer' => t('MC Hammer'),
+    ),
+    '#default_value' => \Drupal::config('pants.settings')->get('pants_type'),
+    '#description' => t('Choose pants type to show on the user profile.'),
+  );
+
+  return parent::buildForm($form, $form_state);
+}
+
+}
diff --git a/src/Plugin/Block/ChangePants.php b/src/Plugin/Block/ChangePants.php
new file mode 100644
index 0000000..6954dfa
--- /dev/null
+++ b/src/Plugin/Block/ChangePants.php
@@ -0,0 +1,35 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\pants\Plugin\Block\ChangePants.
+ */
+
+namespace Drupal\pants\Plugin\Block;
+
+use Drupal\block\BlockBase;
+
+/**
+ * Provides the ChangePants block.
+ *
+ * @Block(
+ *   id = "change_pants",
+ *   admin_label = @Translation("Change pants")
+ * )
+ */
+class ChangePants extends BlockBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function build() {
+    /**
+     * @FIXME
+     * hook_block_view() has been removed in Drupal 8. You should move your
+     * block's code into this method and delete pants_block_view()
+     * as soon as possible!
+     */
+    return pants_block_view('change_pants');
+  }
+
+}
diff --git a/src/Plugin/Block/RecentPants.php b/src/Plugin/Block/RecentPants.php
new file mode 100644
index 0000000..6315b6c
--- /dev/null
+++ b/src/Plugin/Block/RecentPants.php
@@ -0,0 +1,35 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\pants\Plugin\Block\RecentPants.
+ */
+
+namespace Drupal\pants\Plugin\Block;
+
+use Drupal\block\BlockBase;
+
+/**
+ * Provides the RecentPants block.
+ *
+ * @Block(
+ *   id = "recent_pants",
+ *   admin_label = @Translation("Recent pants")
+ * )
+ */
+class RecentPants extends BlockBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function build() {
+    /**
+     * @FIXME
+     * hook_block_view() has been removed in Drupal 8. You should move your
+     * block's code into this method and delete pants_block_view()
+     * as soon as possible!
+     */
+    return pants_block_view('recent_pants');
+  }
+
+}
