_releases (Compatibility\ReleaseStore), lit_mcp__check_report * (Compatibility\CheckReportStore) and lit_mcp__check_lock (Admin\CheckRoute) for the * profiles divi, pods and wpsc (an explicit list: a LIKE pattern could hit foreign options), * Integrations\Divi\Design\DesignLock::option(), Admin\ConnectionStatus::ENDPOINT_TRANSIENT, * Integrations\Divi\Release\ReleaseResolver::CACHE, * Integrations\SuperCache\SuperCacheListener::PURGED_AT (transient), * ChangeLog\ChangeLogCleanup::HOOK, Integrations\SuperCache\SuperCacheListener::TRAILING_HOOK (cron), * ChangeLog\ChangeLog::TABLE, Admin\LogTab::PER_PAGE_OPTION and * Updater\RecheckOnInstall::OPTION on purpose; * tests/Unit/UninstallerTest.php and tests/Unit/UninstallTest.php keep them in sync with * those constants. * * Never touches the bundled wp-media/mcp-oauth library's data (option mcp_jwt_secret, * option wpmedia_mcp_oauth_rewrite_version, user meta mcp_refresh_jti_*, application * passwords of connected clients) – that library may be shared with other plugins on * this site. Never deletes posts, attachments or revisions. */ final class Uninstaller { private const OPTIONS = [ 'lit_mcp_allowed_roles', 'lit_mcp_exposure', 'lit_mcp_limits', 'lit_mcp_db_version', 'lit_mcp_divi_releases', 'lit_mcp_divi_check_report', 'lit_mcp_divi_check_lock', 'lit_mcp_pods_releases', 'lit_mcp_pods_check_report', 'lit_mcp_pods_check_lock', 'lit_mcp_wpsc_releases', 'lit_mcp_wpsc_check_report', 'lit_mcp_wpsc_check_lock', 'lit_mcp_snapshots_colors', 'lit_mcp_snapshots_variables', 'lit_mcp_snapshots_presets', 'lit_mcp_snapshots_theme_options', 'lit_mcp_snapshots_custom_css', 'lit_mcp_lock_divi_options', 'lit_mcp_lock_variables', 'lit_mcp_lock_presets', 'lit_mcp_lock_custom_css', // Locks of versions before the shared one (audit L5) may still sit in the table. 'lit_mcp_lock_colors', 'lit_mcp_lock_theme_options', 'lit_mcp_installed_version', ]; private const TRANSIENTS = ['lit_mcp_endpoint_check', 'lit_mcp_divi_state', 'lit_mcp_wpsc_purged_at']; private const CRON_HOOKS = ['lit_mcp_log_cleanup', 'lit_mcp_wpsc_trailing_purge']; private const TABLE = 'lit_mcp_log'; /** Screen option "Einträge pro Seite" of the Protokoll tab (Admin\LogTab::PER_PAGE_OPTION): user meta. */ private const USER_META = 'lit_mcp_log_per_page'; public static function run(): void { // User meta is shared by every site of a network: removed once, for all users. delete_metadata('user', 0, self::USER_META, '', true); if (! is_multisite()) { self::removeSiteData(); return; } foreach (get_sites(['fields' => 'ids', 'number' => 0]) as $site_id) { switch_to_blog((int) $site_id); self::removeSiteData(); restore_current_blog(); } } public static function removeSiteData(): void { global $wpdb; foreach (self::OPTIONS as $option) { delete_option($option); } foreach (self::TRANSIENTS as $transient) { delete_transient($transient); } foreach (self::CRON_HOOKS as $hook) { wp_clear_scheduled_hook($hook); } $table = $wpdb->prefix . self::TABLE; // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- own table name, not user input. $wpdb->query("DROP TABLE IF EXISTS {$table}"); } }