'ids', 'number' => 100, 'offset' => $offset, ) ); foreach ( $sites as $site_id ) { switch_to_blog( $site_id ); try { $retained_site = ! self::site() || $retained_site; } finally { restore_current_blog(); } } $offset += 100; $count = count( $sites ); } while ( 100 === $count ); } else { $retained_site = ! self::site(); } // Legacy correction debt is user-global. Preserve it if any site retains its ledger. if ( ! $retained_site ) { delete_metadata( 'user', 0, '_devoynx_rewards_reversal_due', '', true ); delete_metadata( 'user', 0, '_devoynx_rewards_referral_optout', '', true ); } } /** * Clean up only the current site's opted-in rewards data. * * @return bool Whether this site's rewards data was removed. */ private static function site() { global $wpdb; Migrator::deactivate(); foreach ( array( 'administrator', 'shop_manager' ) as $role_name ) { $role = get_role( $role_name ); if ( $role ) { $role->remove_cap( 'manage_devoynx_rewards' ); } } $settings = get_option( 'devoynx_rewards_settings', array() ); if ( empty( $settings['delete_on_uninstall'] ) ) { return false; } foreach ( array( 'devoynx_rewards_ledger', 'devoynx_rewards_balances', 'devoynx_rewards_program_records' ) as $suffix ) { $wpdb->query( $wpdb->prepare( 'DROP TABLE IF EXISTS %i', $wpdb->prefix . $suffix ) ); } foreach ( array( '_devoynx_rewards_excluded', '_devoynx_rewards_rate' ) as $key ) { delete_metadata( 'post', 0, $key, '', true ); delete_metadata( 'term', 0, $key, '', true ); } $order_keys = array( '_devoynx_rewards_awarded_points', '_devoynx_rewards_award_entry', '_devoynx_rewards_reversed_points', '_devoynx_rewards_redeemed_points', '_devoynx_rewards_redemption_state', '_devoynx_rewards_redemption_attempt', '_devoynx_rewards_quote', '_devoynx_rewards_returned_points' ); foreach ( $order_keys as $key ) { delete_metadata( 'post', 0, $key, '', true ); } foreach ( array( 'wc_orders_meta', 'woocommerce_order_itemmeta' ) as $suffix ) { $table = $wpdb->prefix . $suffix; if ( $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $wpdb->esc_like( $table ) ) ) === $table ) { foreach ( $order_keys as $key ) { $wpdb->delete( $table, array( 'meta_key' => $key ), array( '%s' ) ); // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- Exact owned-key cleanup during explicit uninstall, never a frontend query. } } } delete_option( 'devoynx_rewards_settings' ); delete_option( 'devoynx_rewards_program_schema' ); delete_option( 'devoynx_rewards_recognition' ); delete_option( 'devoynx_rewards_email_settings' ); delete_option( 'devoynx_rewards_spin' ); delete_option( 'devoynx_rewards_guest_claims' ); delete_option( 'devoynx_rewards_basic_referrals' ); delete_option( 'devoynx_rewards_guest_cleanup_cursor' ); delete_option( 'devoynx_rewards_guest_mail_cursor' ); delete_option( Migrator::OPTION_NAME ); self::session_selections(); return true; } /** Remove only our saved selections, never another plugin's cart/session data. */ private static function session_selections() { global $wpdb; $table = $wpdb->prefix . 'woocommerce_sessions'; if ( $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $wpdb->esc_like( $table ) ) ) !== $table ) { return; } $last_id = 0; do { $rows = $wpdb->get_results( $wpdb->prepare( 'SELECT session_id, session_value FROM %i WHERE session_id > %d AND session_value LIKE %s ORDER BY session_id LIMIT 100', $table, $last_id, '%' . $wpdb->esc_like( 'devoynx_rewards_' ) . '%' ), ARRAY_A ); foreach ( $rows as $row ) { $last_id = (int) $row['session_id']; $data = maybe_unserialize( $row['session_value'] ); if ( ! is_array( $data ) ) { continue; } unset( $data['devoynx_rewards_redeem'], $data['devoynx_rewards_quote'] ); // Compare-and-set preserves a cart concurrently updated during uninstall. $wpdb->update( $table, array( 'session_value' => maybe_serialize( $data ) ), array( 'session_id' => $last_id, 'session_value' => $row['session_value'], ), array( '%s' ), array( '%d', '%s' ) ); } $count = count( $rows ); } while ( 100 === $count ); if ( class_exists( 'WC_Cache_Helper' ) && defined( 'WC_SESSION_CACHE_GROUP' ) ) { \WC_Cache_Helper::invalidate_cache_group( WC_SESSION_CACHE_GROUP ); } } }