Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/261 #71

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions quick-cache-pro/includes/menu-pages.php
Original file line number Diff line number Diff line change
Expand Up @@ -136,16 +136,16 @@ public function options()
echo '<div class="plugin-menu-page-panel">'."\n";

echo ' <div class="plugin-menu-page-panel-heading">'."\n";
echo ' <i class="fa fa-shield"></i> '.__('Deactivation Safeguards', $this->plugin->text_domain)."\n";
echo ' <i class="fa fa-shield"></i> '.__('Plugin Deletion Safeguards', $this->plugin->text_domain)."\n";
echo ' </div>'."\n";

echo ' <div class="plugin-menu-page-panel-body clearfix">'."\n";
echo ' <i class="fa fa-shield fa-4x" style="float:right; margin: 0 0 0 25px;"></i>'."\n";
echo ' <h3>'.__('Uninstall on Deactivation; or Safeguard Options?', $this->plugin->text_domain).'</h3>'."\n";
echo ' <p>'.__('<strong>Tip:</strong> By default, if you deactivate Quick Cache from the plugins menu in WordPress; nothing is lost. However, if you want to uninstall Quick Cache you should set this to <code>Yes</code> and <strong>THEN</strong> deactivate it from the plugins menu in WordPress. This way Quick Cache will erase your options for the plugin, clear the cache, remove the <code>advanced-cache.php</code> file, terminate CRON jobs, etc. It erases itself from existence completely.', $this->plugin->text_domain).'</p>'."\n";
echo ' <p><select name="'.esc_attr(__NAMESPACE__).'[save_options][uninstall_on_deactivation]">'."\n";
echo ' <option value="0"'.selected($this->plugin->options['uninstall_on_deactivation'], '0', FALSE).'>'.__('If I deactivate Quick Cache please safeguard my options and the cache (recommended).', $this->plugin->text_domain).'</option>'."\n";
echo ' <option value="1"'.selected($this->plugin->options['uninstall_on_deactivation'], '1', FALSE).'>'.__('Yes, uninstall (completely erase) Quick Cache on deactivation.', $this->plugin->text_domain).'</option>'."\n";
echo ' <h3>'.__('Uninstall on Plugin Deletion; or Safeguard Options?', $this->plugin->text_domain).'</h3>'."\n";
echo ' <p>'.__('<strong>Tip:</strong> By default, if you delete Quick Cache using the plugins menu in WordPress, nothing is lost. However, if you want to completely uninstall Quick Cache you should set this to <code>Yes</code> and <strong>THEN</strong> deactivate &amp; delete Quick Cache from the plugins menu in WordPress. This way Quick Cache will erase your options for the plugin, erase directories/files created by the plugin, remove the <code>advanced-cache.php</code> file, terminate CRON jobs, etc. It erases itself from existence completely.', $this->plugin->text_domain).'</p>'."\n";
echo ' <p><select name="'.esc_attr(__NAMESPACE__).'[save_options][uninstall_on_deletion]">'."\n";
echo ' <option value="0"'.selected($this->plugin->options['uninstall_on_deletion'], '0', FALSE).'>'.__('Safeguard my options and the cache (recommended).', $this->plugin->text_domain).'</option>'."\n";
echo ' <option value="1"'.selected($this->plugin->options['uninstall_on_deletion'], '1', FALSE).'>'.__('Yes, uninstall (completely erase) Quick Cache on plugin deletion.', $this->plugin->text_domain).'</option>'."\n";
echo ' </select></p>'."\n";
echo ' </div>'."\n";

Expand Down
113 changes: 102 additions & 11 deletions quick-cache-pro/quick-cache-pro.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,16 @@ class plugin extends share
*/
public $network_cap = '';

/**
* Uninstall capability requirement.
*
* @since 14xxxx Adding uninstall handler.
*
* @var string WordPress capability required to
* completely uninstall/delete QC.
*/
public $uninstall_cap = '';

/**
* Cache directory.
*
Expand Down Expand Up @@ -119,16 +129,31 @@ class plugin extends share
*/
public $cache = array();

/**
* Used by the plugin's uninstall handler.
*
* @since 14xxxx Adding uninstall handler.
*
* @var boolean If FALSE, run without any hooks.
*/
public $enable_hooks = TRUE;

/**
* Quick Cache plugin constructor.
*
* @param boolean $enable_hooks Defaults to a TRUE value.
* If FALSE, setup runs but without adding any hooks.
*
* @since 140422 First documented version.
*/
public function __construct()
public function __construct($enable_hooks = TRUE)
{
parent::__construct(); // Shared constructor.

$this->file = preg_replace('/\.inc\.php$/', '.php', __FILE__);
$this->enable_hooks = (boolean)$enable_hooks;
$this->file = preg_replace('/\.inc\.php$/', '.php', __FILE__);

if(!$this->enable_hooks) return; // All done in this case.

add_action('after_setup_theme', array($this, 'setup'));
register_activation_hook($this->file, array($this, 'activate'));
Expand All @@ -142,7 +167,8 @@ public function __construct()
*/
public function setup()
{
do_action('before__'.__METHOD__, get_defined_vars());
if($this->enable_hooks) // Hooks enabled?
do_action('before__'.__METHOD__, get_defined_vars());

load_plugin_textdomain($this->text_domain);

Expand Down Expand Up @@ -195,7 +221,7 @@ public function setup()
'htmlc_compress_html_code' => '1', // `0|1`.

'change_notifications_enable' => '1', // `0|1`.
'uninstall_on_deactivation' => '0', // `0|1`.
'uninstall_on_deletion' => '0', // `0|1`.

'auto_cache_enable' => '0', // `0|1`.
'auto_cache_sitemap_url' => 'sitemap.xml', // Relative to `site_url()`.
Expand Down Expand Up @@ -250,9 +276,12 @@ public function setup()
if(!$this->options['base_dir']) // Security enhancement; NEVER allow this to be empty.
$this->options['base_dir'] = $this->default_options['base_dir'];

$this->cap = apply_filters(__METHOD__.'__cap', 'activate_plugins');
$this->network_cap = apply_filters(__METHOD__.'__network_cap', 'manage_network_plugins');
$this->update_cap = apply_filters(__METHOD__.'__update_cap', 'update_plugins');
$this->cap = apply_filters(__METHOD__.'__cap', 'activate_plugins');
$this->update_cap = apply_filters(__METHOD__.'__update_cap', 'update_plugins');
$this->network_cap = apply_filters(__METHOD__.'__network_cap', 'manage_network_plugins');
$this->uninstall_cap = apply_filters(__METHOD__.'__uninstall_cap', 'delete_plugins');

if(!$this->enable_hooks) return; // Stop here; setup without hooks.

add_action('init', array($this, 'check_advanced_cache'));
add_action('init', array($this, 'check_blog_paths'));
Expand Down Expand Up @@ -418,11 +447,35 @@ public function deactivate()
$this->remove_wp_cache_from_wp_config();
$this->remove_advanced_cache();
$this->clear_cache();
}

/**
* Plugin uninstall hook.
*
* @since 14xxxx Adding uninstall handler.
*
* @attaches-to {@link \register_uninstall_hook()} ~ via {@link uninstall()}
*/
public function uninstall()
{
if(!current_user_can($this->uninstall_cap))
return; // Extra layer of security.

if(!$this->options['uninstall_on_deactivation'])
if(!class_exists('\\'.__NAMESPACE__.'\\uninstall'))
return; // Expecting the uninstall class.

if(!defined('WP_UNINSTALL_PLUGIN'))
return; // Disallow.

$this->remove_wp_cache_from_wp_config();
$this->remove_advanced_cache();
$this->wipe_cache();

if(!$this->options['uninstall_on_deletion'])
return; // Nothing to do here.

$this->delete_advanced_cache();
$this->remove_base_dir();

delete_option(__NAMESPACE__.'_options');
if(is_multisite()) // Delete network options too.
Expand Down Expand Up @@ -2600,6 +2653,44 @@ public function update_blog_paths($enable_live_network_counts = NULL)
}
return $value; // Pass through untouched (always).
}

/**
* Removes the entire base directory.
*
* @since 14xxx First documented version.
*
* @return integer Total files removed by this routine (if any).
*
* @throws \exception If a wipe failure occurs.
*/
public function remove_base_dir()
{
$counter = 0; // Initialize.

// @TODO When set_time_limit() is disabled by PHP configuration, display a warning message to users upon plugin activation.
@set_time_limit(1800); // In case of HUGE sites w/ a very large directory. Errors are ignored in case `set_time_limit()` is disabled.

$base_dir = $this->wp_content_dir_to(''); // Simply the base directory.

/** @var $_dir_file \RecursiveDirectoryIterator For IDEs. */
if($base_dir && is_dir($base_dir)) foreach($this->dir_regex_iteration($base_dir, '/.+/') as $_dir_file)
{
if(($_dir_file->isFile() || $_dir_file->isLink()))
if(!unlink($_dir_file->getPathname())) // Throw exception if unable to delete.
throw new \exception(sprintf(__('Unable to remove file: `%1$s`.', $this->text_domain), $_dir_file->getPathname()));
else $counter++; // Increment counter for each file we wipe.

else if($_dir_file->isDir())
if(!rmdir($_dir_file->getPathname())) // Throw exception if unable to delete.
throw new \exception(sprintf(__('Unable to remove dir: `%1$s`.', $this->text_domain), $_dir_file->getPathname()));
}
unset($_dir_file); // Just a little housekeeping.

if(is_dir($base_dir) && !rmdir($base_dir)) // Throw exception if unable to delete.
throw new \exception(sprintf(__('Unable to remove base dir: `%1$s`.', $this->text_domain), $base_dir));

return $counter; // Total removals.
}
}

/**
Expand All @@ -2620,15 +2711,15 @@ function plugin() // Easy reference.
*
* @since 140422 First documented version.
*
* @var plugin $GLOBALS [__NAMESPACE__]
* @var plugin Main plugin class.
*/
$GLOBALS[__NAMESPACE__] = new plugin(); // New plugin instance.
$GLOBALS[__NAMESPACE__] = new plugin(!class_exists('\\'.__NAMESPACE__.'\\uninstall'));
/*
* API class inclusion; depends on {@link $GLOBALS[__NAMESPACE__]}.
*/
require_once dirname(__FILE__).'/includes/api-class.php';
}
else add_action('all_admin_notices', function () // Do NOT load in this case.
else if(!class_exists('\\'.__NAMESPACE__.'\\uninstall')) add_action('all_admin_notices', function ()
{
echo '<div class="error"><p>'. // Running multiple versions of this plugin at same time.
__('Please disable the LITE version of Quick Cache before you activate the PRO version.',
Expand Down
2 changes: 1 addition & 1 deletion quick-cache-pro/quick-cache-pro.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@

if(require(dirname(__FILE__).'/includes/wp-php53.php')) // TRUE if running PHP v5.3+.
require_once dirname(__FILE__).'/quick-cache-pro.inc.php';
else wp_php53_notice('Quick Cache Pro');
else wp_php53_notice('Quick Cache Pro');
43 changes: 43 additions & 0 deletions quick-cache-pro/uninstall.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php
/**
* Quick Cache Uninstaller
*
* @package quick_cache\uninstall
* @since 14xxxx Adding plugin uninstaller.
* @copyright WebSharks, Inc. <http://www.websharks-inc.com>
* @license GNU General Public License, version 2
*/
namespace quick_cache
{
if(!defined('WPINC')) // MUST have WordPress.
exit('Do NOT access this file directly: '.basename(__FILE__));

require_once dirname(__FILE__).'/quick-cache-pro.inc.php';

if(!class_exists('\\'.__NAMESPACE__.'\\uninstall'))
{
class uninstall // Uninstall handler.
{
/**
* @since 14xxxx Adding uninstaller.
*
* @var plugin Primary plugin class instance.
*/
protected $plugin; // Set by constructor.

/**
* Uninstall constructor.
*
* @since 14xxxx Adding uninstall handler.
*/
public function __construct()
{
$this->plugin = plugin( /* Without hooks. */);
$this->plugin->setup( /* Without hooks. */);
$this->plugin->uninstall();
}
}

new uninstall(); // Run the uninstaller.
}
}