query( "DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_agentorie_%' OR option_name LIKE '_transient_timeout_agentorie_%'" ); /* |-------------------------------------------------------------------------- | Always Delete: User Meta |-------------------------------------------------------------------------- */ // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter $wpdb->query( "DELETE FROM {$wpdb->usermeta} WHERE meta_key LIKE 'agentorie_%'" ); /* |-------------------------------------------------------------------------- | Always Delete: Scheduled Cron Events |-------------------------------------------------------------------------- */ wp_clear_scheduled_hook( 'agentorie_chat_cleanup_sessions' ); wp_clear_scheduled_hook( 'agentorie_chat_daily_maintenance' ); wp_clear_scheduled_hook( 'agentorie_chat_sync_to_saas' ); wp_clear_scheduled_hook( 'agentorie_chat_check_license' ); wp_clear_scheduled_hook( 'agentorie_chat_daily_index' ); /* |-------------------------------------------------------------------------- | Optional: Database Tables (if user opted in) |-------------------------------------------------------------------------- */ if ( $agentorie_delete_data ) { // Table names. $agentorie_tables = array( $wpdb->prefix . 'agentorie_sessions', $wpdb->prefix . 'agentorie_chat_messages', $wpdb->prefix . 'agentorie_contacts', $wpdb->prefix . 'agentorie_visitors', $wpdb->prefix . 'agentorie_site_content', ); // Drop tables. foreach ( $agentorie_tables as $agentorie_table ) { // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter $wpdb->query( "DROP TABLE IF EXISTS `{$agentorie_table}`" ); } /* |-------------------------------------------------------------------------- | Optional: Log Files (if user opted in) |-------------------------------------------------------------------------- */ // Delete log directory in uploads. $agentorie_upload_dir = wp_upload_dir(); $agentorie_log_dir_upload = trailingslashit( $agentorie_upload_dir['basedir'] ) . 'agentorie-chat/'; if ( is_dir( $agentorie_log_dir_upload ) ) { agentorie_chat_uninstall_delete_directory( $agentorie_log_dir_upload ); } } /* |-------------------------------------------------------------------------- | Helper Functions |-------------------------------------------------------------------------- */ /** * Recursively delete a directory and its contents. * * @param string $dir Directory path to delete. * @return bool True on success, false on failure. */ function agentorie_chat_uninstall_delete_directory( $dir ) { if ( ! is_dir( $dir ) ) { return false; } // Security check: only delete directories within uploads. $agentorie_upload_dir = wp_upload_dir(); $allowed_base = trailingslashit( $agentorie_upload_dir['basedir'] ); if ( strpos( realpath( $dir ), realpath( $allowed_base ) ) !== 0 ) { return false; } $files = array_diff( scandir( $dir ), array( '.', '..' ) ); foreach ( $files as $file ) { $path = trailingslashit( $dir ) . $file; if ( is_dir( $path ) ) { agentorie_chat_uninstall_delete_directory( $path ); } else { // phpcs:ignore WordPress.WP.AlternativeFunctions.unlink_unlink unlink( $path ); } } // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_rmdir return rmdir( $dir ); }