diff --git a/backend/igny8_core/auth/migrations/0031_drop_all_blueprint_tables.py b/backend/igny8_core/auth/migrations/0031_drop_all_blueprint_tables.py new file mode 100644 index 00000000..af1aaf6b --- /dev/null +++ b/backend/igny8_core/auth/migrations/0031_drop_all_blueprint_tables.py @@ -0,0 +1,43 @@ +# Generated manually on 2026-01-13 +# Purpose: Drop all remaining blueprint-related tables + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('igny8_core_auth', '0030_drop_site_blueprints_table'), + ] + + operations = [ + migrations.RunSQL( + sql=""" + -- Drop foreign key constraints first + ALTER TABLE IF EXISTS igny8_page_blueprints + DROP CONSTRAINT IF EXISTS igny8_page_blueprints_sector_id_c7e67972_fk_igny8_sectors_id; + + ALTER TABLE IF EXISTS igny8_site_blueprint_taxonomies + DROP CONSTRAINT IF EXISTS igny8_site_blueprint_sector_id_d80376a0_fk_igny8_sec; + + ALTER TABLE IF EXISTS igny8_site_blueprint_clusters + DROP CONSTRAINT IF EXISTS igny8_site_blueprint_sector_id_34c615f1_fk_igny8_sec; + + -- Drop tables in correct order (child tables first) + DROP TABLE IF EXISTS igny8_site_blueprint_taxonomies_clusters CASCADE; + DROP TABLE IF EXISTS igny8_site_blueprint_taxonomies CASCADE; + DROP TABLE IF EXISTS igny8_site_blueprint_clusters CASCADE; + DROP TABLE IF EXISTS igny8_page_blueprints CASCADE; + + -- Drop any remaining sequences + DROP SEQUENCE IF EXISTS igny8_page_blueprints_id_seq; + DROP SEQUENCE IF EXISTS igny8_site_blueprint_taxonomies_id_seq; + DROP SEQUENCE IF EXISTS igny8_site_blueprint_clusters_id_seq; + DROP SEQUENCE IF EXISTS igny8_site_blueprint_taxonomies_clusters_id_seq; + """, + reverse_sql=""" + -- Cannot reverse this migration - table structures were removed from models + SELECT 1; + """ + ), + ] diff --git a/plugins/wordpress/source/igny8-wp-bridge/uninstall.php b/plugins/wordpress/source/igny8-wp-bridge/uninstall.php index b0764afd..02aebf6d 100644 --- a/plugins/wordpress/source/igny8-wp-bridge/uninstall.php +++ b/plugins/wordpress/source/igny8-wp-bridge/uninstall.php @@ -12,40 +12,119 @@ if (!defined('WP_UNINSTALL_PLUGIN')) { exit; } -// Remove all options -delete_option('igny8_access_token'); -delete_option('igny8_refresh_token'); -delete_option('igny8_email'); -delete_option('igny8_site_id'); -delete_option('igny8_last_site_sync'); -delete_option('igny8_last_site_import_id'); -delete_option('igny8_token_refreshed_at'); -delete_option('igny8_bridge_version'); +// Remove all IGNY8 options from wp_options table +$igny8_options = array( + // Authentication & Connection + 'igny8_access_token', + 'igny8_refresh_token', + 'igny8_api_key', + 'igny8_email', + 'igny8_site_id', + 'igny8_integration_id', + 'igny8_access_token_issued', + 'igny8_token_refreshed_at', + 'igny8_bridge_version', + + // API & Health + 'igny8_last_api_health_check', + 'igny8_api_key_revoked', + + // Site Sync Timestamps + 'igny8_last_site_sync', + 'igny8_last_site_import_id', + 'igny8_last_structure_sync', + 'igny8_last_taxonomy_sync', + 'igny8_last_keyword_sync', + 'igny8_last_writer_sync', + 'igny8_last_full_site_scan', + 'igny8_last_semantic_map', + 'igny8_last_semantic_map_summary', + 'igny8_last_incremental_site_sync', + 'igny8_last_link_graph_sync', + 'igny8_last_link_graph_count', + 'igny8_last_sync_from_igny8', + 'igny8_last_site_snapshot', + + // Settings & Configuration + 'igny8_default_post_status', + 'igny8_default_author_role', + 'igny8_enable_woocommerce', + 'igny8_enable_two_way_sync', + 'igny8_connection_enabled', + 'igny8_control_mode', + 'igny8_widgets_enabled', + 'igny8_toc_min_headings', + 'igny8_auto_create_authors', + 'igny8_show_image_description', + + // Module & Feature Toggles + 'igny8_enabled_modules', + 'igny8_enabled_post_types', + 'igny8_enabled_taxonomies', + 'igny8_available_modules', + 'igny8_supported_post_types', + 'igny8_supported_taxonomies', + + // Data & Mappings + 'igny8_taxonomy_sector_mappings', + 'igny8_link_queue', + 'igny8_webhook_logs', + 'igny8_site_scan_settings', + 'igny8_site_metadata_v1', + + // Sync & Queue + 'igny8_sync_enabled', +); -// Remove all post meta (optional - uncomment if you want to remove all meta on uninstall) -/* +// Delete all IGNY8 options +foreach ($igny8_options as $option) { + delete_option($option); +} + +// Remove all post meta (IGNY8-specific metadata on posts) global $wpdb; $wpdb->query(" DELETE FROM {$wpdb->postmeta} - WHERE meta_key LIKE '_igny8_%' + WHERE meta_key LIKE '_igny8_%' OR meta_key LIKE 'igny8_%' "); -*/ -// Unschedule cron jobs -$timestamp = wp_next_scheduled('igny8_sync_post_statuses'); -if ($timestamp) { - wp_unschedule_event($timestamp, 'igny8_sync_post_statuses'); +// Unschedule ALL cron jobs +$cron_hooks = array( + 'igny8_sync_post_statuses', + 'igny8_sync_site_data', + 'igny8_sync_from_igny8', + 'igny8_cron_sync_post_statuses', + 'igny8_cron_sync_site_data', + 'igny8_cron_sync_from_igny8', + 'igny8_cron_full_site_scan', + 'igny8_cron_sync_keywords', + 'igny8_cron_sync_taxonomies', + 'igny8_clear_old_webhook_logs', + 'igny8_batch_sync_post_statuses', +); + +foreach ($cron_hooks as $hook) { + $timestamp = wp_next_scheduled($hook); + while ($timestamp) { + wp_unschedule_event($timestamp, $hook); + $timestamp = wp_next_scheduled($hook); + } + // Also clear any hooks from the cron array + wp_clear_scheduled_hook($hook); } -$timestamp = wp_next_scheduled('igny8_sync_site_data'); -if ($timestamp) { - wp_unschedule_event($timestamp, 'igny8_sync_site_data'); -} +// Remove all IGNY8 transients +$wpdb->query(" + DELETE FROM {$wpdb->options} + WHERE option_name LIKE '_transient_igny8_%' + OR option_name LIKE '_transient_timeout_igny8_%' +"); -$timestamp = wp_next_scheduled('igny8_sync_from_igny8'); -if ($timestamp) { - wp_unschedule_event($timestamp, 'igny8_sync_from_igny8'); -} +// Remove any IGNY8 user meta +$wpdb->query(" + DELETE FROM {$wpdb->usermeta} + WHERE meta_key LIKE 'igny8_%' OR meta_key LIKE '_igny8_%' +"); // Note: Taxonomies and terms are NOT deleted // They remain in WordPress for user reference