cd5da4143e
- The refused-uninstall notice said no tool writes the data back to native tables; wp tmdo bridge-restore-native does. - The post stress tester no longer maps product to the retired wc_product table. - Verify: unit 711, integration 611, phpcs 0 - PR: PR-139 (manual F-7, F-8)
138 lines
4.9 KiB
PHP
138 lines
4.9 KiB
PHP
<?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.
|
||
*
|
||
* Refuses (wp_die, before any snapshot or DROP) while any site still holds data
|
||
* that exists only in wpdo_* tables — see TMDO_Installer::uninstall_blockers().
|
||
* wp_die() also stops WordPress from deleting the plugin files.
|
||
*
|
||
* 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.
|
||
*
|
||
* Multisite: every site is checked and cleaned. The plugin may have been active
|
||
* per site, and it is always inactive by the time it can be deleted, so network
|
||
* activation cannot tell which sites hold wpdo_* tables.
|
||
*
|
||
* @package WP_Data_Optimizer
|
||
*/
|
||
|
||
declare(strict_types=1);
|
||
|
||
if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
|
||
exit;
|
||
}
|
||
|
||
global $wpdb;
|
||
|
||
// ── Load shared cleanup logic + snapshot classes ─────────────────────────
|
||
$wpdo_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',
|
||
);
|
||
$wpdo_bootstrap_ok = true;
|
||
foreach ( $wpdo_bootstrap_files as $wpdo_bootstrap_file ) {
|
||
if ( ! is_file( $wpdo_bootstrap_file ) ) {
|
||
$wpdo_bootstrap_ok = false;
|
||
continue;
|
||
}
|
||
require_once $wpdo_bootstrap_file;
|
||
}
|
||
|
||
// ── Sites to check and clean (0 = single site, no blog switching) ────────
|
||
$wpdo_site_ids = is_multisite()
|
||
? array_map(
|
||
'intval',
|
||
get_sites(
|
||
array(
|
||
'fields' => 'ids',
|
||
'number' => 0,
|
||
)
|
||
)
|
||
)
|
||
: array( 0 );
|
||
|
||
$wpdo_for_each_site = static function ( callable $callback ) use ( $wpdo_site_ids ): void {
|
||
foreach ( $wpdo_site_ids as $wpdo_blog_id ) {
|
||
if ( $wpdo_blog_id ) {
|
||
switch_to_blog( $wpdo_blog_id );
|
||
}
|
||
try {
|
||
$callback( $wpdo_blog_id );
|
||
} finally {
|
||
if ( $wpdo_blog_id ) {
|
||
restore_current_blog();
|
||
}
|
||
}
|
||
}
|
||
};
|
||
|
||
// ── Refuse while any site holds data that exists only in wpdo_* tables ───
|
||
if ( ! $wpdo_bootstrap_ok ) {
|
||
wp_die( esc_html( '2meet Data Optimizer:無法載入資料安全檢查,為避免資料遺失,已停止解除安裝。' ) );
|
||
}
|
||
|
||
$wpdo_blocked = array();
|
||
$wpdo_for_each_site(
|
||
static function ( int $blog_id ) use ( &$wpdo_blocked ): void {
|
||
foreach ( TMDO_Installer::uninstall_blockers() as $reason ) {
|
||
$wpdo_blocked[] = ( $blog_id ? "站台 #{$blog_id}:" : '' ) . $reason;
|
||
}
|
||
}
|
||
);
|
||
|
||
if ( $wpdo_blocked ) {
|
||
wp_die(
|
||
'<p>' . esc_html( '2meet Data Optimizer 已停止解除安裝:以下資料只存在 wpdo_* 表,刪除外掛會一併刪除這些表。' ) . '</p>'
|
||
. '<ul><li>' . implode( '</li><li>', array_map( 'esc_html', $wpdo_blocked ) ) . '</li></ul>'
|
||
. '<p>' . esc_html( '請先以 wp tmdo bridge-restore-native 把資料寫回 WordPress 原生表,再解除安裝。若只想移除外掛程式,可手動刪除外掛目錄,資料表會保留。' ) . '</p>'
|
||
);
|
||
}
|
||
|
||
// ── 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 ( class_exists( 'TMDO_Snapshot_Manager' ) ) {
|
||
$wpdo_snapshot = 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( $wpdo_snapshot['ok'] ) ) {
|
||
$wpdo_snapshot_id = $wpdo_snapshot['snapshot_id'];
|
||
$wpdo_backup_dir = TMDO_Snapshot_Manager::backup_dir();
|
||
if ( is_dir( $wpdo_backup_dir ) ) {
|
||
file_put_contents(
|
||
trailingslashit( $wpdo_backup_dir ) . 'README-pre-uninstall.txt',
|
||
"WPDO pre-uninstall snapshot: {$wpdo_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 {$wpdo_snapshot_id} --apply\n"
|
||
);
|
||
}
|
||
}
|
||
}
|
||
|
||
// ── Drop wpdo_* tables and options on every site ─────────────────────────
|
||
$wpdo_for_each_site(
|
||
static function (): void {
|
||
TMDO_Installer::drop_all_tables_for_current_blog();
|
||
}
|
||
);
|