get_col( $wpdb->prepare( "SELECT option_name FROM {$wpdb->options} WHERE option_name LIKE %s OR option_name LIKE %s OR option_name LIKE %s OR option_name LIKE %s", $wpdb->esc_like( 'activelayer_fluentforms_form_' ) . '%', $wpdb->esc_like( 'activelayer_sureforms_form_' ) . '%', $wpdb->esc_like( 'activelayer_ws_form_form_' ) . '%', $wpdb->esc_like( 'activelayer_funnelkit_form_' ) . '%' ) ); if ( $activelayer_per_form_rows ) { foreach ( $activelayer_per_form_rows as $activelayer_per_form_option ) { delete_option( $activelayer_per_form_option ); } } // Transients. delete_transient( 'activelayer_subscription_stats' ); delete_transient( 'activelayer_activation_redirect' ); delete_transient( 'activelayer_table_creation_failed' ); // Watchdog state options. delete_option( 'activelayer_last_queue_run' ); delete_option( 'activelayer_queue_watchdog_notice' ); // Drop the submissions table for this blog. $activelayer_table_to_drop = esc_sql( $wpdb->prefix . 'activelayer_submissions' ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange -- Required for uninstall cleanup, table name sanitized. $wpdb->query( "DROP TABLE IF EXISTS `{$activelayer_table_to_drop}`" ); // Clear ActiveLayer cache entries. if ( function_exists( 'wp_cache_delete' ) ) { wp_cache_delete( 'list_cache_version', ACTIVELAYER_CACHE_GROUP ); wp_cache_delete( 'queue_stats', ACTIVELAYER_CACHE_GROUP ); wp_cache_delete( 'table_exists', ACTIVELAYER_CACHE_GROUP ); } // Unschedule this blog's Action Scheduler jobs. Plugin hooks: // activelayer_process_submission, activelayer_cleanup_pending, // activelayer_refresh_subscription_stats, activelayer_queue_watchdog, // activelayer_retry_failed_submissions, activelayer_cleanup_submissions, // activelayer_send_feedback. // // Action Scheduler is loaded process-wide (from the main site), but a // subsite we switch_to_blog() into may never have created its own AS // tables — the unschedule would then query a missing table. Suppress DB // errors so that stays a no-op instead of a visible warning. if ( function_exists( 'as_unschedule_all_actions' ) ) { $activelayer_previous_suppression = $wpdb->suppress_errors(); as_unschedule_all_actions( 'activelayer_process_submission' ); as_unschedule_all_actions( 'activelayer_cleanup_pending' ); as_unschedule_all_actions( 'activelayer_refresh_subscription_stats' ); as_unschedule_all_actions( 'activelayer_queue_watchdog' ); as_unschedule_all_actions( 'activelayer_retry_failed_submissions' ); as_unschedule_all_actions( 'activelayer_cleanup_submissions' ); as_unschedule_all_actions( 'activelayer_send_feedback' ); $wpdb->suppress_errors( $activelayer_previous_suppression ); } // Clear the standard WP-Cron hook if Action Scheduler is unavailable. wp_clear_scheduled_hook( 'activelayer_queue_watchdog' ); } } // Only run the destructive teardown during a genuine uninstall. if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) { return; } if ( is_multisite() ) { // uninstall.php fires once for the whole network, so walk every blog and // clean it under its own prefix. number => 0 returns all sites; acceptable // here because uninstall must reach every one. // ponytail: loops all network sites; fine for a one-shot uninstall. $activelayer_site_ids = get_sites( [ 'fields' => 'ids', 'number' => 0, ] ); foreach ( $activelayer_site_ids as $activelayer_site_id ) { switch_to_blog( $activelayer_site_id ); activelayer_uninstall_site_data( $activelayer_option_names ); restore_current_blog(); } // Network-level options (stored once for the whole network). foreach ( $activelayer_option_names as $activelayer_option_name ) { delete_site_option( $activelayer_option_name ); } delete_site_option( 'activelayer_last_queue_run' ); delete_site_option( 'activelayer_queue_watchdog_notice' ); } else { activelayer_uninstall_site_data( $activelayer_option_names ); }