init(); } return self::$instance; } /** * Register hooks. */ private function init() { // Ingest any raw captures the mu-plugin watcher recorded, and keep the // installed drop-in in sync with the bundled version. Runs on init so // WordPress APIs (get_plugins, etc.) are available. add_action( 'init', array( $this, 'boot' ), 5 ); // Admin bootstrap. if ( is_admin() ) { Culprit_Admin::instance(); Culprit_Environment::init(); Culprit_Watcher_Installer::init(); Culprit_Database::maybe_upgrade(); } // Translations load automatically for WordPress.org-hosted plugins since // WP 4.6 — no manual load_plugin_textdomain() call needed (Plugin Check // flags it as discouraged). } /** * Per-load housekeeping: refresh the watcher drop-in if stale, then ingest * any captures it has written since the last load. */ public function boot() { // Record plugin/theme/core changes for recent-change context. Culprit_Changes::init(); Culprit_Watcher_Installer::maybe_refresh(); Culprit_Capture::ingest_pending(); // If the mu-plugin watcher isn't installed (e.g. unwritable mu-plugins), // register an in-request fallback shutdown handler so later fatals are // still caught — just not the earliest-boot ones. if ( ! file_exists( Culprit_Watcher_Installer::installed_path() ) ) { register_shutdown_function( array( 'Culprit_Capture', 'fallback_shutdown' ) ); } } } /** * Activation: create table, install the watcher drop-in, seed defaults. */ function culprit_activate() { require_once CULPRIT_PLUGIN_DIR . 'includes/class-culprit-database.php'; require_once CULPRIT_PLUGIN_DIR . 'includes/class-culprit-settings.php'; require_once CULPRIT_PLUGIN_DIR . 'includes/class-culprit-watcher-installer.php'; Culprit_Database::install(); Culprit_Settings::seed_defaults(); // Prepare the protected capture-buffer location. The mu-plugin watcher is // NOT installed here — it requires an explicit admin opt-in on the Status // screen (WordPress.org guideline: never write executable code outside the // plugin directory without the administrator's explicit action). Culprit_Watcher_Installer::ensure_buffer_dir(); } register_activation_hook( __FILE__, 'culprit_activate' ); /** * Deactivation: remove the watcher drop-in so a turned-off plugin stops writing * captures. Data is preserved; the drop-in is reinstalled on reactivation. */ function culprit_deactivate() { require_once CULPRIT_PLUGIN_DIR . 'includes/class-culprit-watcher-installer.php'; Culprit_Watcher_Installer::remove(); } register_deactivation_hook( __FILE__, 'culprit_deactivate' ); // Boot. Culprit::instance();