'ids', 'number' => 0 ] ) as $site_id ) { switch_to_blog( (int) $site_id ); clusterlane_uninstall_data_site(); restore_current_blog(); } } else { clusterlane_uninstall_data_site(); } } /** * Remove Clusterlane's data from the current site (switch_to_blog() first on * multisite). Table names are listed explicitly, so a name collision can * never drop unrelated tables. */ function clusterlane_uninstall_data_site(): void { global $wpdb; // 1. Tables. foreach ( [ 'clusterlane_links', 'clusterlane_clusters', 'clusterlane_post_metrics', 'clusterlane_ai_cache', 'clusterlane_custom_members', 'clusterlane_tms_skipped', 'clusterlane_cluster_post_class', 'clusterlane_snapshots', 'clusterlane_activity' ] as $bare ) { $table = $wpdb->prefix . $bare; $wpdb->query( $wpdb->prepare( 'DROP TABLE IF EXISTS %i', $table ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- removing the plugin's own tables on uninstall } // 2. Options. foreach ( [ 'clusterlane_settings', 'clusterlane_db_version', 'clusterlane_caps_version', 'clusterlane_ai_usage', 'clusterlane_chosen_pillars', 'clusterlane_cluster_sections', 'clusterlane_cluster_groups', 'clusterlane_data_version', 'clusterlane_last_snapshot', 'clusterlane_render_log', 'clusterlane_page_queue', 'clusterlane_page_lock', 'clusterlane_hub_relations', 'clusterlane_migrated', 'clusterlane_migrating' ] as $option ) { delete_option( $option ); } // 3. Transients: undo data for SEO fields and applied links (30 minutes each). $wpdb->query( // phpcs:ignore WordPress.DB.DirectDatabaseQuery "DELETE FROM {$wpdb->options} WHERE option_name LIKE '\\_transient\\_clusterlane\\_%' OR option_name LIKE '\\_transient\\_timeout\\_clusterlane\\_%'" ); // 4. Post meta: the draft marker from Gap Analysis and the Elementor // backup written before Clusterlane changed an Elementor page. foreach ( [ '_clusterlane_gap_cluster', '_clusterlane_elementor_backup', '_clusterlane_seo_check', '_clusterlane_seo_check_min', '_clusterlane_seo_original', '_clusterlane_page_stats' ] as $meta_key ) { delete_post_meta_by_key( $meta_key ); } // 5. The daily snapshot event. wp_clear_scheduled_hook( 'clusterlane_daily_snapshot' ); wp_clear_scheduled_hook( 'clusterlane_read_pages' ); // 6. Capabilities added to roles (roles are stored per site). foreach ( wp_roles()->role_objects as $role ) { $role->remove_cap( 'manage_clusterlane' ); $role->remove_cap( 'use_clusterlane' ); $role->remove_cap( 'use_clusterlane_ai' ); $role->remove_cap( 'clusterlane_add_links' ); $role->remove_cap( 'clusterlane_write_seo' ); } } }