diff --git a/panelizer.module b/panelizer.module
index 6e6b4ee..efeae12 100644
--- a/panelizer.module
+++ b/panelizer.module
@@ -70,6 +70,17 @@ function panelizer_menu() {
     $handler->hook_menu($items);
   }
 
+  // Create a generic ajax callback useful for things like adding widgets
+  // to the IPE.
+  // /entity-type/entity-id/op
+  $items['panelizer/ajax/%/%/%'] = array(
+    'page callback' => 'panelizer_entity_plugin_switcher_page',
+    'page arguments' => array(2, 4, 3),
+    // This callback must handle its own access control.
+    'access callback' => TRUE,
+    'delivery callback' => 'ajax_deliver',
+  );
+
   return $items;
 }
 
@@ -277,8 +288,10 @@ function panelizer_ctools_plugin_api($module, $api) {
  */
 function panelizer_features_api() {
   $api = array();
-  $api['panelizer_defaults'] = _ctools_features_get_info('panelizer_defaults');
-  $api['panelizer_defaults']['alter_type'] = FEATURES_ALTER_TYPE_NONE;
+  if (function_exists('_ctools_features_get_info')) {
+    $api['panelizer_defaults'] = _ctools_features_get_info('panelizer_defaults');
+    $api['panelizer_defaults']['alter_type'] = FEATURES_ALTER_TYPE_NONE;
+  }
 
   return $api;
 }
@@ -542,7 +555,7 @@ function panelizer_entity_plugin_switcher_page($entity_type, $op) {
 
   // Load the $plugin information
   if ($handler = panelizer_entity_plugin_get_handler($entity_type)) {
-    $method = 'page_' . $op;
+    $method = 'page_' . str_replace('-', '_', $op);
     if (method_exists($handler, $method)) {
       // replace the first two arguments:
       $args[0] = $js;
@@ -960,11 +973,19 @@ function panelizer_context_cache_clear($entity_type, $key) {
  * The key is the second half of the key in this form:
  * panelizer:TYPE:KEY;
  */
-function panelizer_panels_cache_get($argument) {
+function panelizer_panels_cache_get($argument, $override_panelizer_type = NULL, $override_panelizer_key = NULL) {
   ctools_include('object-cache');
   list($entity_type, $key) = explode(':', $argument, 2);
   $cache = ctools_object_cache_get('panelizer_display_cache', $entity_type . ':' . $key);
 
+  if (isset($cache->override_panelizer_type)) {
+    // This override allows us to actually edit the default with a different
+    // button using the IPE.
+    list($entity_id, $view_mode) = explode(':', $key);
+    $entity_type = $cache->override_panelizer_type;
+    $key = $cache->override_panelizer_key;
+  }
+
   // Keep $type because $entity_type can be 'default' which is not actually an
   // entity type in that case.
   $type = $entity_type;
@@ -972,32 +993,46 @@ function panelizer_panels_cache_get($argument) {
     list($entity_type, $bundle, $name) = @explode(':', $key, 3);
     $get_default = TRUE;
   }
+  else {
+    list($entity_id, $view_mode) = explode(':', $key);
+  }
 
   $handler = panelizer_entity_plugin_get_handler($entity_type);
   if (!$handler) {
     return;
   }
 
+  if (isset($entity_id)) {
+    $entities = entity_load($entity_type, array($entity_id));
+  }
+
   // If it's already cached, we still need to restore our contexts.
   if (!empty($cache)) {
     $cache->cached = TRUE;
     if (!empty($get_default)) {
       $panelizer = $handler->get_default_panelizer_object($bundle, $name);
-      $cache->display->context = $handler->get_contexts($panelizer);
     }
     else {
-      list($entity_id, $view_mode) = explode(':', $key);
-      $entities = entity_load($entity_type, array($entity_id));
       if (!empty($entities[$entity_id]) && !empty($entities[$entity_id]->panelizer[$view_mode])) {
         $panelizer = $entities[$entity_id]->panelizer[$view_mode];
-        $cache->display->context = $handler->get_contexts($panelizer, $entities[$entity_id]);
       }
     }
 
+    if (empty($entities) || empty($entities[$entity_id])) {
+      $cache->display->context = $handler->get_contexts($panelizer);
+    }
+    else {
+      $cache->display->context = $handler->get_contexts($panelizer, $entities[$entity_id]);
+    }
+
     return $cache;
   }
 
   $cache = new stdClass();
+  if (!empty($override_panelizer_type)) {
+    $cache->override_panelizer_type = $override_panelizer_type;
+    $cache->override_panelizer_key = $override_panelizer_key;
+  }
 
   // If it wasn't cached, create a new cache.
   if (!empty($get_default)) {
@@ -1019,7 +1054,7 @@ function panelizer_panels_cache_get($argument) {
   }
 
   ctools_include('common', 'panels');
-  $cache->display->cache_key = "panelizer:$type:$key";
+  $cache->display->cache_key = "panelizer:$argument";
   $cache->content_types = panels_common_get_allowed_types('panelizer_' . $type . ':' . $bundle, $cache->display->context);
 
   return $cache;
@@ -1048,7 +1083,15 @@ function panelizer_panels_cache_clear($argument, $cache) {
  */
 function panelizer_panels_cache_save($argument, $cache) {
   list($entity_type, $key) = explode(':', $argument, 2);
-  $type = $entity_type;
+
+  if (isset($cache->override_panelizer_type)) {
+    // This override allows us to actually edit the default with a different
+    // button using the IPE.
+    list($entity_id, $view_mode) = explode(':', $key);
+    $entity_type = $cache->override_panelizer_type;
+    $key = $cache->override_panelizer_key;
+  }
+
   if ($entity_type == 'default') {
     list($entity_type, $bundle, $name) = @explode(':', $key, 3);
     $get_default = TRUE;
@@ -1074,6 +1117,7 @@ function panelizer_panels_cache_save($argument, $cache) {
       $handler->entity_save($entities[$entity_id]);
     }
   }
+
   panelizer_panels_cache_clear($argument, $cache);
 }
 
@@ -1286,3 +1330,62 @@ function panelizer_set_status_action_submit($form, $form_state) {
 
   return $retval;
 }
+
+/**
+ * Implements hook_form_alter().
+ *
+ * This form alter adds a submit response to the IPE edit control form
+ * so that we can tell it to properly reset IPE extra buttons when
+ * IPE is saved using panelizer.
+ */
+function panelizer_form_panels_ipe_edit_control_form_alter(&$form, &$form_state) {
+  if (empty($form_state['renderer'])) {
+    return;
+  }
+
+  $renderer = $form_state['renderer'];
+
+  $cache_key = $renderer->display->cache_key;
+  list($module, $type, $key) = explode(':', $cache_key, 3);
+  if ($module != 'panelizer') {
+    return;
+  }
+
+  if ($type == 'default') {
+    return;
+  }
+
+  // Load the $plugin information
+  $handler = panelizer_entity_plugin_get_handler($type);
+  if (!$handler) {
+    return;
+  }
+
+  // We only do this on standard IPE edit, not our specialized IPE edit.
+
+  if (!empty($renderer->cache->override_panelizer_type)) {
+    return;
+  }
+
+  $form_state['panelizer handler'] = $handler;
+  $form_state['panelizer key'] = $key;
+  $form['buttons']['submit']['#submit'][] = 'panelizer_panels_ipe_edit_control_form_submit';
+}
+
+function panelizer_panels_ipe_edit_control_form_submit($form, &$form_state) {
+  $handler = $form_state['panelizer handler'];
+  $renderer = $form_state['renderer'];
+  list($entity_id, $view_mode) = explode(':', $form_state['panelizer key']);
+
+  $entities = entity_load($handler->entity_type, array($entity_id));
+
+  $buttons = $handler->get_ipe_buttons($renderer, $entities[$entity_id], $view_mode, $cache->display->cache_key, $cache->clean_key, TRUE);
+  foreach ($buttons as $id => $button) {
+    if (empty($button['#skip'])) {
+      $renderer->commands[] = ajax_command_replace('#' . $id, drupal_render($button));
+    }
+    else {
+      $renderer->commands[] = ajax_command_remove('#' . $id);
+    }
+  }
+}
diff --git a/plugins/entity/PanelizerEntityDefault.class.php b/plugins/entity/PanelizerEntityDefault.class.php
index cda4296..4bdefe2 100644
--- a/plugins/entity/PanelizerEntityDefault.class.php
+++ b/plugins/entity/PanelizerEntityDefault.class.php
@@ -951,6 +951,7 @@ abstract class PanelizerEntityDefault implements PanelizerEntityInterface {
 
       if ($this->supports_revisions) {
         if (empty($panelizer->revision_id) || $panelizer->revision_id != $revision_id) {
+          $previous_revision = $panelizer->revision_id;
           $panelizer->revision_id = $revision_id;
           $update = array();
         }
@@ -978,14 +979,19 @@ abstract class PanelizerEntityDefault implements PanelizerEntityInterface {
           $panelizer = $this->clone_panelizer($panelizer, $entity);
         }
 
-        // First write the display
-        panels_save_display($panelizer->display);
+        if (!empty($panelizer->display)) {
+          panels_save_display($panelizer->display);
 
-        // Make sure we have the did.
-        $panelizer->did = $panelizer->display->did;
+          // Make sure we have the did.
+          $panelizer->did = $panelizer->display->did;
 
-        // Ensure that we always write this as NULL when we have our own panel:
-        $panelizer->name = NULL;
+          // Ensure that we always write this as NULL when we have our own panel:
+          $panelizer->name = NULL;
+        }
+        else {
+          // If display is modified and there is no display, this is a revert.
+          $panelizer->did = '';
+        }
 
         // Make sure there is a view mode.
         if (!isset($panelizer->view_mode)) {
@@ -1159,16 +1165,19 @@ abstract class PanelizerEntityDefault implements PanelizerEntityInterface {
     list($entity_id, $revision_id, $bundle) = entity_extract_ids($this->entity_type, $entity);
     $panelizer_clone = clone $panelizer;
 
-    // In order to ensure we don't actually use and modify the default display,
-    // we export and re-import it.
-    $code = panels_export_display($panelizer->display);
-    ob_start();
-    eval($code);
-    ob_end_clean();
+    if (!empty($panelizer->display)) {
+      // In order to ensure we don't actually use and modify the default display,
+      // we export and re-import it.
+      $code = panels_export_display($panelizer->display);
+      ob_start();
+      eval($code);
+      ob_end_clean();
+
+      $panelizer_clone->display = $display;
+      $panelizer_clone->name = NULL;
+    }
 
-    $panelizer_clone->display = $display;
     $panelizer_clone->did = NULL;
-    $panelizer_clone->name = NULL;
     $panelizer_clone->entity_type = $this->entity_type;
     $panelizer_clone->entity_id = $entity_id;
     // The (int) ensures that entities that do not support revisions work
@@ -2120,6 +2129,26 @@ abstract class PanelizerEntityDefault implements PanelizerEntityInterface {
 
     ctools_include('plugins', 'panels');
     $renderer = panels_get_renderer($panelizer->pipeline, $display);
+
+    if ($renderer->plugin['name'] == 'ipe' && !$this->panelizer_access('content', $entity, $view_mode)) {
+      // If the IPE is enabled, but the user does not have access to edit,
+      // load the standard renderer instead.
+      $renderer = panels_get_renderer_handler('standard', $display);
+    }
+
+    // If there's an IPE running, add some custom buttons:
+    if ($renderer->plugin['name'] == 'ipe') {
+      ctools_include('cleanstring');
+      $clean_key = ctools_cleanstring($display->cache_key);
+      $buttons = $this->get_ipe_buttons($renderer, $entity, $view_mode, $display->cache_key, $clean_key);
+
+      foreach ($buttons as $id => $button) {
+        if (empty($button['#skip'])) {
+          panels_ipe_toolbar_add_button($clean_key, $id, $button);
+        }
+      }
+    }
+
     $renderer->address = $address;
 
     $info = array(
@@ -2144,6 +2173,177 @@ abstract class PanelizerEntityDefault implements PanelizerEntityInterface {
   }
 
   /**
+   * Fetch a list of buttons for the IPE toolbar.
+   */
+  function get_ipe_buttons($renderer, $entity, $view_mode, $cache_key, $clean_key, $force_custom = FALSE) {
+    list($entity_id, $revision_id, $bundle) = entity_extract_ids($this->entity_type, $entity);
+    ctools_include('cleanstring');
+    $buttons = array();
+
+    $status = '';
+    if (!$force_custom && !empty($entity->panelizer[$view_mode]->name)) {
+      $default = ctools_export_crud_load('panelizer_defaults', $entity->panelizer[$view_mode]->name);
+      $status = !empty($default->title) ? check_plain($default->title) : t('Default');
+    }
+    else {
+      $status = t('Custom');
+    }
+
+    $buttons['panelizer-status'] = array(
+      '#type' => 'link',
+      '#title' => t('Panelizer status: ') . $status,
+      '#href' => 'panelizer/ajax/' . $this->entity_type . '/' . $entity_id . '/panelizer-status/' . $renderer->plugin['name'] . '/' . $view_mode . '/' . $cache_key,
+      '#id' => 'panelizer-status',
+      '#attributes' => array(
+        'class' => array('panelizer-status', 'panels-ipe-pseudobutton'),
+      ),
+      '#ajax' => array(
+        'progress' => 'throbber',
+        'ipe_cache_key' => $clean_key,
+      ),
+      '#prefix' => '<div class="panels-ipe-pseudobutton-container" id="panelizer-status">',
+      '#suffix' => '</div>',
+    );
+
+    if ($this->panelizer_access('defaults', $entity, $view_mode)) {
+      if (empty($force_custom) && empty($entity->panelizer[$view_mode]->did)) {
+        $buttons['panelizer-ipe-startedit-default'] = array(
+          '#type' => 'link',
+          '#title' => t('Customize this page\'s default'),
+          '#href' => 'panelizer/ajax/' . $this->entity_type . '/' . $entity_id . '/panelizer-edit-default/' . $renderer->plugin['name'] . '/' . $view_mode . '/' . $cache_key,
+          '#id' => 'panels-ipe-customize-page-default',
+          '#attributes' => array(
+            'class' => array('panels-ipe-startedit-default', 'panels-ipe-pseudobutton'),
+          ),
+          '#ajax' => array(
+            'progress' => 'throbber',
+            'ipe_cache_key' => $clean_key,
+          ),
+          '#prefix' => '<div class="panels-ipe-pseudobutton-container" id="panelizer-ipe-startedit-default">',
+          '#suffix' => '</div>',
+          '#attached' => array(
+            'js' => array(ctools_attach_js('panelizer-ipe', 'panelizer')),
+          ),
+        );
+      }
+      else {
+        $buttons['panelizer-ipe-startedit-default'] = array(
+          '#type' => 'markup',
+          '#skip' => TRUE,
+        );
+      }
+    }
+
+    return $buttons;
+  }
+
+  /**
+   * Allow a user to change a panelizer's state from the IPE.
+   */
+  public function page_panelizer_status($js, $input, $entity_id, $renderer_name, $view_mode, $cache_key) {
+    $commands = array();
+
+    $entities = entity_load($this->entity_type, array($entity_id));
+    if (!$entities) {
+      ctools_ajax_render_error(t('Invalid entity id.'));
+    }
+
+    $entity = reset($entities);
+
+    $form_state = array(
+      'handler' => $this,
+      'entity' => $entity,
+      'view_mode' => $view_mode,
+      'no_redirect' => TRUE,
+    );
+
+    ctools_include('modal');
+    $output = drupal_build_form('panelizer_ajax_choice_form', $form_state);
+    if (empty($form_state['executed'])) {
+      $commands[] = ctools_modal_command_display(t('Update panelizer status'), drupal_render($output));
+    }
+    else {
+      $name = $form_state['values']['name'];
+      $panelizer = $entity->panelizer[$view_mode];
+      list($entity_id, $revision_id, $bundle) = entity_extract_ids($this->entity_type, $entity);
+
+      $panelizer->name = implode(':', array($this->entity_type, $bundle, $name));
+      if ($panelizer->view_mode != 'page_manager') {
+        $panelizer->name .= ':' . $panelizer->view_mode;
+      }
+
+      // Remove any customized display.
+      $panelizer->display = NULL;
+      $panelizer->display_is_modified = TRUE;
+      $this->entity_save($entity);
+      ctools_include('ajax');
+      $commands[] = ctools_ajax_command_reload();
+    }
+
+    return array(
+      '#type' => 'ajax',
+      '#commands' => $commands
+    );
+  }
+
+  /**
+   * Allow a user to change a panelizer's state from the IPE.
+   */
+  public function page_panelizer_edit_default($js, $input, $entity_id, $renderer_name, $view_mode, $cache_key) {
+    // Much of this function is a retool of panels_ajax_router().
+
+    $entities = entity_load($this->entity_type, array($entity_id));
+    if (!$entities) {
+      ctools_ajax_render_error(t('Invalid entity id.'));
+    }
+
+    $entity = reset($entities);
+    list($entity_id, $revision_id, $bundle) = entity_extract_ids($this->entity_type, $entity);
+
+    $key = $this->entity_type . ':' . $bundle . ':' . $entity->panelizer[$view_mode]->name;
+    if ($view_mode != 'page_manager') {
+      $key .= ':' . $view_mode;
+    }
+
+    list($junk, $partial_key) = explode(':', $cache_key, 2);
+    $cache = panelizer_panels_cache_get($partial_key, 'default', $key);
+    $entities = entity_load($this->entity_type, array($entity_id));
+    if (!$entities) {
+      ctools_ajax_render_error(t('Invalid entity id.'));
+    }
+
+    $entity = reset($entities);
+    if (empty($cache)) {
+      return MENU_ACCESS_DENIED;
+    }
+
+    ctools_include('plugins', 'panels');
+    $renderer = panels_get_renderer_handler($renderer_name, $cache->display);
+    if (!$renderer) {
+      return MENU_ACCESS_DENIED;
+    }
+
+    ctools_include('display-edit', 'panels');
+
+    // These must be set on the renderer as they are in panels_ajax_router().
+    $renderer->cache = &$cache;
+    ctools_include('cleanstring');
+    $renderer->clean_key = ctools_cleanstring($cache_key);
+
+    $output = $renderer->ajax_save_form();
+    if (empty($output) && !empty($renderer->commands)) {
+      return array(
+        '#type' => 'ajax',
+        '#commands' => $renderer->commands,
+      );
+    }
+    else {
+      return $output;
+    }
+
+  }
+
+  /**
    * Fetch an object array of CTools contexts from panelizer information.
    */
   public function get_contexts($panelizer, $entity = NULL) {
@@ -2326,3 +2526,66 @@ function panelizer_entity_default_bundle_form_submit($form, &$form_state) {
   $type_location = $form['panelizer']['#location'];
   $form_state['panelizer_entity_handler']->add_bundle_setting_form_submit($form, $form_state, $bundle, $type_location);
 }
+
+function panelizer_ajax_choice_form($form, &$form_state) {
+  $entity = $form_state['entity'];
+  $view_mode = $form_state['view_mode'];
+  $handler = $form_state['handler'];
+
+  list($entity_id, $revision_id, $bundle) = entity_extract_ids($handler->entity_type, $entity);
+
+  $custom = empty($entity->panelizer[$view_mode]->name);
+  $options = array();
+  $view_bundle = $bundle . '.' . $view_mode;
+  if ($handler->has_panel_choice($view_bundle)) {
+    $handlers = $handler->get_default_panelizer_objects($view_bundle);
+
+    foreach ($handlers as $name => $handler) {
+      if (empty($handler->disabled)) {
+        $options[$name] = $handler->title ? $handler->title : t('Default');
+      }
+    }
+
+    if (!empty($entity->panelizer[$view_mode]->name)) {
+      $name = $entity->panelizer[$view_mode]->name;
+    }
+    else {
+      $name = 'default';
+    }
+
+    if (!$handler->has_default_panel($view_bundle)) {
+      $options = array('default' => t('-- No panel --')) + $options;
+    }
+  }
+  else if ($custom) {
+    $options = array(
+      'default' => t('Revert to default'),
+    );
+  }
+
+  if (empty($options)) {
+    $form['markup'] = array(
+      '#markup' => t('This entity is currently using the default panel and has no customizations that can be changed or reverted.'),
+    );
+
+    return $form;
+  }
+
+  $form['name'] = array(
+    '#title' => t('Change status'),
+    '#type' => 'radios',
+    '#options' => $options,
+    '#default_value' => $name,
+  );
+
+  if ($custom) {
+    $form['name']['#description'] = t('Warning: selecting one of these options will discard any customizations made to the panel on this entity.');
+  }
+
+  $form['actions']['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Save'),
+  );
+
+  return $form;
+}
