diff --git a/include/class.plugin.php b/include/class.plugin.php
index 5a29ce483be7aa0797165d8430ac70a25d33fb89..d553e5e224c0c018fafda2f4e2a10f0844f9bff3 100644
--- a/include/class.plugin.php
+++ b/include/class.plugin.php
@@ -22,6 +22,10 @@ class PluginConfig extends Config {
         return array();
     }
 
+    function hasCustomConfig() {
+        return $this instanceof PluginCustomConfig;
+    }
+
     /**
      * Retreive a Form instance for the configurable options offered in
      * ::getOptions
@@ -55,6 +59,15 @@ class PluginConfig extends Config {
      * array.
      */
     function commit(&$errors=array()) {
+        global $msg;
+
+        if ($this->hasCustomConfig())
+            return $this->saveCustomConfig($errors);
+
+        return $this->commitForm($errors);
+    }
+
+    function commitForm(&$errors=array()) {
         $f = $this->getForm();
         $commit = false;
         if ($f->isValid()) {
@@ -68,7 +81,11 @@ class PluginConfig extends Config {
                 $field = $f->getField($name);
                 $dbready[$name] = $field->to_database($val);
             }
-            return $this->updateAll($dbready);
+            if ($this->updateAll($dbready)) {
+                if (!$msg)
+                    $msg = 'Successfully updated configuration';
+                return true;
+            }
         }
         return false;
     }
@@ -93,6 +110,20 @@ class PluginConfig extends Config {
     }
 }
 
+/**
+ * Interface: PluginCustomConfig
+ *
+ * Allows a plugin to specify custom configuration pages. If the
+ * configuration cannot be suited by a single page, single form, then
+ * the plugin can use the ::renderCustomConfig() method to trigger
+ * rendering the page, and use ::saveCustomConfig() to trigger
+ * validating and saving the custom configuration.
+ */
+interface PluginCustomConfig {
+    function renderCustomConfig();
+    function saveCustomConfig();
+}
+
 class PluginManager {
     static private $plugin_info = array();
     static private $plugin_list = array();
diff --git a/include/staff/plugin.inc.php b/include/staff/plugin.inc.php
index 4ec565da3565d2489878910a58053bba6b7a08ce..f76b0f27c749e889b0a8170875798a3d2f932292 100644
--- a/include/staff/plugin.inc.php
+++ b/include/staff/plugin.inc.php
@@ -3,10 +3,12 @@
 $info=array();
 if($plugin && $_REQUEST['a']!='add') {
     $config = $plugin->getConfig();
-    if ($config)
-        $form = $config->getForm();
-    if ($_POST)
-        $form->isValid();
+    if (!($page = $config->hasCustomConfig())) {
+        if ($config)
+            $form = $config->getForm();
+        if ($form && $_POST)
+            $form->isValid();
+    }
     $title = __('Update Plugin');
     $action = 'update';
     $submit_text = __('Save Changes');
@@ -23,19 +25,23 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
         <br/><small><?php echo $plugin->getName(); ?></small></h2>
 
     <h3><?php echo __('Configuration'); ?></h3>
+<?php
+if ($page)
+    $config->renderCustomConfig();
+elseif ($form) { ?>
     <table class="form_table" width="940" border="0" cellspacing="0" cellpadding="2">
     <tbody>
+<?php $form->render(); ?>
+    </tbody></table>
 <?php
-if ($form)
-    $form->render();
+}
 else { ?>
     <tr><th><?php echo __('This plugin has no configurable settings'); ?><br>
         <em><?php echo __('Every plugin should be so easy to use.'); ?></em></th></tr>
 <?php }
 ?>
-    </tbody></table>
 <p class="centered">
-<?php if ($form) { ?>
+<?php if ($page || $form) { ?>
     <input type="submit" name="submit" value="<?php echo $submit_text; ?>">
     <input type="reset"  name="reset"  value="<?php echo __('Reset'); ?>">
 <?php } ?>