# vigilante/2.9.9/includes/class-deactivator.php

Vigilant – 100% Free Security Suite: Firewall, 2FA, Login, Headers, Scanner…, version 2.9.9. 300 lines.

- Page: https://pluginprobe.com/plugins/vigilante/2.9.9/code/includes/class-deactivator.php
- Raw: https://pluginprobe.com/plugins/vigilante/2.9.9/raw/includes/class-deactivator.php
- Modified: 2026-08-22T20:46:28+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/vigilante/2.9.9/code/includes/class-deactivator.php#L10-L20`.

```php
<?php
/**
 * Deactivator Class
 *
 * Handles plugin deactivation tasks
 *
 * @package Vigilante
 */

// Prevent direct access
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

/**
 * Class Vigilante_Deactivator
 *
 * Fired during plugin deactivation
 */
class Vigilante_Deactivator {

    /**
     * Run deactivation tasks
     */
    public static function deactivate() {
        // ALWAYS remove htaccess rules using the centralized manager
        self::remove_htaccess_rules();

        // ALWAYS remove wp-config security constants and restore originals
        self::remove_wpconfig_security();

        // Clear scheduled events
        self::clear_scheduled_events();

        // Send deactivation email
        self::send_deactivation_email();

        // Clear transients
        delete_transient( 'vigilante_activated' );
        delete_transient( 'vigilante_restore_on_deactivate' );
        delete_transient( 'vigilante_backup_error' );

        // Audit Alerts: clear every engine transient (per-category counters and
        // cooldowns, plus the immediate anti-duplicate keys). Names are dynamic
        // (one per category, md5 per event), so a prefix sweep is the only way.
        global $wpdb;
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- One-off cleanup on deactivate; dynamic transient names cannot be enumerated individually.
        $wpdb->query( "DELETE FROM {$wpdb->options} WHERE option_name LIKE '\\_transient\\_vigilante\\_aa\\_%' OR option_name LIKE '\\_transient\\_timeout\\_vigilante\\_aa\\_%'" );

        // Flush rewrite rules
        flush_rewrite_rules();
    }

    /**
     * Remove htaccess rules using the centralized manager
     */
    private static function remove_htaccess_rules() {
        // Use the centralized manager
        require_once VIGILANTE_INCLUDES_DIR . 'class-htaccess-manager.php';
        
        $manager = Vigilante_Htaccess_Manager::get_instance();

        // Remove our blocks
        $manager->remove_block( '# BEGIN Vigilante Protection', '# END Vigilante Protection' );
        $manager->remove_block( '# BEGIN Vigilante Security Headers', '# END Vigilante Security Headers' );
    }

    /**
     * Remove wp-config security constants and restore original values
     */
    private static function remove_wpconfig_security() {
        $wpconfig_path = ABSPATH . 'wp-config.php';

        if ( ! file_exists( $wpconfig_path ) ) {
            return;
        }

        // Initialize WP_Filesystem
        global $wp_filesystem;
        if ( ! function_exists( 'WP_Filesystem' ) ) {
            require_once ABSPATH . 'wp-admin/includes/file.php';
        }
        WP_Filesystem();

        if ( ! $wp_filesystem || ! $wp_filesystem->is_writable( $wpconfig_path ) ) {
            return;
        }

        $content = $wp_filesystem->get_contents( $wpconfig_path );

        if ( false === $content || empty( $content ) ) {
            return;
        }

        $modified = false;

        // Step 1: Remove our Vigilante block
        if ( strpos( $content, '/* BEGIN Vigilante Security Constants */' ) !== false ) {
            $lines = explode( "\n", $content );
            $new_lines = array();
            $inside_block = false;

            foreach ( $lines as $line ) {
                if ( strpos( $line, '/* BEGIN Vigilante Security Constants */' ) !== false ) {
                    $inside_block = true;
                    continue;
                }

                if ( strpos( $line, '/* END Vigilante Security Constants */' ) !== false ) {
                    $inside_block = false;
                    continue;
                }

                if ( ! $inside_block ) {
                    $new_lines[] = $line;
                }
            }

            $content = implode( "\n", $new_lines );
            $modified = true;
        }

        // Step 2: Uncomment original constants (restore [VIGILANTE_ORIGINAL] lines)
        $original_marker = '// [VIGILANTE_ORIGINAL] ';
        if ( strpos( $content, $original_marker ) !== false ) {
            $pattern = '/^(\s*)' . preg_quote( $original_marker, '/' ) . '(.+)$/m';
            $content = preg_replace( $pattern, '$1$2', $content );
            $modified = true;
        }

        if ( ! $modified ) {
            return;
        }

        // Clean up multiple empty lines
        $content = preg_replace( '/\n{3,}/', "\n\n", $content );

        // Safety check: must still have basic wp-config content
        if ( strpos( $content, 'DB_NAME' ) === false ) {
            return; // Don't write if it would corrupt wp-config
        }

        $wp_filesystem->put_contents( $wpconfig_path, $content, FS_CHMOD_FILE );
    }

    /**
     * Clear all scheduled cron events
     */
    private static function clear_scheduled_events() {
        $events = array(
            'vigilante_daily_maintenance',
            'vigilante_hourly_checks',
            'vigilante_file_integrity_scan',
            'vigilante_password_expiry_reminder',
            'vigilante_analyzer_weekly_scan',
            'vigilante_plugin_status_check',
        );

        foreach ( $events as $event ) {
            $timestamp = wp_next_scheduled( $event );
            if ( $timestamp ) {
                wp_unschedule_event( $timestamp, $event );
            }
        }

        // Clear all events with our prefix
        wp_unschedule_hook( 'vigilante_daily_maintenance' );
        wp_unschedule_hook( 'vigilante_hourly_checks' );
        wp_unschedule_hook( 'vigilante_file_integrity_scan' );
        wp_unschedule_hook( 'vigilante_password_expiry_reminder' );
        wp_unschedule_hook( 'vigilante_analyzer_weekly_scan' );
        wp_unschedule_hook( 'vigilante_plugin_status_check' );
        // Post-update verification single events (scheduled with per-update args).
        wp_unschedule_hook( 'vigilante_fi_postupdate_verify' );
    }

    /**
     * Send deactivation notification email
     */
    private static function send_deactivation_email() {
        $settings = new Vigilante_Settings();
        $email_settings = $settings->get_section( 'email' );

        if ( empty( $email_settings['send_deactivation_email'] ) ) {
            return;
        }

        if ( ! class_exists( 'Vigilante_Email_Template' ) ) {
            require_once VIGILANTE_INCLUDES_DIR . 'class-email-template.php';
        }

        $to = Vigilante_Email_Template::get_admin_recipients();

        $site_name = get_bloginfo( 'name' );
        $site_url = get_site_url();

        // Get current user info
        $current_user = wp_get_current_user();
        $user_info = $current_user->ID > 0 
            ? $current_user->user_login . ' (' . $current_user->user_email . ')' 
            : __( 'Unknown', 'vigilante' );

        $subject = sprintf(
            /* translators: %s: Site name */
            __( '[%s] Vigilant Deactivated', 'vigilante' ),
            $site_name
        );

        $body  = Vigilante_Email_Template::warning_box( __( 'Security protection has been disabled. Please ensure you have alternative security measures in place.', 'vigilante' ) );
        $body .= Vigilante_Email_Template::data_table( array(
            __( 'Site', 'vigilante' )            => $site_name,
            __( 'URL', 'vigilante' )             => $site_url,
            __( 'Date', 'vigilante' )            => wp_date( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ) ),
            __( 'Deactivated by', 'vigilante' )  => $user_info,
        ) );

        Vigilante_Email_Template::send( $to, $subject, __( 'Plugin deactivated', 'vigilante' ), $body );
    }

    /**
     * Full uninstall - removes all data
     * Called from uninstall.php
     */
    public static function uninstall() {
        // Drop database tables
        $database = new Vigilante_Database();
        $database->drop_tables();

        // Remove all options
        delete_option( 'vigilante_options' );
        delete_option( 'vigilante_db_version' );
        delete_option( 'vigilante_activated_time' );
        delete_option( 'vigilante_dismissed_notices' );
        delete_option( 'vigilante_backup_timestamp' );
        delete_option( 'vigilante_last_integrity_results' );
        delete_option( 'vigilante_last_integrity_scan' );
        delete_option( 'vigilante_critical_files_baseline' );
        delete_option( 'vigilante_analyzer_last_scan' );
        delete_option( 'vigilante_analyzer_history' );
        delete_option( 'vigilante_analyzer_fix_log' );

        // Remove transients
        delete_transient( 'vigilante_activated' );
        delete_transient( 'vigilante_restore_on_deactivate' );
        delete_transient( 'vigilante_backup_error' );
        delete_transient( 'vigilante_file_integrity_last_scan' );

        // Audit Alerts: remove every engine transient (counters, cooldowns and
        // the immediate anti-duplicate keys), including their timeout twins.
        // Names are dynamic (md5 per event), so a prefix sweep is the only way.
        global $wpdb;
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- One-off uninstall cleanup; dynamic transient names cannot be enumerated individually.
        $wpdb->query( "DELETE FROM {$wpdb->options} WHERE option_name LIKE '\\_transient\\_vigilante\\_aa\\_%' OR option_name LIKE '\\_transient\\_timeout\\_vigilante\\_aa\\_%'" );

        // Remove backup directory
        self::remove_backup_directory();

        // Clear scheduled events
        self::clear_scheduled_events();

        // Remove htaccess rules
        self::remove_htaccess_rules();

        // Remove wp-config security constants and restore originals
        self::remove_wpconfig_security();
    }

    /**
     * Remove backup directory and its contents
     */
    private static function remove_backup_directory() {
        $backup_dirs = array(
            WP_CONTENT_DIR . '/vigilante-backups',
        );

        if ( defined( 'VIGILANTE_BACKUP_DIR' ) ) {
            $backup_dirs[] = VIGILANTE_BACKUP_DIR;
        }

        // Initialize WP_Filesystem
        global $wp_filesystem;
        if ( ! function_exists( 'WP_Filesystem' ) ) {
            require_once ABSPATH . 'wp-admin/includes/file.php';
        }
        WP_Filesystem();

        if ( ! $wp_filesystem ) {
            return;
        }

        foreach ( $backup_dirs as $backup_dir ) {
            if ( ! $wp_filesystem->is_dir( $backup_dir ) ) {
                continue;
            }

            // Remove directory and contents recursively
            $wp_filesystem->delete( $backup_dir, true );
        }
    }
}
```
