| @@ -29,8 +29,18 @@ | ||
| 29 | 29 | if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) { |
| 30 | 30 | exit; |
| 31 | 31 | } |
| 32 | 32 | |
| 33 | +// Consent-gated churn signal. Sent first, while the consent option still | |
| 34 | +// exists below; sends nothing when the site never opted in. The plugin main | |
| 35 | +// file is not loaded during uninstall, so the key constant it normally | |
| 36 | +// defines must be defined here or track() is a silent no-op. | |
| 37 | +if ( ! defined( 'METASYNC_POSTHOG_API_KEY' ) ) { | |
| 38 | + define( 'METASYNC_POSTHOG_API_KEY', getenv('METASYNC_POSTHOG_API_KEY') !== false ? getenv('METASYNC_POSTHOG_API_KEY') : 'phc_ntSayCJE7Ad9eBHRG6ygBaY4BJMa8rFjXcXESun9ftkh' ); // gitleaks:allow -- public write-only PostHog project key | |
| 39 | +} | |
| 40 | +require_once plugin_dir_path( __FILE__ ) . 'includes/class-metasync-posthog.php'; | |
| 41 | +Metasync_PostHog::get_instance()->track( 'plugin_uninstalled', array() ); | |
| 42 | + | |
| 33 | 43 | /** |
| 34 | 44 | * Remove plugin data for the current site. |
| 35 | 45 | * |
| 36 | 46 | * @return void |
| @@ -62,8 +72,9 @@ | ||
| 62 | 72 | 'metasync_media_batch_optimize_cron', |
| 63 | 73 | 'metasync_check_debug_limits', |
| 64 | 74 | 'metasync_speed_cache_cleanup', |
| 65 | 75 | 'metasync_bing_indexnow_submit_event', |
| 76 | + 'metasync_ph_flush_rollups', | |
| 66 | 77 | ); |
| 67 | 78 | foreach ( $cron_hooks as $cron_hook ) { |
| 68 | 79 | wp_clear_scheduled_hook( $cron_hook ); |
| 69 | 80 | } |
| @@ -79,9 +90,9 @@ | ||
| 79 | 90 | 'metasync_otto_bot_stats', |
| 80 | 91 | 'metasync_otto_bot_logs', |
| 81 | 92 | ); |
| 82 | 93 | foreach ( $tables as $table ) { |
| 83 | - $wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}{$table}" ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- static table names, no user input. | |
| 94 | + $wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}{$table}" ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- static table names, no user input. | |
| 84 | 95 | } |
| 85 | 96 | |
| 86 | 97 | // Plugin options and transients (transients live in the options table |
| 87 | 98 | // under _transient_/_transient_timeout_ prefixes when no object cache |
| @@ -93,9 +104,9 @@ | ||
| 93 | 104 | '\_site\_transient\_metasync\_%', |
| 94 | 105 | '\_site\_transient\_timeout\_metasync\_%', |
| 95 | 106 | ); |
| 96 | 107 | foreach ( $option_patterns as $option_pattern ) { |
| 97 | - $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->options} WHERE option_name LIKE %s", $option_pattern ) ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- table name from core. | |
| 108 | + $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->options} WHERE option_name LIKE %s", $option_pattern ) ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- table name from core. | |
| 98 | 109 | } |
| 99 | 110 | |
| 100 | 111 | // Per-post SEO values saved by the plugin (custom titles, meta |
| 101 | 112 | // descriptions, robots directives, schema, Open Graph, canonical URLs). |
| @@ -102,9 +113,9 @@ | ||
| 102 | 113 | // Several metaboxes store their values without the leading underscore |
| 103 | 114 | // (metasync_common_robots, metasync_schema_markup, metasync_advance_robots, |
| 104 | 115 | // metasync_post, metasync_post_redirection_meta), so both prefixes are |
| 105 | 116 | // swept. |
| 106 | - $wpdb->query( "DELETE FROM {$wpdb->postmeta} WHERE meta_key LIKE '\_metasync\_%' OR meta_key LIKE 'metasync\_%'" ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- literal patterns, no user input. | |
| 117 | + $wpdb->query( "DELETE FROM {$wpdb->postmeta} WHERE meta_key LIKE '\_metasync\_%' OR meta_key LIKE 'metasync\_%'" ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- literal patterns, no user input. | |
| 107 | 118 | |
| 108 | 119 | // On-disk data directory (error logs, zipped logs, cache artifacts). |
| 109 | 120 | $metasync_data_dir = WP_CONTENT_DIR . '/metasync_data'; |
| 110 | 121 | if ( is_dir( $metasync_data_dir ) ) { |
| @@ -129,12 +140,12 @@ | ||
| 129 | 140 | $path = $dir . '/' . $entry; |
| 130 | 141 | if ( is_dir( $path ) ) { |
| 131 | 142 | metasync_uninstall_rrmdir( $path ); |
| 132 | 143 | } else { |
| 133 | - @unlink( $path ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged -- best-effort cleanup on uninstall. | |
| 144 | + @wp_delete_file( $path ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged -- best-effort cleanup on uninstall. | |
| 134 | 145 | } |
| 135 | 146 | } |
| 136 | - @rmdir( $dir ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged -- best-effort cleanup on uninstall. | |
| 147 | + @rmdir( $dir ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged, WordPress.WP.AlternativeFunctions.file_system_operations_rmdir -- best-effort cleanup on uninstall; WP_Filesystem would prompt for FTP credentials on non-direct hosts. | |
| 137 | 148 | } |
| 138 | 149 | |
| 139 | 150 | if ( is_multisite() ) { |
| 140 | 151 | $metasync_uninstall_site_ids = get_sites( array( 'fields' => 'ids', 'number' => 0 ) ); |