query( "DELETE FROM {$wpdb->postmeta} WHERE meta_key LIKE '_ai_explainer%'" ); // 3. Drop custom database tables. // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.DirectDatabaseQuery.SchemaChange -- Uninstall cleanup: schema change is the goal. $wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}ai_explainer_scan_history" ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.DirectDatabaseQuery.SchemaChange -- Uninstall cleanup: schema change is the goal. $wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}ai_explainer_history" ); // Pro 2.3.0+ tables (audit log + API keys). // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.DirectDatabaseQuery.SchemaChange -- Uninstall cleanup. $wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}aiep_audit_log" ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.DirectDatabaseQuery.SchemaChange -- Uninstall cleanup. $wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}aiep_api_keys" ); // 3b. Unschedule cron events. $aiep_cron_hooks = [ 'aiep_audit_log_purge', 'aiep_email_report_event', 'aiep_weekly_rescan' ]; foreach ( $aiep_cron_hooks as $aiep_hook ) { // phpcs:ignore Generic.CodeAnalysis.AssignmentInCondition.FoundInWhileCondition -- Intentional: unschedule every remaining occurrence of the hook by polling wp_next_scheduled() until it returns false. while ( $aiep_ts = wp_next_scheduled( $aiep_hook ) ) { wp_unschedule_event( $aiep_ts, $aiep_hook ); } } // 4. Clean transients. // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- Uninstall cleanup of plugin transients. $wpdb->query( "DELETE FROM {$wpdb->options} WHERE option_name LIKE '%_transient_aiep_%'" ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- Uninstall cleanup of plugin transients. $wpdb->query( "DELETE FROM {$wpdb->options} WHERE option_name LIKE '%_transient_timeout_aiep_%'" ); // 5. Clear scheduled cron events. wp_clear_scheduled_hook( 'aiep_send_email_report' ); // 6. Remove user meta (dismissed notices). // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- Uninstall cleanup of plugin user meta. $wpdb->query( "DELETE FROM {$wpdb->usermeta} WHERE meta_key LIKE 'aiep_%'" );