robotstxt-mlp2-mlp5/includes/class-robotstxt-mlp2-mlp5-step-cleanup.php
2026-03-02 14:31:34 +00:00

204 lines
7.7 KiB
PHP

<?php
/**
* Wizard Step 6 — Optional Cleanup.
*
* Offers three independent cleanup actions:
* 1. Deactivate MultilingualPress 2 (if still active).
* 2. Drop all MLP2 backup tables ({prefix}mlp2bak_*).
* 3. Remove MLP2-related entries from wp_sitemeta.
*
* All actions require typing "DELETE" in a confirmation field and
* verifying a nonce. Actions are logged in the migration log.
*
* @package Robotstxt_Mlp2_Mlp5
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Class Robotstxt_Mlp2_Mlp5_Step_Cleanup
*/
class Robotstxt_Mlp2_Mlp5_Step_Cleanup {
/**
* Deactivate MultilingualPress 2 if it is currently network-active.
*
* @return string 'success', 'skipped', or 'error'.
*/
public static function deactivate_mlp2(): string {
$mlp2 = new Robotstxt_Mlp2_Mlp5_Detector_Mlp2();
if ( ! $mlp2->is_active() ) {
Robotstxt_Mlp2_Mlp5_Logger::log( 'skipped', 'cleanup', null, null, __( 'MLP2 deactivation: plugin is already inactive.', 'robotstxt-mlp2-mlp5' ) );
return 'skipped';
}
if ( ! function_exists( 'deactivate_plugins' ) ) {
require_once ABSPATH . 'wp-admin/includes/plugin.php';
}
deactivate_plugins( $mlp2->get_plugin_file(), true );
Robotstxt_Mlp2_Mlp5_Logger::log( 'success', 'cleanup', null, null, __( 'MLP2 plugin deactivated network-wide.', 'robotstxt-mlp2-mlp5' ) );
return 'success';
}
/**
* Drop all MLP2 backup tables ({prefix}mlp2bak_*).
*
* Each table drop is logged individually.
*
* @return array { @type int $dropped, @type int $errors }
*/
public static function drop_backup_tables(): array {
global $wpdb;
$tables = Robotstxt_Mlp2_Mlp5_Table_Preparer::get_backup_tables();
$dropped = 0;
$errors = 0;
foreach ( $tables as $table ) {
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
$result = $wpdb->query( "DROP TABLE IF EXISTS `{$table}`" );
if ( false === $result ) {
Robotstxt_Mlp2_Mlp5_Logger::log( 'error', 'cleanup', null, null, sprintf( /* translators: %s: table name */ __( 'Failed to drop backup table: %s', 'robotstxt-mlp2-mlp5' ), $table ) );
++$errors;
} else {
Robotstxt_Mlp2_Mlp5_Logger::log( 'success', 'cleanup', null, null, sprintf( /* translators: %s: table name */ __( 'Backup table dropped: %s', 'robotstxt-mlp2-mlp5' ), $table ) );
++$dropped;
}
}
return array(
'dropped' => $dropped,
'errors' => $errors,
);
}
/**
* Delete MLP2-related entries from wp_sitemeta.
*
* Removes sitemeta keys matching 'mlp_*' (MLP2 prefix) and
* 'mlp2bak_inpsyde_multilingual*' (backed-up MLP2 sitemeta).
*
* @return int Number of keys deleted.
*/
public static function remove_mlp2_sitemeta(): int {
global $wpdb;
$patterns = array(
$wpdb->esc_like( 'mlp_' ) . '%',
$wpdb->esc_like( Robotstxt_Mlp2_Mlp5_Table_Preparer::SITEMETA_BACKUP_PREFIX ) . '%',
);
$keys = array();
foreach ( $patterns as $like ) {
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
$found = $wpdb->get_col(
$wpdb->prepare(
"SELECT meta_key FROM {$wpdb->sitemeta} WHERE meta_key LIKE %s AND site_id = %d",
$like,
get_current_network_id()
)
);
if ( is_array( $found ) ) {
$keys = array_merge( $keys, $found );
}
}
$deleted = 0;
foreach ( array_unique( $keys ) as $key ) {
if ( delete_site_option( $key ) ) {
++$deleted;
}
}
Robotstxt_Mlp2_Mlp5_Logger::log( 'success', 'cleanup', null, null, sprintf( /* translators: %d: key count */ __( 'Removed %d MLP2 sitemeta entries.', 'robotstxt-mlp2-mlp5' ), $deleted ) );
return $deleted;
}
/**
* Render the Step 6 UI.
*/
public static function render(): void {
$backup_tables = Robotstxt_Mlp2_Mlp5_Table_Preparer::get_backup_tables();
$mlp2 = new Robotstxt_Mlp2_Mlp5_Detector_Mlp2();
?>
<h2><?php esc_html_e( 'Step 6 — Cleanup (Optional)', 'robotstxt-mlp2-mlp5' ); ?></h2>
<div class="notice notice-success inline" style="margin:0 0 1.5em;">
<p><strong><?php esc_html_e( 'Migration complete!', 'robotstxt-mlp2-mlp5' ); ?></strong> <?php esc_html_e( 'MultilingualPress 5 is now configured with your migrated data. Verify that everything works before performing the optional cleanup below.', 'robotstxt-mlp2-mlp5' ); ?></p>
</div>
<p><?php esc_html_e( 'The cleanup actions below are optional and irreversible. MultilingualPress 5 will work correctly whether or not you perform them.', 'robotstxt-mlp2-mlp5' ); ?></p>
<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>">
<?php wp_nonce_field( 'mlp_migrator_cleanup', 'mlp_migrator_nonce' ); ?>
<input type="hidden" name="action" value="mlp_migrator_step" />
<input type="hidden" name="mlp_migrator_step_action" value="6_cleanup" />
<table class="widefat" style="border:0;max-width:600px;margin-bottom:1.5em;">
<tbody>
<tr>
<td style="width:36px;"><input type="checkbox" id="cleanup_deactivate" name="cleanup_deactivate" value="1" /></td>
<td><label for="cleanup_deactivate">
<?php if ( $mlp2->is_active() ) : ?>
<strong><?php esc_html_e( 'Deactivate MultilingualPress 2 (network-wide)', 'robotstxt-mlp2-mlp5' ); ?></strong>
<?php else : ?>
<strong><?php esc_html_e( 'Deactivate MultilingualPress 2', 'robotstxt-mlp2-mlp5' ); ?></strong>
<em style="color:#888;"> — <?php esc_html_e( 'already inactive', 'robotstxt-mlp2-mlp5' ); ?></em>
<?php endif; ?>
</label></td>
</tr>
<tr>
<td><input type="checkbox" id="cleanup_drop_tables" name="cleanup_drop_tables" value="1" disabled /></td>
<td><label for="cleanup_drop_tables">
<strong><?php esc_html_e( 'Delete MLP2 backup database tables', 'robotstxt-mlp2-mlp5' ); ?></strong>
<span style="color:#888;"> (<?php echo esc_html( sprintf( /* translators: %d: table count */ _n( '%d table', '%d tables', count( $backup_tables ), 'robotstxt-mlp2-mlp5' ), count( $backup_tables ) ) ); ?>: <code><?php echo esc_html( implode( ', ', $backup_tables ) ); ?></code>)</span>
<br><em style="color:#d63638;"><?php esc_html_e( 'Irreversible. Only do this after verifying the migration in MLP5.', 'robotstxt-mlp2-mlp5' ); ?></em>
</label></td>
</tr>
<tr>
<td><input type="checkbox" id="cleanup_sitemeta" name="cleanup_sitemeta" value="1" /></td>
<td><label for="cleanup_sitemeta">
<strong><?php esc_html_e( 'Delete MLP2 network settings from wp_sitemeta', 'robotstxt-mlp2-mlp5' ); ?></strong>
</label></td>
</tr>
</tbody>
</table>
<p>
<label for="cleanup_confirm"><strong><?php esc_html_e( 'Type DELETE to confirm:', 'robotstxt-mlp2-mlp5' ); ?></strong></label><br>
<input type="text" id="cleanup_confirm" name="cleanup_confirm" value="" placeholder="DELETE" autocomplete="off" style="font-family:monospace;width:160px;margin-top:.25em;" />
</p>
<p>
<button type="submit" id="cleanup_submit" class="button button-primary" disabled>
<?php esc_html_e( 'Proceed with cleanup', 'robotstxt-mlp2-mlp5' ); ?>
</button>
</p>
</form>
<script>
(function() {
var chkDeactivate = document.getElementById('cleanup_deactivate');
var chkTables = document.getElementById('cleanup_drop_tables');
var inputConfirm = document.getElementById('cleanup_confirm');
var btnSubmit = document.getElementById('cleanup_submit');
function update() {
chkTables.disabled = ! chkDeactivate.checked;
if ( ! chkDeactivate.checked ) { chkTables.checked = false; }
btnSubmit.disabled = inputConfirm.value !== 'DELETE';
}
chkDeactivate.addEventListener('change', update);
inputConfirm.addEventListener('input', update);
update();
})();
</script>
<?php
}
}