$addsynapse_search_widgets ) { if ( ! is_array( $addsynapse_search_widgets ) ) { continue; } $addsynapse_search_kept = array_values( array_filter( $addsynapse_search_widgets, static function ( $id ) { return 0 !== strpos( (string) $id, 'addsynapse_search_filter_widget-' ); } ) ); if ( count( $addsynapse_search_kept ) !== count( $addsynapse_search_widgets ) ) { $addsynapse_search_sidebars[ $addsynapse_search_sidebar ] = $addsynapse_search_kept; $addsynapse_search_changed = true; } } if ( $addsynapse_search_changed ) { update_option( 'sidebars_widgets', $addsynapse_search_sidebars ); } } wp_clear_scheduled_hook( 'addsynapse_search_hub_refresh' ); // Λίστα εκκρεμών διαγραφών: μία γραμμή ανά id (βλ. Addsynapse_Search_Indexer::PDEL_PREFIX). // Πραγματικές γραμμές wp_options (όχι transients) — σβήνονται ΚΑΙ με persistent object cache. // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- μαζικός καθαρισμός στο uninstall, δεν υπάρχει WP API βάσει προθέματος. $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->options} WHERE option_name LIKE %s", $wpdb->esc_like( 'addsynapse_search_pdel_' ) . '%' ) ); // Locks της ροής Connect (Addsynapse_Search_Hub::LOCK_PREFIX) — γραμμές wp_options, συνήθως ήδη σβησμένες. // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- μαζικός καθαρισμός στο uninstall, δεν υπάρχει WP API βάσει προθέματος. $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->options} WHERE option_name LIKE %s", $wpdb->esc_like( 'addsynapse_search_connect_lock_' ) . '%' ) ); // Transients με ΑΚΡΙΒΗ κλειδιά — delete_transient() δουλεύει ΚΑΙ με // persistent object cache (Redis/Memcached), όπου το wp_options δεν έχει // τίποτα να σβήσει (audit F14). $addsynapse_search_transients = array( 'addsynapse_search_tenant_token', 'addsynapse_search_relink_guard', 'addsynapse_search_license_status', 'addsynapse_search_token_backoff', 'addsynapse_search_token_refresh_lock', 'addsynapse_search_token_failures', 'addsynapse_search_plan_limit_hit', 'addsynapse_search_cron_checked', 'addsynapse_search_stats_7', 'addsynapse_search_stats_30', 'addsynapse_search_stats_90', 'addsynapse_search_term_links_categories', 'addsynapse_search_term_links_brand', 'addsynapse_search_cat_terms', 'addsynapse_search_connect_nopoll', 'addsynapse_search_storefront_probe', 'addsynapse_search_tq_down', 'addsynapse_search_tq_novis', ); foreach ( $addsynapse_search_transients as $addsynapse_search_transient ) { delete_transient( $addsynapse_search_transient ); } // Ανά χρήστη διαχειριστή (βλ. Addsynapse_Search_License::pending_key_transient()). $addsynapse_search_user_ids = get_users( array( 'fields' => 'ID', 'number' => 500, 'capability' => 'manage_woocommerce', ) ); foreach ( (array) $addsynapse_search_user_ids as $addsynapse_search_user_id ) { delete_transient( 'addsynapse_search_pending_key_' . (int) $addsynapse_search_user_id ); delete_transient( 'addsynapse_search_register_limit_' . (int) $addsynapse_search_user_id ); delete_transient( 'addsynapse_search_connect_pending_' . (int) $addsynapse_search_user_id ); } // Δίχτυ ασφαλείας ΜΟΝΟ χωρίς persistent object cache: ό,τι transient // `addsynapse_search_` έμεινε ορφανό (π.χ. από άλλο module) στο wp_options. if ( ! wp_using_ext_object_cache() ) { // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- μαζικός καθαρισμός στο uninstall, δεν υπάρχει WP API βάσει προθέματος. $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->options} WHERE option_name LIKE %s OR option_name LIKE %s", $wpdb->esc_like( '_transient_addsynapse_search_' ) . '%', $wpdb->esc_like( '_transient_timeout_addsynapse_search_' ) . '%' ) ); } // Action Scheduler: ΟΛΕΣ οι ενέργειες της ομάδας μας. if ( function_exists( 'as_unschedule_all_actions' ) ) { as_unschedule_all_actions( '', array(), 'addsynapse-search' ); } else { addsynapse_search_uninstall_purge_action_scheduler_tables(); } } /** * Αν υπάρχει ο πίνακας. * * @param string $table Πλήρες όνομα πίνακα. * @return bool */ function addsynapse_search_uninstall_table_exists( $table ) { global $wpdb; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- uninstall χωρίς WooCommerce: δεν υπάρχει API του Action Scheduler. return $table === $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $wpdb->esc_like( $table ) ) ); } /** * Uninstall με ανενεργό WooCommerce: το API του Action Scheduler δεν φορτώθηκε, αλλά οι * πίνακές του μένουν στη βάση με τις ενέργειες της ομάδας μας. Τις σβήνουμε απευθείας — * ΜΟΝΟ της ομάδας `addsynapse-search`, και ΜΟΝΟ αν υπάρχουν οι πίνακες (αλλιώς τίποτα). * * @return void */ function addsynapse_search_uninstall_purge_action_scheduler_tables() { global $wpdb; if ( ! addsynapse_search_uninstall_table_exists( $wpdb->prefix . 'actionscheduler_groups' ) || ! addsynapse_search_uninstall_table_exists( $wpdb->prefix . 'actionscheduler_actions' ) ) { return; } // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- uninstall χωρίς WooCommerce: δεν υπάρχει API του Action Scheduler. $addsynapse_search_group_id = (int) $wpdb->get_var( $wpdb->prepare( "SELECT group_id FROM {$wpdb->prefix}actionscheduler_groups WHERE slug = %s", 'addsynapse-search' ) ); if ( $addsynapse_search_group_id <= 0 ) { return; } if ( addsynapse_search_uninstall_table_exists( $wpdb->prefix . 'actionscheduler_logs' ) ) { // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- βλ. παραπάνω. $wpdb->query( $wpdb->prepare( "DELETE l FROM {$wpdb->prefix}actionscheduler_logs l INNER JOIN {$wpdb->prefix}actionscheduler_actions a ON a.action_id = l.action_id WHERE a.group_id = %d", $addsynapse_search_group_id ) ); } // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- βλ. παραπάνω. $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}actionscheduler_actions WHERE group_id = %d", $addsynapse_search_group_id ) ); } if ( is_multisite() && function_exists( 'get_sites' ) ) { $addsynapse_search_site_ids = get_sites( array( 'fields' => 'ids', 'number' => 10000, ) ); foreach ( $addsynapse_search_site_ids as $addsynapse_search_site_id ) { switch_to_blog( (int) $addsynapse_search_site_id ); addsynapse_search_uninstall_current_site(); restore_current_blog(); } delete_site_option( 'addsynapse_search_settings' ); delete_site_option( 'addsynapse_search_attribute_labels' ); delete_site_option( 'addsynapse_search_sync_run' ); } else { addsynapse_search_uninstall_current_site(); }