| 1 |
<?php |
| 2 |
/** |
| 3 |
* Plugin Name: Plugin Detective - Troubleshooting |
| 4 |
* Plugin URI: https://nsquared.io |
| 5 |
* Description: Quickly troubleshoot & fix plugin conflicts |
| 6 |
* Version: 1.2.9 |
| 7 |
* Author: NSquared |
| 8 |
* Donate link: https://nsquared.io |
| 9 |
* License: GPLv2 |
| 10 |
* Text Domain: plugin-detective |
| 11 |
* Domain Path: /languages |
| 12 |
* |
| 13 |
* @link https://nsquared.io |
| 14 |
* |
| 15 |
* @package Plugin_Detective |
| 16 |
* @version 1.2.9 |
| 17 |
* |
| 18 |
* Built using generator-plugin-wp (https://github.com/WebDevStudios/generator-plugin-wp) |
| 19 |
*/ |
| 20 |
|
| 21 |
/** |
| 22 |
* Copyright (c) 2018 NSquared (email : support@nsqua.red) |
| 23 |
* |
| 24 |
* This program is free software; you can redistribute it and/or modify |
| 25 |
* it under the terms of the GNU General Public License, version 2 or, at |
| 26 |
* your discretion, any later version, as published by the Free |
| 27 |
* Software Foundation. |
| 28 |
* |
| 29 |
* This program is distributed in the hope that it will be useful, |
| 30 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 31 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 32 |
* GNU General Public License for more details. |
| 33 |
* |
| 34 |
* You should have received a copy of the GNU General Public License |
| 35 |
* along with this program; if not, write to the Free Software |
| 36 |
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| 37 |
*/ |
| 38 |
|
| 39 |
|
| 40 |
/** |
| 41 |
* Autoloads files with classes when needed. |
| 42 |
* |
| 43 |
* @since 0.0.0 |
| 44 |
* @param string $class_name Name of the class being requested. |
| 45 |
*/ |
| 46 |
function plugin_detective_autoload_classes( $class_name ) { |
| 47 |
|
| 48 |
// If our class doesn't have our prefix, don't load it. |
| 49 |
if ( 0 !== strpos( $class_name, 'PD_' ) ) { |
| 50 |
return; |
| 51 |
} |
| 52 |
|
| 53 |
// Set up our filename. |
| 54 |
$filename = strtolower( str_replace( '_', '-', substr( $class_name, strlen( 'PD_' ) ) ) ); |
| 55 |
|
| 56 |
// Include our file. |
| 57 |
Plugin_Detective::include_file( 'includes/class-' . $filename ); |
| 58 |
} |
| 59 |
spl_autoload_register( 'plugin_detective_autoload_classes' ); |
| 60 |
|
| 61 |
/** |
| 62 |
* Main initiation class. |
| 63 |
* |
| 64 |
* @since 0.0.0 |
| 65 |
*/ |
| 66 |
final class Plugin_Detective { |
| 67 |
|
| 68 |
/** |
| 69 |
* Current version. |
| 70 |
* |
| 71 |
* @var string |
| 72 |
* @since 0.0.0 |
| 73 |
*/ |
| 74 |
const VERSION = '1.2.9'; |
| 75 |
|
| 76 |
/** |
| 77 |
* URL of plugin directory. |
| 78 |
* |
| 79 |
* @var string |
| 80 |
* @since 0.0.0 |
| 81 |
*/ |
| 82 |
protected $url = ''; |
| 83 |
|
| 84 |
/** |
| 85 |
* Path of plugin directory. |
| 86 |
* |
| 87 |
* @var string |
| 88 |
* @since 0.0.0 |
| 89 |
*/ |
| 90 |
protected $path = ''; |
| 91 |
|
| 92 |
/** |
| 93 |
* Plugin basename. |
| 94 |
* |
| 95 |
* @var string |
| 96 |
* @since 0.0.0 |
| 97 |
*/ |
| 98 |
protected $basename = ''; |
| 99 |
|
| 100 |
/** |
| 101 |
* Detailed activation error messages. |
| 102 |
* |
| 103 |
* @var array |
| 104 |
* @since 0.0.0 |
| 105 |
*/ |
| 106 |
protected $activation_errors = array(); |
| 107 |
|
| 108 |
/** |
| 109 |
* Singleton instance of plugin. |
| 110 |
* |
| 111 |
* @var Plugin_Detective |
| 112 |
* @since 0.0.0 |
| 113 |
*/ |
| 114 |
protected static $single_instance = null; |
| 115 |
|
| 116 |
/** |
| 117 |
* Creates or returns an instance of this class. |
| 118 |
* |
| 119 |
* @since 0.0.0 |
| 120 |
* @return Plugin_Detective A single instance of this class. |
| 121 |
*/ |
| 122 |
public static function get_instance() { |
| 123 |
if ( null === self::$single_instance ) { |
| 124 |
self::$single_instance = new self(); |
| 125 |
} |
| 126 |
|
| 127 |
return self::$single_instance; |
| 128 |
} |
| 129 |
|
| 130 |
/** |
| 131 |
* Sets up our plugin. |
| 132 |
* |
| 133 |
* @since 0.0.0 |
| 134 |
*/ |
| 135 |
protected function __construct() { |
| 136 |
$this->basename = plugin_basename( __FILE__ ); |
| 137 |
$this->url = plugin_dir_url( __FILE__ ); |
| 138 |
$this->path = plugin_dir_path( __FILE__ ); |
| 139 |
} |
| 140 |
|
| 141 |
/** |
| 142 |
* Attach other plugin classes to the base plugin class. |
| 143 |
* |
| 144 |
* @since 0.0.0 |
| 145 |
*/ |
| 146 |
public function plugin_classes() { |
| 147 |
$this->wp_admin = new PD_Wp_Admin( $this ); |
| 148 |
} // END OF PLUGIN CLASSES FUNCTION |
| 149 |
|
| 150 |
/** |
| 151 |
* Add hooks and filters. |
| 152 |
* Priority needs to be |
| 153 |
* < 10 for CPT_Core, |
| 154 |
* < 5 for Taxonomy_Core, |
| 155 |
* and 0 for Widgets because widgets_init runs at init priority 1. |
| 156 |
* |
| 157 |
* @since 0.0.0 |
| 158 |
*/ |
| 159 |
public function hooks() { |
| 160 |
add_action( 'init', array( $this, 'init' ), 0 ); |
| 161 |
} |
| 162 |
|
| 163 |
/** |
| 164 |
* Activate the plugin. |
| 165 |
* |
| 166 |
* @since 0.0.0 |
| 167 |
*/ |
| 168 |
public function _activate() { |
| 169 |
// Bail early if requirements aren't met. |
| 170 |
if ( ! $this->check_requirements() ) { |
| 171 |
return; |
| 172 |
} |
| 173 |
|
| 174 |
// Make sure any rewrite functionality has been loaded. |
| 175 |
flush_rewrite_rules(); |
| 176 |
} |
| 177 |
|
| 178 |
/** |
| 179 |
* Deactivate the plugin. |
| 180 |
* Uninstall routines should be in uninstall.php. |
| 181 |
* |
| 182 |
* @since 0.0.0 |
| 183 |
*/ |
| 184 |
public function _deactivate() { |
| 185 |
// Add deactivation cleanup functionality here. |
| 186 |
} |
| 187 |
|
| 188 |
/** |
| 189 |
* Init hooks |
| 190 |
* |
| 191 |
* @since 0.0.0 |
| 192 |
*/ |
| 193 |
public function init() { |
| 194 |
|
| 195 |
// Bail early if requirements aren't met. |
| 196 |
if ( ! $this->check_requirements() ) { |
| 197 |
return; |
| 198 |
} |
| 199 |
|
| 200 |
// Load translated strings for plugin. |
| 201 |
load_plugin_textdomain( 'plugin-detective', false, dirname( $this->basename ) . '/languages/' ); |
| 202 |
|
| 203 |
// Initialize plugin classes. |
| 204 |
$this->plugin_classes(); |
| 205 |
} |
| 206 |
|
| 207 |
/** |
| 208 |
* Check if the plugin meets requirements and |
| 209 |
* disable it if they are not present. |
| 210 |
* |
| 211 |
* @since 0.0.0 |
| 212 |
* |
| 213 |
* @return boolean True if requirements met, false if not. |
| 214 |
*/ |
| 215 |
public function check_requirements() { |
| 216 |
|
| 217 |
// Bail early if plugin meets requirements. |
| 218 |
if ( $this->meets_requirements() ) { |
| 219 |
return true; |
| 220 |
} |
| 221 |
|
| 222 |
// Add a dashboard notice. |
| 223 |
add_action( 'all_admin_notices', array( $this, 'requirements_not_met_notice' ) ); |
| 224 |
|
| 225 |
// Deactivate our plugin. |
| 226 |
add_action( 'admin_init', array( $this, 'deactivate_me' ) ); |
| 227 |
|
| 228 |
// Didn't meet the requirements. |
| 229 |
return false; |
| 230 |
} |
| 231 |
|
| 232 |
/** |
| 233 |
* Deactivates this plugin, hook this function on admin_init. |
| 234 |
* |
| 235 |
* @since 0.0.0 |
| 236 |
*/ |
| 237 |
public function deactivate_me() { |
| 238 |
|
| 239 |
// We do a check for deactivate_plugins before calling it, to protect |
| 240 |
// any developers from accidentally calling it too early and breaking things. |
| 241 |
if ( function_exists( 'deactivate_plugins' ) ) { |
| 242 |
deactivate_plugins( $this->basename ); |
| 243 |
} |
| 244 |
} |
| 245 |
|
| 246 |
/** |
| 247 |
* Check that all plugin requirements are met. |
| 248 |
* |
| 249 |
* @since 0.0.0 |
| 250 |
* |
| 251 |
* @return boolean True if requirements are met. |
| 252 |
*/ |
| 253 |
public function meets_requirements() { |
| 254 |
|
| 255 |
// Do checks for required classes / functions or similar. |
| 256 |
// Add detailed messages to $this->activation_errors array. |
| 257 |
if ( defined( 'MULTISITE' ) && MULTISITE || ( function_exists( 'is_multsite' ) && is_multsite() ) ) { |
| 258 |
$this->activation_errors[] = '<h3>Plugin Detective doesn\'t support multisite (yet)</h3> |
| 259 |
<p>Unfortunately we don\'t support multisite yet. We wanted to get Plugin Detective out there for people to use as soon as possible, but there’s a good amount of work to do before it will support multisite. As you may know, multisite can get a bit complicated.</p> |
| 260 |
|
| 261 |
<p>With a single install, it’s easy to determine which plugins are active and manipulate them. With a multisite, there are network-activated plugins and plugins at the site level. And theoretically Plugin Detective could be run the whole network, or just looking at a single site. And there are permission differences between a network admin and a site admin. So it will take some work for us to support all that. We want to see how much interest there is in supporting multisite, and get some feedback from multisite users to understand what would be most useful for them and how they’d use it.</p> |
| 262 |
|
| 263 |
<p><strong>If you\'re reading this, you likely want to use Plugin Detective to troubleshoot multisite installs. Please send us an email</strong> (<a href="mailto:support@tylerdigital.com">support@tylerdigital.com</a>) to let us know you\'re interested and answer a few questions to help us build this the right way:</p> |
| 264 |
|
| 265 |
<p>Would this just be a tool for you (the network admin)?<br /> |
| 266 |
Or would you want your site admins to be able to run it (and I assume they could only test their site-activated plugins, not disable any that you’ve network-activated?)</p> |
| 267 |
|
| 268 |
<p>Thanks,<br /> |
| 269 |
Nathan & Natalie</p>'; |
| 270 |
} |
| 271 |
|
| 272 |
if ( !empty( $this->activation_errors ) ) { |
| 273 |
return false; |
| 274 |
} |
| 275 |
|
| 276 |
return true; |
| 277 |
} |
| 278 |
|
| 279 |
/** |
| 280 |
* Adds a notice to the dashboard if the plugin requirements are not met. |
| 281 |
* |
| 282 |
* @since 0.0.0 |
| 283 |
*/ |
| 284 |
public function requirements_not_met_notice() { |
| 285 |
|
| 286 |
// Compile default message. |
| 287 |
$default_message = sprintf( __( 'Plugin Detective is missing requirements and has been <a href="%s">deactivated</a>. Please make sure all requirements are available.', 'plugin-detective' ), admin_url( 'plugins.php' ) ); |
| 288 |
|
| 289 |
// Default details to null. |
| 290 |
$details = null; |
| 291 |
|
| 292 |
// Add details if any exist. |
| 293 |
if ( $this->activation_errors && is_array( $this->activation_errors ) ) { |
| 294 |
$details = '<small>' . implode( '</small><br /><small>', $this->activation_errors ) . '</small>'; |
| 295 |
} |
| 296 |
|
| 297 |
// Output errors. |
| 298 |
?> |
| 299 |
<div id="message" class="error"> |
| 300 |
<p><?php echo wp_kses_post( $default_message ); ?></p> |
| 301 |
<?php echo wp_kses_post( $details ); ?> |
| 302 |
</div> |
| 303 |
<?php |
| 304 |
} |
| 305 |
|
| 306 |
/** |
| 307 |
* Magic getter for our object. |
| 308 |
* |
| 309 |
* @since 0.0.0 |
| 310 |
* |
| 311 |
* @param string $field Field to get. |
| 312 |
* @throws Exception Throws an exception if the field is invalid. |
| 313 |
* @return mixed Value of the field. |
| 314 |
*/ |
| 315 |
public function __get( $field ) { |
| 316 |
switch ( $field ) { |
| 317 |
case 'version': |
| 318 |
return self::VERSION; |
| 319 |
case 'basename': |
| 320 |
case 'url': |
| 321 |
case 'path': |
| 322 |
case 'wp_admin': |
| 323 |
return $this->$field; |
| 324 |
default: |
| 325 |
throw new Exception( 'Invalid ' . __CLASS__ . ' property: ' . $field ); |
| 326 |
} |
| 327 |
} |
| 328 |
|
| 329 |
/** |
| 330 |
* Include a file from the includes directory. |
| 331 |
* |
| 332 |
* @since 0.0.0 |
| 333 |
* |
| 334 |
* @param string $filename Name of the file to be included. |
| 335 |
* @return boolean Result of include call. |
| 336 |
*/ |
| 337 |
public static function include_file( $filename ) { |
| 338 |
$file = self::dir( $filename . '.php' ); |
| 339 |
if ( file_exists( $file ) ) { |
| 340 |
return include_once( $file ); |
| 341 |
} |
| 342 |
return false; |
| 343 |
} |
| 344 |
|
| 345 |
/** |
| 346 |
* This plugin's directory. |
| 347 |
* |
| 348 |
* @since 0.0.0 |
| 349 |
* |
| 350 |
* @param string $path (optional) appended path. |
| 351 |
* @return string Directory and path. |
| 352 |
*/ |
| 353 |
public static function dir( $path = '' ) { |
| 354 |
static $dir; |
| 355 |
$dir = $dir ? $dir : trailingslashit( dirname( __FILE__ ) ); |
| 356 |
return $dir . $path; |
| 357 |
} |
| 358 |
|
| 359 |
/** |
| 360 |
* This plugin's url. |
| 361 |
* |
| 362 |
* @since 0.0.0 |
| 363 |
* |
| 364 |
* @param string $path (optional) appended path. |
| 365 |
* @return string URL and path. |
| 366 |
*/ |
| 367 |
public static function url( $path = '' ) { |
| 368 |
static $url; |
| 369 |
$url = $url ? $url : trailingslashit( plugin_dir_url( __FILE__ ) ); |
| 370 |
return $url . $path; |
| 371 |
} |
| 372 |
} |
| 373 |
|
| 374 |
/** |
| 375 |
* Grab the Plugin_Detective object and return it. |
| 376 |
* Wrapper for Plugin_Detective::get_instance(). |
| 377 |
* |
| 378 |
* @since 0.0.0 |
| 379 |
* @return Plugin_Detective Singleton instance of plugin class. |
| 380 |
*/ |
| 381 |
function plugin_detective() { |
| 382 |
return Plugin_Detective::get_instance(); |
| 383 |
} |
| 384 |
|
| 385 |
// Kick it off. |
| 386 |
add_action( 'plugins_loaded', array( plugin_detective(), 'hooks' ) ); |
| 387 |
|
| 388 |
// Activation and deactivation. |
| 389 |
register_activation_hook( __FILE__, array( plugin_detective(), '_activate' ) ); |
| 390 |
register_deactivation_hook( __FILE__, array( plugin_detective(), '_deactivate' ) ); |
| 391 |
|