chore: initial snapshot of 2meet-data-optimizer v0.1.0
Baseline before backporting wp-data-optimizer v3.0.1-v3.4.6. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TbG1keQQ7XBa7qMQY16KCY
This commit is contained in:
+244
@@ -0,0 +1,244 @@
|
||||
<?php
|
||||
/**
|
||||
* WP Data Optimizer — Uninstall script.
|
||||
*
|
||||
* Runs only when the plugin is deleted via the WordPress admin.
|
||||
* Removes all WPDO tables and options. Does NOT remove HPCT tables.
|
||||
*
|
||||
* v2.2.0 hardening: take a `pre_uninstall` snapshot BEFORE dropping tables.
|
||||
* The snapshot file under wp-content/uploads/wpdo-backups/ survives plugin
|
||||
* deletion (uploads dir is never auto-purged), so the user can re-install +
|
||||
* `wp wpdo snapshot restore <id> --apply` to recover.
|
||||
*
|
||||
* v2.14.0 multisite hardening: when network-uninstalled, iterate all sites
|
||||
* via switch_to_blog so every wp_N_wpdo_* table is dropped (previously only
|
||||
* the main site got cleaned, leaving orphans on every other site).
|
||||
*
|
||||
* @package WP_Data_Optimizer
|
||||
*/
|
||||
|
||||
if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
global $wpdb;
|
||||
|
||||
// ── Load shared cleanup logic + snapshot classes ─────────────────────────
|
||||
$bootstrap_files = array(
|
||||
__DIR__ . '/includes/class-tmdo-logger.php',
|
||||
__DIR__ . '/includes/class-tmdo-feature-flags.php',
|
||||
__DIR__ . '/includes/class-tmdo-installer.php',
|
||||
__DIR__ . '/includes/snapshots/class-tmdo-snapshot-manager.php',
|
||||
__DIR__ . '/includes/snapshots/class-tmdo-snapshot-writer.php',
|
||||
__DIR__ . '/includes/snapshots/class-tmdo-snapshot-reader.php',
|
||||
__DIR__ . '/includes/snapshots/class-tmdo-snapshot-pruner.php',
|
||||
);
|
||||
$bootstrap_ok = true;
|
||||
foreach ( $bootstrap_files as $f ) {
|
||||
if ( ! is_file( $f ) ) {
|
||||
$bootstrap_ok = false;
|
||||
continue;
|
||||
}
|
||||
require_once $f;
|
||||
}
|
||||
|
||||
// ── v2.2.0 M1.5: pre-uninstall snapshot (main-site context only) ─────────
|
||||
// Snapshot is taken once on the main site — it captures the catalog of all
|
||||
// wpdo_snapshots rows (which is per-site so per-site snapshots survive the
|
||||
// site-level table DROP that happens later). Best-effort.
|
||||
if ( $bootstrap_ok && class_exists( 'TMDO_Snapshot_Manager' ) ) {
|
||||
$result = TMDO_Snapshot_Manager::create(
|
||||
'pre_uninstall',
|
||||
array(),
|
||||
array(
|
||||
'notes' => 'Auto-snapshot taken at plugin uninstall time',
|
||||
'retention_days' => 365,
|
||||
'inline_threshold_bytes' => 0,
|
||||
)
|
||||
);
|
||||
if ( ! empty( $result['ok'] ) ) {
|
||||
$snapshot_id = $result['snapshot_id'];
|
||||
$dir = TMDO_Snapshot_Manager::backup_dir();
|
||||
if ( is_dir( $dir ) ) {
|
||||
file_put_contents(
|
||||
trailingslashit( $dir ) . 'README-pre-uninstall.txt',
|
||||
"WPDO pre-uninstall snapshot: {$snapshot_id}\n"
|
||||
. 'Created: ' . gmdate( 'Y-m-d H:i:s' ) . " UTC\n\n"
|
||||
. "To restore after re-installing wp-data-optimizer:\n"
|
||||
. " 1. Re-install the plugin (it will re-create wp_wpdo_snapshots).\n"
|
||||
. " 2. Manually re-insert this snapshot's catalog row, or use wp wpdo snapshot list to confirm.\n"
|
||||
. " 3. Run: wp wpdo snapshot restore {$snapshot_id} --apply\n"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── v2.14.0: shared cleanup helper ───────────────────────────────────────
|
||||
// Falls back to inline DROP loop if the helper class isn't loadable
|
||||
// (e.g. partially-broken install where includes/class-tmdo-installer.php
|
||||
// is missing). The inline path is the original v2.13.x logic verbatim.
|
||||
$has_helper = class_exists( 'TMDO_Installer' )
|
||||
&& method_exists( 'TMDO_Installer', 'drop_all_tables_for_current_blog' );
|
||||
|
||||
/**
|
||||
* Run the cleanup for the current blog (helper-aware).
|
||||
*/
|
||||
$run_cleanup = static function () use ( $has_helper ): void {
|
||||
global $wpdb;
|
||||
|
||||
if ( $has_helper ) {
|
||||
TMDO_Installer::drop_all_tables_for_current_blog();
|
||||
return;
|
||||
}
|
||||
|
||||
// ── Fallback inline path (helper unavailable) ─────────────────────────
|
||||
$tables = array(
|
||||
$wpdb->prefix . 'wpdo_migrations',
|
||||
$wpdb->prefix . 'wpdo_errors',
|
||||
$wpdb->prefix . 'wpdo_benchmarks',
|
||||
$wpdb->prefix . 'wpdo_warm',
|
||||
$wpdb->prefix . 'wpdo_archive',
|
||||
$wpdb->prefix . 'wpdo_audit',
|
||||
$wpdb->prefix . 'wpdo_shadow_diffs',
|
||||
$wpdb->prefix . 'wpdo_site_metrics',
|
||||
$wpdb->prefix . 'wpdo_registry_meta',
|
||||
$wpdb->prefix . 'wpdo_uni_options',
|
||||
$wpdb->prefix . 'wpdo_wc_commissions',
|
||||
$wpdb->prefix . 'wpdo_snapshots',
|
||||
$wpdb->prefix . 'wpdo_migration_status',
|
||||
$wpdb->prefix . 'wpdo_user_points_ledger',
|
||||
$wpdb->prefix . 'wpdo_user_membership',
|
||||
$wpdb->prefix . 'wpdo_user_activity',
|
||||
$wpdb->prefix . 'wpdo_user_profile',
|
||||
$wpdb->prefix . 'wpdo_user_sso',
|
||||
$wpdb->prefix . 'wpdo_user_core_profile',
|
||||
$wpdb->prefix . 'wpdo_user_social',
|
||||
$wpdb->prefix . 'wpdo_user_commerce',
|
||||
$wpdb->prefix . 'wpdo_user_hp_user',
|
||||
$wpdb->prefix . 'wpdo_user_admin_prefs',
|
||||
$wpdb->prefix . 'wpdo_post_wp_core',
|
||||
$wpdb->prefix . 'wpdo_post_attachment',
|
||||
$wpdb->prefix . 'wpdo_post_wc_product',
|
||||
$wpdb->prefix . 'wpdo_post_hp_listing_core',
|
||||
$wpdb->prefix . 'wpdo_post_hp_request_core',
|
||||
$wpdb->prefix . 'wpdo_post_hp_vendor_core',
|
||||
$wpdb->prefix . 'wpdo_post_nav_menu_item',
|
||||
$wpdb->prefix . 'wpdo_hot_hp_listing',
|
||||
$wpdb->prefix . 'wpdo_term_hp_taxonomy',
|
||||
$wpdb->prefix . 'wpdo_comment_hp_review',
|
||||
$wpdb->prefix . 'wpdo_term_misc',
|
||||
$wpdb->prefix . 'wpdo_comment_misc',
|
||||
// v3.0.0: HivePress family integration tables.
|
||||
$wpdb->prefix . 'wpdo_hot_hp_request',
|
||||
$wpdb->prefix . 'wpdo_hot_hp_membership',
|
||||
$wpdb->prefix . 'wpdo_hot_hp_membership_plan',
|
||||
$wpdb->prefix . 'wpdo_hot_hp_booking',
|
||||
$wpdb->prefix . 'wpdo_comment_hp_message',
|
||||
$wpdb->prefix . 'wpdo_comment_hp_favorite',
|
||||
$wpdb->prefix . 'wpdo_comment_hp_offer',
|
||||
$wpdb->prefix . 'wpdo_term_hp_listing_tag',
|
||||
);
|
||||
|
||||
$hot_like = $wpdb->esc_like( $wpdb->prefix . 'wpdo_hot_' ) . '%';
|
||||
$cold_like = $wpdb->esc_like( $wpdb->prefix . 'wpdo_cold_' ) . '%';
|
||||
$entity_like = $wpdb->esc_like( $wpdb->prefix . 'wpdo_user_' ) . '%';
|
||||
$post_ent_like = $wpdb->esc_like( $wpdb->prefix . 'wpdo_post_' ) . '%';
|
||||
$term_ent_like = $wpdb->esc_like( $wpdb->prefix . 'wpdo_term_' ) . '%';
|
||||
$comment_ent_like = $wpdb->esc_like( $wpdb->prefix . 'wpdo_comment_' ) . '%';
|
||||
|
||||
if ( class_exists( 'WP_SQLite_Driver' ) ) {
|
||||
$dynamic = $wpdb->get_col(
|
||||
$wpdb->prepare(
|
||||
"SELECT name FROM sqlite_master WHERE type='table' AND (name LIKE %s OR name LIKE %s OR name LIKE %s OR name LIKE %s OR name LIKE %s OR name LIKE %s)",
|
||||
$hot_like,
|
||||
$cold_like,
|
||||
$entity_like,
|
||||
$post_ent_like,
|
||||
$term_ent_like,
|
||||
$comment_ent_like
|
||||
)
|
||||
);
|
||||
} else {
|
||||
$dynamic = $wpdb->get_col(
|
||||
$wpdb->prepare(
|
||||
'SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND (TABLE_NAME LIKE %s OR TABLE_NAME LIKE %s OR TABLE_NAME LIKE %s OR TABLE_NAME LIKE %s OR TABLE_NAME LIKE %s OR TABLE_NAME LIKE %s)',
|
||||
$hot_like,
|
||||
$cold_like,
|
||||
$entity_like,
|
||||
$post_ent_like,
|
||||
$term_ent_like,
|
||||
$comment_ent_like
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$tables = array_unique( array_merge( $tables, $dynamic ?: array() ) );
|
||||
$prefix = $wpdb->prefix . 'wpdo_';
|
||||
foreach ( $tables as $table ) {
|
||||
if ( ! preg_match( '/^[a-zA-Z0-9_]+$/', $table ) || strpos( $table, $prefix ) !== 0 ) {
|
||||
continue;
|
||||
}
|
||||
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
|
||||
$wpdb->query( "DROP TABLE IF EXISTS `{$table}`" );
|
||||
}
|
||||
|
||||
delete_option( 'wpdo_db_version' );
|
||||
delete_option( 'wpdo_features' );
|
||||
delete_option( 'wpdo_features_shadow' );
|
||||
delete_option( 'wpdo_hpct_imported' );
|
||||
delete_option( 'wpdo_hook_bus_enabled' );
|
||||
delete_option( 'wpdo_v2_features_backup' );
|
||||
delete_option( 'wpdo_v2_upgrade_status' );
|
||||
delete_option( 'wpdo_v2_upgrade_error' );
|
||||
delete_option( 'wpdo_v2_upgraded_at' );
|
||||
delete_option( 'wpdo_health_alert' );
|
||||
delete_option( 'wpdo_rl_stats' );
|
||||
delete_option( 'wpdo_setup_wizard_completed' );
|
||||
delete_option( 'wpdo_first_run_at' );
|
||||
|
||||
wp_clear_scheduled_hook( 'wpdo_warm_cleanup' );
|
||||
wp_clear_scheduled_hook( 'wpdo_archive_sweep' );
|
||||
wp_clear_scheduled_hook( 'wpdo_errors_gc' );
|
||||
wp_clear_scheduled_hook( 'wpdo_health_snapshot_monthly' );
|
||||
wp_clear_scheduled_hook( 'wpdo_daily_health_check' );
|
||||
wp_clear_scheduled_hook( 'wpdo_snapshot_prune_daily' );
|
||||
};
|
||||
|
||||
// ── Run cleanup ──────────────────────────────────────────────────────────
|
||||
// v2.14.0: when network-uninstalling on multisite, iterate every site so each
|
||||
// wp_N_wpdo_* table set is dropped. Pre-v2.14.0 only the main site got cleaned.
|
||||
if ( is_multisite() ) {
|
||||
$is_network_active = function_exists( 'is_plugin_active_for_network' )
|
||||
&& is_plugin_active_for_network( plugin_basename( __FILE__ ) );
|
||||
|
||||
if ( $is_network_active ) {
|
||||
// Iterate all sites in batches.
|
||||
$offset = 0;
|
||||
$batch = 100;
|
||||
do {
|
||||
$site_ids = get_sites(
|
||||
array(
|
||||
'number' => $batch,
|
||||
'offset' => $offset,
|
||||
'fields' => 'ids',
|
||||
)
|
||||
);
|
||||
foreach ( $site_ids as $wpdo_blog_id ) {
|
||||
switch_to_blog( (int) $wpdo_blog_id );
|
||||
try {
|
||||
$run_cleanup();
|
||||
} finally {
|
||||
restore_current_blog();
|
||||
}
|
||||
}
|
||||
$offset += $batch;
|
||||
$batch_size = count( $site_ids );
|
||||
} while ( $batch_size === $batch );
|
||||
} else {
|
||||
// Per-site activation: clean only the current site.
|
||||
$run_cleanup();
|
||||
}
|
||||
} else {
|
||||
// Single-site install: run once.
|
||||
$run_cleanup();
|
||||
}
|
||||
Reference in New Issue
Block a user