diff --git a/.gitignore b/.gitignore
index 6ad14d206163763202e8bc4ae8bd269c52bda931..f70efa66584272e181a6fadc9ee689cda535c22d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,6 +8,7 @@
 /conf/words.aspell
 /conf/lang/*
 /conf/plugin_lang/*
+/conf/plugins.local.*
 .htaccess
 *.swp
 *.bak
diff --git a/conf/plugins.protected.php b/conf/plugins.protected.php
new file mode 100644
index 0000000000000000000000000000000000000000..26eb8888b75bc29fea03f0d34dcbe042fa5690d3
--- /dev/null
+++ b/conf/plugins.protected.php
@@ -0,0 +1,11 @@
+<?php
+/**
+ * This file configures the enabled/disabled status of plugins, which are also protected
+ * from changes by the extention manager. These settings will override any local settings.
+ * It is not recommended to change this file, as it is overwritten on DokuWiki upgrades.
+ */
+$plugins['acl']         = 1;
+$plugins['plugin']      = 1;
+$plugins['config']      = 1;
+$plugins['usermanager'] = 1;
+$plugins['revert']      = 1;
diff --git a/inc/config_cascade.php b/inc/config_cascade.php
index 48ed5a000b36d77db56dfb2610089ade8b3d1775..c01778e99f552e8a1cbf48556ffcf5eb668f203a 100644
--- a/inc/config_cascade.php
+++ b/inc/config_cascade.php
@@ -64,6 +64,11 @@ $config_cascade = array_merge(
         'plainauth.users' => array(
             'default' => DOKU_CONF.'users.auth.php',
             ),
+        
+        'plugins' => array(
+            'local'     => array(DOKU_CONF.'plugins.local.php'),
+            'protected' => array(DOKU_CONF.'plugins.protected.php'),
+            ),
         ),
         $config_cascade
 );
diff --git a/inc/infoutils.php b/inc/infoutils.php
index 786661d01d69eb478ce3cf92bf126e875d6639a1..f1deec66b2d999ea325339edb4f0847216fef1d8 100644
--- a/inc/infoutils.php
+++ b/inc/infoutils.php
@@ -66,8 +66,8 @@ function getVersionData(){
             $chunk = fread($fh,2000);
             fclose($fh);
             $chunk = trim($chunk);
-            $chunk = array_pop(explode("\n",$chunk));   //last log line
-            $chunk = array_shift(explode("\t",$chunk)); //strip commit msg
+            $chunk = @array_pop(explode("\n",$chunk));   //last log line
+            $chunk = @array_shift(explode("\t",$chunk)); //strip commit msg
             $chunk = explode(" ",$chunk);
             array_pop($chunk); //strip timezone
             $date = date('Y-m-d',array_pop($chunk));
diff --git a/inc/lang/en/lang.php b/inc/lang/en/lang.php
index 6a02bbe0b6d6fb3cddf9f579418317c53bfe227a..ab6a88497084c0fda835cdfabd21bf77e106065e 100644
--- a/inc/lang/en/lang.php
+++ b/inc/lang/en/lang.php
@@ -361,4 +361,6 @@ $lang['js']['media_drop']       = 'Drop files here to upload';
 $lang['js']['media_cancel']     = 'remove';
 $lang['js']['media_overwrt']    = 'Overwrite existing files';
 
+$lang['plugin_install_err'] = "Plugin installed incorrectly. Rename plugin directory '%s' to '%s'.";
+
 //Setup VIM: ex: et ts=2 :
diff --git a/inc/plugincontroller.class.php b/inc/plugincontroller.class.php
index ea5725d47938b8d09460bdb18b1288ba3e6e4490..734331c94a6500823e0bd431292795c9e09a9153 100644
--- a/inc/plugincontroller.class.php
+++ b/inc/plugincontroller.class.php
@@ -11,11 +11,16 @@ if(!defined('DOKU_PLUGIN'))  define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
 
 class Doku_Plugin_Controller {
 
-    var $list_enabled = array();
-    var $list_disabled = array();
     var $list_bytype = array();
+    var $tmp_plugins = array();
+    var $plugin_cascade = array('default'=>array(),'local'=>array(),'protected'=>array());
+    var $last_local_config_file = '';
 
-    function Doku_Plugin_Controller() {
+    /**
+     * Populates the master list of plugins
+     */
+    function __construct() {
+        $this->loadConfig();
         $this->_populateMasterList();
     }
 
@@ -37,7 +42,7 @@ class Doku_Plugin_Controller {
 
         // request the complete list
         if (!$type) {
-            return $all ? array_merge($this->list_enabled,$this->list_disabled) : $this->list_enabled;
+            return $all ? array_keys($this->tmp_plugins) : array_keys(array_filter($this->tmp_plugins));
         }
 
         if (!isset($this->list_bytype[$type]['enabled'])) {
@@ -61,9 +66,11 @@ class Doku_Plugin_Controller {
      * @param  $disabled bool   true to load even disabled plugins
      * @return objectreference  the plugin object or null on failure
      */
-    function &load($type,$name,$new=false,$disabled=false){
+    function load($type,$name,$new=false,$disabled=false){
+
         //we keep all loaded plugins available in global scope for reuse
         global $DOKU_PLUGINS;
+        global $lang;
 
         list($plugin,$component) = $this->_splitName($name);
 
@@ -85,12 +92,12 @@ class Doku_Plugin_Controller {
 
         //construct class and instantiate
         if (!class_exists($class, true)) {
+
             # the plugin might be in the wrong directory
             $dir = $this->get_directory($plugin);
             $inf = confToHash(DOKU_PLUGIN."$dir/plugin.info.txt");
             if($inf['base'] && $inf['base'] != $plugin){
-                msg("Plugin installed incorrectly. Rename plugin directory '".
-                    hsc($plugin)."' to '".hsc($inf['base'])."'.",-1);
+                msg(sprintf($lang['plugin_install_err'],hsc($plugin),hsc($inf['base'])),-1);
             }
             return null;
         }
@@ -100,30 +107,28 @@ class Doku_Plugin_Controller {
     }
 
     function isdisabled($plugin) {
-        return (array_search($plugin, $this->list_enabled) === false);
+        return empty($this->tmp_plugins[$plugin]);
     }
 
-    function enable($plugin) {
-        if (array_search($plugin, $this->list_disabled) !== false) {
-            return @unlink(DOKU_PLUGIN.$plugin.'/disabled');
-        }
-        return false;
+    function disable($plugin) {
+        if(array_key_exists($plugin,$this->plugin_cascade['protected'])) return false;
+        $this->tmp_plugins[$plugin] = 0;
+        return $this->saveList();
     }
 
-    function disable($plugin) {
-        if (array_search($plugin, $this->list_enabled) !== false) {
-            return @touch(DOKU_PLUGIN.$plugin.'/disabled');
-        }
-        return false;
+    function enable($plugin) {
+        if(array_key_exists($plugin,$this->plugin_cascade['protected'])) return false;
+        $this->tmp_plugins[$plugin] = 1;
+        return $this->saveList();
     }
 
     function get_directory($plugin) {
         return $plugin;
     }
 
-    function _populateMasterList() {
-        global $conf;
-        if ($dh = opendir(DOKU_PLUGIN)) {
+    protected function _populateMasterList() {
+        if ($dh = @opendir(DOKU_PLUGIN)) {
+            $all_plugins = array();
             while (false !== ($plugin = readdir($dh))) {
                 if ($plugin[0] == '.') continue;               // skip hidden entries
                 if (is_file(DOKU_PLUGIN.$plugin)) continue;    // skip files, we're only interested in directories
@@ -132,19 +137,119 @@ class Doku_Plugin_Controller {
                     // the plugin was disabled by rc2009-01-26
                     // disabling mechanism was changed back very soon again
                     // to keep everything simple we just skip the plugin completely
-                }elseif(@file_exists(DOKU_PLUGIN.$plugin.'/disabled') ||
-                        ($plugin === 'plugin' && isset($conf['pluginmanager']) &&
-                         !$conf['pluginmanager'])){
-                    $this->list_disabled[] = $plugin;
+                } elseif (@file_exists(DOKU_PLUGIN.$plugin.'/disabled')) {
+                    // treat this as a default disabled plugin(over-rideable by the plugin manager)
+                    // deprecated 2011-09-10 (usage of disabled files)
+                    if (empty($this->plugin_cascade['local'][$plugin])) {
+                        $all_plugins[$plugin] = 0;
+                    } else {
+                        $all_plugins[$plugin] = 1;
+                    }
+                    $this->plugin_cascade['default'][$plugin] = 0;
+
+                } elseif ((array_key_exists($plugin,$this->tmp_plugins) && $this->tmp_plugins[$plugin] == 0) ||
+                          ($plugin === 'plugin' && isset($conf['pluginmanager']) && !$conf['pluginmanager'])){
+                    $all_plugins[$plugin] = 0;
+
+                } elseif ((array_key_exists($plugin,$this->tmp_plugins) && $this->tmp_plugins[$plugin] == 1)) {
+                    $all_plugins[$plugin] = 1;
                 } else {
-                    $this->list_enabled[] = $plugin;
+                    $all_plugins[$plugin] = 1;
                 }
             }
+            $this->tmp_plugins = $all_plugins;
+            if (!file_exists($this->last_local_config_file)) {
+                $this->saveList(true);
+            }
+        }
+    }
+
+    protected function checkRequire($files) {
+        $plugins = array();
+        foreach($files as $file) {
+            if(file_exists($file)) {
+                @include_once($file);
+            }
+        }
+        return $plugins;
+    }
+
+    function getCascade() {
+        return $this->plugin_cascade;
+    }
+
+    /**
+     * Save the current list of plugins
+     */
+    function saveList($forceSave = false) {
+        global $conf;
+
+        if (empty($this->tmp_plugins)) return false;
+
+        // Rebuild list of local settings
+        $local_plugins = $this->rebuildLocal();
+        if($local_plugins != $this->plugin_cascade['local'] || $forceSave) {
+            $file = $this->last_local_config_file;
+            $out = "<?php\n/*\n * Local plugin enable/disable settings\n * Auto-generated through plugin/extension manager\n *\n".
+                   " * NOTE: Plugins will not be added to this file unless there is a need to override a default setting. Plugins are\n".
+                   " *       enabled by default, unless having a 'disabled' file in their plugin folder.\n */\n";
+            foreach ($local_plugins as $plugin => $value) {
+                $out .= "\$plugins['$plugin'] = $value;\n";
+            }
+            // backup current file (remove any existing backup)
+            if (@file_exists($file)) {
+                $backup = $file.'.bak';
+                if (@file_exists($backup)) @unlink($backup);
+                if (!@copy($file,$backup)) return false;
+                if ($conf['fperm']) chmod($backup, $conf['fperm']);
+            }
+            //check if can open for writing, else restore
+            return io_saveFile($file,$out);
+        }
+        return false;
+    }
+
+    /**
+     * Rebuild the set of local plugins
+     * @return array array of plugins to be saved in end($config_cascade['plugins']['local'])
+     */
+    function rebuildLocal() {
+        //assign to local variable to avoid overwriting
+        $backup = $this->tmp_plugins;
+        //Can't do anything about protected one so rule them out completely
+        $local_default = array_diff_key($backup,$this->plugin_cascade['protected']);
+        //Diff between local+default and default
+        //gives us the ones we need to check and save
+        $diffed_ones = array_diff_key($local_default,$this->plugin_cascade['default']);
+        //The ones which we are sure of (list of 0s not in default)
+        $sure_plugins = array_filter($diffed_ones,array($this,'negate'));
+        //the ones in need of diff
+        $conflicts = array_diff_key($local_default,$diffed_ones);
+        //The final list
+        return array_merge($sure_plugins,array_diff_assoc($conflicts,$this->plugin_cascade['default']));
+    }
+
+    /**
+     * Build the list of plugins and cascade
+     * 
+     */
+    function loadConfig() {
+        global $config_cascade;
+        foreach(array('default','protected') as $type) {
+            if(array_key_exists($type,$config_cascade['plugins']))
+                $this->plugin_cascade[$type] = $this->checkRequire($config_cascade['plugins'][$type]);
         }
+        $local = $config_cascade['plugins']['local'];
+        $this->last_local_config_file = array_pop($local);
+        $this->plugin_cascade['local'] = $this->checkRequire(array($this->last_local_config_file));
+        if(is_array($local)) {
+            $this->plugin_cascade['default'] = array_merge($this->plugin_cascade['default'],$this->checkRequire($local));
+        }
+        $this->tmp_plugins = array_merge($this->plugin_cascade['default'],$this->plugin_cascade['local'],$this->plugin_cascade['protected']);
     }
 
     function _getListByType($type, $enabled) {
-        $master_list = $enabled ? $this->list_enabled : $this->list_disabled;
+        $master_list = $enabled ? array_keys(array_filter($this->tmp_plugins)) : array_keys(array_filter($this->tmp_plugins,array($this,'negate')));
 
         $plugins = array();
         foreach ($master_list as $plugin) {
@@ -169,11 +274,13 @@ class Doku_Plugin_Controller {
     }
 
     function _splitName($name) {
-        if (array_search($name, $this->list_enabled + $this->list_disabled) === false) {
+        if (array_search($name, array_keys($this->tmp_plugins)) === false) {
             return explode('_',$name,2);
         }
 
         return array($name,'');
     }
-
+    function negate($input) {
+        return !(bool) $input;
+    }
 }
diff --git a/inc/pluginutils.php b/inc/pluginutils.php
index 85bcaee1e80b09dcfb234b718a65d1503e7a2a95..53cfedf82b6edeb7df2c2efdcfb28205df9f3507 100644
--- a/inc/pluginutils.php
+++ b/inc/pluginutils.php
@@ -16,7 +16,7 @@ function plugin_list($type='',$all=false) {
     global $plugin_controller;
     return $plugin_controller->getList($type,$all);
 }
-function &plugin_load($type,$name,$new=false,$disabled=false) {
+function plugin_load($type,$name,$new=false,$disabled=false) {
     global $plugin_controller;
     return $plugin_controller->load($type,$name,$new,$disabled);
 }
@@ -36,3 +36,7 @@ function plugin_directory($plugin) {
     global $plugin_controller;
     return $plugin_controller->get_directory($plugin);
 }
+function plugin_getcascade() {
+    global $plugin_controller;
+    return $plugin_controller->getCascade();
+}
diff --git a/lib/plugins/acl/admin.php b/lib/plugins/acl/admin.php
index 53f6db0cc99ebd0d0f427335e45bce23ff6117b9..a6b0624bce42a9e83da72e7bfdb9bceedb62c49a 100644
--- a/lib/plugins/acl/admin.php
+++ b/lib/plugins/acl/admin.php
@@ -30,20 +30,6 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
     var $usersgroups = array();
     var $specials = array();
 
-    /**
-     * return some info
-     */
-    function getInfo(){
-        return array(
-            'author' => 'Andreas Gohr',
-            'email'  => 'andi@splitbrain.org',
-            'date'   => '2011-04-16',
-            'name'   => 'ACL Manager',
-            'desc'   => 'Manage Page Access Control Lists',
-            'url'    => 'http://dokuwiki.org/plugin:acl',
-        );
-    }
-
     /**
      * return prompt for admin menu
      */
diff --git a/lib/plugins/acl/plugin.info.txt b/lib/plugins/acl/plugin.info.txt
new file mode 100644
index 0000000000000000000000000000000000000000..f108a239068ae11190e952aef725ff40befcce28
--- /dev/null
+++ b/lib/plugins/acl/plugin.info.txt
@@ -0,0 +1,6 @@
+author Andreas Gohr
+email  andi@splitbrain.org
+date   2011-04-16
+name   ACL Manager
+desc   Manage Page Access Control Lists
+url    http://dokuwiki.org/plugin:acl
diff --git a/lib/plugins/config/admin.php b/lib/plugins/config/admin.php
index e24f3b87b3c3d146aa900533cd4e07f2831198af..64906171d3340ceb85da8270ab02bb693a48dfb2 100644
--- a/lib/plugins/config/admin.php
+++ b/lib/plugins/config/admin.php
@@ -32,21 +32,6 @@ class admin_plugin_config extends DokuWiki_Admin_Plugin {
     var $_session_started = false;
     var $_localised_prompts = false;
 
-    /**
-     * return some info
-     */
-    function getInfo(){
-
-      return array(
-        'author' => 'Christopher Smith',
-        'email'  => 'chris@jalakai.co.uk',
-        'date'   => '2007-08-05',
-        'name'   => 'Configuration Manager',
-        'desc'   => "Manage Dokuwiki's Configuration Settings",
-        'url'    => 'http://dokuwiki.org/plugin:config',
-      );
-    }
-
     function getMenuSort() { return 100; }
 
     /**
diff --git a/lib/plugins/config/plugin.info.txt b/lib/plugins/config/plugin.info.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ace4889b6c4f8a147dfa617eea5a570eed4dc087
--- /dev/null
+++ b/lib/plugins/config/plugin.info.txt
@@ -0,0 +1,6 @@
+author Christopher Smith
+email  chris@jalakai.co.uk
+date   2007-08-05
+name   Configuration Manager
+desc   Manage Dokuwiki's Configuration Settings
+url    http://dokuwiki.org/plugin:config
diff --git a/lib/plugins/info/plugin.info.txt b/lib/plugins/info/plugin.info.txt
new file mode 100644
index 0000000000000000000000000000000000000000..2432225f1f744564101bb38136f9a6961c8c0431
--- /dev/null
+++ b/lib/plugins/info/plugin.info.txt
@@ -0,0 +1,6 @@
+author Andreas Gohr
+email andi@splitbrain.org
+date 2008-09-12
+name Info Plugin
+desc Displays information about various DokuWiki internals
+url http://dokuwiki.org/plugin:info
diff --git a/lib/plugins/revert/admin.php b/lib/plugins/revert/admin.php
index e188e2488d363f636289daf3273bd2756d860366..2aaf1395f6f6bbac99fbf32fbad904f61bf0e526 100644
--- a/lib/plugins/revert/admin.php
+++ b/lib/plugins/revert/admin.php
@@ -20,20 +20,6 @@ class admin_plugin_revert extends DokuWiki_Admin_Plugin {
         $this->setupLocale();
     }
 
-    /**
-     * return some info
-     */
-    function getInfo(){
-        return array(
-            'author' => 'Andreas Gohr',
-            'email'  => 'andi@splitbrain.org',
-            'date'   => '2008-12-10',
-            'name'   => 'Revert Manager',
-            'desc'   => 'Allows you to mass revert recent edits',
-            'url'    => 'http://dokuwiki.org/plugin:revert',
-        );
-    }
-
     /**
      * access for managers
      */
diff --git a/lib/plugins/revert/plugin.info.txt b/lib/plugins/revert/plugin.info.txt
new file mode 100644
index 0000000000000000000000000000000000000000..5bb6f34138303e9c62a980c16b69fec0e0cfb073
--- /dev/null
+++ b/lib/plugins/revert/plugin.info.txt
@@ -0,0 +1,6 @@
+author Andreas Gohr
+email  andi@splitbrain.org
+date   2008-12-10
+name   Revert Manager
+desc   Allows you to mass revert recent edits
+url    http://dokuwiki.org/plugin:revert
diff --git a/lib/plugins/usermanager/admin.php b/lib/plugins/usermanager/admin.php
index e40ee9b7e69a58aa6bd05c8e2d1f2b5edc64d8e2..8e90be0935e48d0c74ef2c9b79d15eed5192904f 100644
--- a/lib/plugins/usermanager/admin.php
+++ b/lib/plugins/usermanager/admin.php
@@ -51,20 +51,6 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
         }
     }
 
-    /**
-     * return some info
-     */
-    function getInfo(){
-
-        return array(
-            'author' => 'Chris Smith',
-            'email'  => 'chris@jalakai.co.uk',
-            'date'   => '2008-09-17',
-            'name'   => 'User Manager',
-            'desc'   => 'Manage users '.$this->disabled,
-            'url'    => 'http://dokuwiki.org/plugin:usermanager',
-        );
-    }
      /**
      * return prompt for admin menu
      */
diff --git a/lib/plugins/usermanager/plugin.info.txt b/lib/plugins/usermanager/plugin.info.txt
new file mode 100644
index 0000000000000000000000000000000000000000..7ec5fafd52558c1a9dc2aeadd4f774501d0aa51d
--- /dev/null
+++ b/lib/plugins/usermanager/plugin.info.txt
@@ -0,0 +1,6 @@
+author Chris Smith
+email  chris@jalakai.co.uk
+date   2008-09-17
+name   User Manager
+desc   Manage users 
+url    http://dokuwiki.org/plugin:usermanager