'ids', 'number' => 0]) as $site_id) { switch_to_blog((int) $site_id); try { cleanup_site(); } finally { restore_current_blog(); } } } /** Remove derived catalog data after the last edition is removed. */ function cleanup_site() { global $wpdb; foreach (['fqbpro_catalog_process_queue', 'fqbpro_catalog_rebuild_dirty', 'fqbpro_catalog_reconcile', 'fqbpro_catalog_reconcile_batch', 'fqbpro_instances_scan', 'fqbpro_instances_scan_batch', 'fqbpro_v4_migrate_content'] as $hook) wp_clear_scheduled_hook($hook); foreach (['_fqbp_v4_filter_summary', '_fqbp_v4_filter_count', '_fqbp_v4_filter_reference', '_fqbp_v4_filter_scan_error', '_fqbp_v4_filter_fingerprint', '_fqbp_v4_migration_report', '_fqbpro_filter_summary', '_fqbpro_filter_count', '_fqbpro_filter_reference', '_fqbpro_v4_migration_report'] as $key) delete_post_meta_by_key($key); foreach ((array) get_option('fqbp_v4_catalog_schema_cache_keys', []) as $key) { if (is_string($key) && str_starts_with($key, 'fqbp_v4_acf_schema_')) delete_transient($key); } // Raw discovery caches may be backed by an external object cache. Delete known // keys through the transient API before discarding the tracked-source lists. $types = array_unique(array_merge((array) get_option('fqbp_v4_catalog_tracked_post_types', []), (array) get_option('fqbp_free_catalog_tracked_post_types', []), array_keys(get_post_types(['public' => true])))); foreach ($types as $type) if (is_string($type)) delete_transient('fqbp_v4_read_through_' . sanitize_key($type)); foreach (['fqbp_v4_read_through_', 'fqbp_v4_acf_schema_', 'fqbp_v4_migration_preview_', 'fqbp_v4_restore_review_', 'fqbp_dict_'] as $prefix) { // Enumerate current transient names once during uninstall; cached results could leave data behind. // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching $names = $wpdb->get_col($wpdb->prepare("SELECT option_name FROM {$wpdb->options} WHERE option_name LIKE %s", $wpdb->esc_like('_transient_' . $prefix) . '%')); foreach ($names as $name) delete_transient(substr($name, strlen('_transient_'))); } if (function_exists('wp_cache_supports') && wp_cache_supports('flush_group')) wp_cache_flush_group('fqbp_dictionary'); foreach ([ 'fqbp_catalog_exclusions', 'fqbp_free_catalog_tracked_post_types', 'fqbp_v4_metadata_catalog', 'fqbp_v4_catalog_tracked_post_types', 'fqbp_v4_catalog_dirty_post_types', 'fqbp_v4_catalog_index_schema_version', 'fqbp_v4_catalog_registration_signatures', 'fqbp_v4_catalog_reconciliation', 'fqbp_v4_catalog_schema_generation', 'fqbp_v4_catalog_schema_cache_keys', 'fqbp_v4_catalog_reindex_jobs', 'fqbp_v4_instance_scan', 'fqbp_v4_instance_scan_version', 'fqbp_v4_plugin_version', 'fqbp_v4_maintenance', 'fqbp_v4_workers_paused', 'fqbp_v4_recovery_mode', 'fqbp_v4_deactivation', 'fqbp_v4_inventory_deactivated', 'fqbp_v4_migration_state', 'fqbp_v4_content_migration_version', 'fqbp_v4_free_tracking_imported', 'fqbp_v4_legacy_cache_retired', 'fqbp_dictionary_cache_version', 'fqbpro_metadata_catalog', 'fqbpro_catalog_tracked_post_types', 'fqbpro_catalog_dirty_post_types', 'fqbpro_catalog_index_schema_version', 'fqbpro_catalog_registration_signatures', 'fqbpro_catalog_reconciliation', 'fqbpro_instance_scan', 'fqbpro_plugin_version', 'fqbpro_v4_migration_state', 'fqbpro_content_migration_version', ] as $option) delete_option($option); foreach (['fqbp_v4_catalog_', 'fqbpro_catalog_'] as $prefix) { foreach (['posts', 'terms', 'meta_values', 'queue'] as $suffix) { $table = $wpdb->prefix . $prefix . $suffix; // Remove only this plugin's derived tables when the final edition is uninstalled. // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.SchemaChange $wpdb->query($wpdb->prepare('DROP TABLE IF EXISTS %i', $table)); } } // Saved blocks, migration content backups and commercial license options are // intentionally retained. Uninstall never contacts the licensing service. }