PluginProbe
Search Atlas SEO – OTTO AI SEO Automation for WordPress / trunk
Search Atlas SEO – OTTO AI SEO Automation for WordPress vtrunk
2.6.26 2.6.25 2.6.24 2.6.23 2.6.22 2.6.21 2.6.20 2.6.19 2.6.18 2.6.17 2.6.16 2.6.15 2.6.14 2.6.13 2.6.12 2.6.11 2.6.10 2.6.9 2.6.8 2.6.7 2.6.6 2.6.5 2.6.4 2.6.3 2.5.23 All 138 releases
metasync / uninstall.php

uninstall.php in Search Atlas SEO – OTTO AI SEO Automation for WordPress trunk, at uninstall.php

150 lines 5.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Fired when the plugin is uninstalled.
5 *
6 * Cleanup policy:
7 *
8 * - Credentials (the Google Indexing service account — a plaintext private
9 * key — and the IndexNow API key) are ALWAYS deleted. They must never be
10 * left behind in wp_options by a plugin that is no longer installed.
11 * - Everything else (custom tables, options, transients, per-post SEO meta,
12 * log files) is only removed when the site owner opted in via the
13 * "Delete all plugin data when the plugin is uninstalled" toggle in
14 * Advanced Settings. The default is OFF, per WordPress uninstall guidelines.
15 *
16 * The opt-in option is read BEFORE any options are deleted, because the
17 * option itself is plugin data.
18 *
19 * For multisite, the cleanup runs once per site when the plugin is
20 * network-activated and removed.
21 *
22 * @link https://searchatlas.com
23 * @since 1.0.0
24 *
25 * @package Metasync
26 */
27
28 // If uninstall not called from WordPress, then exit.
29 if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
30 exit;
31 }
32
33 /**
34 * Remove plugin data for the current site.
35 *
36 * @return void
37 */
38 function metasync_uninstall_cleanup() {
39 global $wpdb;
40
41 // Read the opt-in first: the option itself is plugin data and is removed
42 // by the prefix sweep below.
43 $delete_all_data = ( 'yes' === get_option( 'metasync_delete_data_on_uninstall', 'no' ) );
44
45 // Credentials are always removed, regardless of the opt-in.
46 delete_option( 'google_index_service_account' );
47 delete_option( 'metasync_options_bing_instant_indexing' );
48 // Legacy instant-indexing option: holds the Google service-account JSON key.
49 delete_option( 'metasync_options_instant_indexing' );
50
51 if ( ! $delete_all_data ) {
52 return;
53 }
54
55 // Scheduled events.
56 $cron_hooks = array(
57 'metasync_daily_cleanup',
58 'metasync_otto_js_check_event',
59 'metasync_process_otto_batch_cache_job',
60 'metasync_process_otto_crawl_url_job',
61 'metasync_sitemap_async_warmup_event',
62 'metasync_media_batch_optimize_cron',
63 'metasync_check_debug_limits',
64 'metasync_speed_cache_cleanup',
65 'metasync_bing_indexnow_submit_event',
66 );
67 foreach ( $cron_hooks as $cron_hook ) {
68 wp_clear_scheduled_hook( $cron_hook );
69 }
70
71 // Custom tables.
72 $tables = array(
73 'metasync_404_logs',
74 'metasync_redirections',
75 'metasync_heartbeat_error_logs',
76 'metasync_sync_history',
77 'metasync_otto_excluded_urls',
78 'metasync_robots_txt_backups',
79 'metasync_otto_bot_stats',
80 'metasync_otto_bot_logs',
81 );
82 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.
84 }
85
86 // Plugin options and transients (transients live in the options table
87 // under _transient_/_transient_timeout_ prefixes when no object cache
88 // persists them; object-cache-backed transients age out on their own).
89 $option_patterns = array(
90 'metasync\_%',
91 '\_transient\_metasync\_%',
92 '\_transient\_timeout\_metasync\_%',
93 '\_site\_transient\_metasync\_%',
94 '\_site\_transient\_timeout\_metasync\_%',
95 );
96 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.
98 }
99
100 // Per-post SEO values saved by the plugin (custom titles, meta
101 // descriptions, robots directives, schema, Open Graph, canonical URLs).
102 // Several metaboxes store their values without the leading underscore
103 // (metasync_common_robots, metasync_schema_markup, metasync_advance_robots,
104 // metasync_post, metasync_post_redirection_meta), so both prefixes are
105 // 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.
107
108 // On-disk data directory (error logs, zipped logs, cache artifacts).
109 $metasync_data_dir = WP_CONTENT_DIR . '/metasync_data';
110 if ( is_dir( $metasync_data_dir ) ) {
111 metasync_uninstall_rrmdir( $metasync_data_dir );
112 }
113 }
114
115 /**
116 * Recursively delete a directory.
117 *
118 * @param string $dir Absolute directory path.
119 * @return void
120 */
121 function metasync_uninstall_rrmdir( $dir ) {
122 if ( ! is_dir( $dir ) ) {
123 return;
124 }
125 foreach ( scandir( $dir ) as $entry ) {
126 if ( '.' === $entry || '..' === $entry ) {
127 continue;
128 }
129 $path = $dir . '/' . $entry;
130 if ( is_dir( $path ) ) {
131 metasync_uninstall_rrmdir( $path );
132 } else {
133 @unlink( $path ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged -- best-effort cleanup on uninstall.
134 }
135 }
136 @rmdir( $dir ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged -- best-effort cleanup on uninstall.
137 }
138
139 if ( is_multisite() ) {
140 $metasync_uninstall_site_ids = get_sites( array( 'fields' => 'ids', 'number' => 0 ) );
141 foreach ( $metasync_uninstall_site_ids as $metasync_uninstall_site_id ) {
142 switch_to_blog( $metasync_uninstall_site_id );
143 metasync_uninstall_cleanup();
144 }
145 restore_current_blog();
146 unset( $metasync_uninstall_site_ids, $metasync_uninstall_site_id );
147 } else {
148 metasync_uninstall_cleanup();
149 }
150