robotstxt-mlp2-mlp5/includes/class-robotstxt-mlp2-mlp5-admin-page.php
2026-03-02 11:22:59 +00:00

583 lines
24 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/**
* Network Admin page.
*
* Registers the plugin settings page under Network Admin > Settings and
* orchestrates the full migration wizard. Handles all POST actions for:
* - Table rename / restore (preparation)
* - Wizard step navigation (steps 1–6)
* - Wizard reset
* - CSV log export
*
* Network Admin only. Uses exclusively:
* network_admin_menu, network_admin_init.
*
* @package Robotstxt_Mlp2_Mlp5
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Class Robotstxt_Mlp2_Mlp5_Admin_Page
*/
class Robotstxt_Mlp2_Mlp5_Admin_Page {
/**
* Menu slug for the plugin settings page.
*
* @var string
*/
const MENU_SLUG = 'robotstxt-mlp2-mlp5';
/**
* Required capability to access the plugin page.
*
* The manage_network capability is the standard for Network Admin settings.
*
* @var string
*/
const CAPABILITY = 'manage_network';
/**
* Register the Network Admin page and all POST/GET handlers.
*/
public static function init(): void {
add_action( 'network_admin_menu', array( static::class, 'register_menu' ) );
add_action( 'admin_post_mlp_migrator_rename_tables', array( static::class, 'handle_rename_action' ) );
add_action( 'admin_post_mlp_migrator_restore_tables', array( static::class, 'handle_restore_action' ) );
add_action( 'admin_post_mlp_migrator_step', array( static::class, 'handle_step_actions' ) );
add_action( 'admin_post_mlp_migrator_reset_wizard', array( static::class, 'handle_reset_action' ) );
add_action( 'admin_post_mlp_migrator_export_log', array( 'Robotstxt_Mlp2_Mlp5_Step_Verification', 'maybe_export_csv' ) );
}
/**
* Add the settings page under Network Admin > Settings.
*/
public static function register_menu(): void {
add_submenu_page(
'settings.php',
__( 'MLP2 to MLP5 Migrator', 'robotstxt-mlp2-mlp5' ),
__( 'MLP Migrator', 'robotstxt-mlp2-mlp5' ),
self::CAPABILITY,
self::MENU_SLUG,
array( static::class, 'render' )
);
}
/**
* Return the URL to this plugin's Network Admin page.
*
* @param array $extra Optional extra query args.
* @return string Absolute URL.
*/
public static function page_url( array $extra = array() ): string {
$args = array_merge( array( 'page' => self::MENU_SLUG ), $extra );
return network_admin_url( 'settings.php?' . http_build_query( $args ) );
}
// -------------------------------------------------------------------------
// POST handlers (preparation)
// -------------------------------------------------------------------------
/**
* Handle the "Rename MLP2 tables" POST action.
*/
public static function handle_rename_action(): void {
check_admin_referer( 'mlp_migrator_rename', 'mlp_migrator_nonce' );
if ( ! current_user_can( self::CAPABILITY ) ) {
wp_die( esc_html__( 'You do not have permission to perform this action.', 'robotstxt-mlp2-mlp5' ) );
}
$result = Robotstxt_Mlp2_Mlp5_Table_Preparer::rename_to_backup();
$args = array( 'renamed' => count( $result['renamed'] ) );
if ( ! empty( $result['errors'] ) ) {
$args['rename_errors'] = count( $result['errors'] );
}
wp_safe_redirect( self::page_url( $args ) );
exit;
}
/**
* Handle the "Restore original table names" POST action.
*/
public static function handle_restore_action(): void {
check_admin_referer( 'mlp_migrator_restore', 'mlp_migrator_nonce' );
if ( ! current_user_can( self::CAPABILITY ) ) {
wp_die( esc_html__( 'You do not have permission to perform this action.', 'robotstxt-mlp2-mlp5' ) );
}
$result = Robotstxt_Mlp2_Mlp5_Table_Preparer::restore_from_backup();
$args = array( 'restored' => count( $result['restored'] ) );
if ( ! empty( $result['errors'] ) ) {
$args['restore_errors'] = count( $result['errors'] );
}
wp_safe_redirect( self::page_url( $args ) );
exit;
}
// -------------------------------------------------------------------------
// POST handlers (wizard steps)
// -------------------------------------------------------------------------
/**
* Route all wizard step POST actions.
*/
public static function handle_step_actions(): void {
// phpcs:ignore WordPress.Security.NonceVerification.Missing
if ( ! isset( $_POST['mlp_migrator_step_action'] ) ) {
return;
}
if ( ! current_user_can( self::CAPABILITY ) ) {
wp_die( esc_html__( 'You do not have permission to perform this action.', 'robotstxt-mlp2-mlp5' ) );
}
// phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
$action = sanitize_key( wp_unslash( $_POST['mlp_migrator_step_action'] ) );
switch ( $action ) {
case '1':
self::handle_step_1_next();
break;
case '2_run':
self::handle_step_2_run();
break;
case '2':
self::handle_step_next( 2, 3, 'mlp_migrator_step_2' );
break;
case '3_run':
self::handle_step_3_run();
break;
case '3':
self::handle_step_next( 3, 4, 'mlp_migrator_step_3' );
break;
case '4':
self::handle_step_next( 4, 5, 'mlp_migrator_step_4' );
break;
case '5':
self::handle_step_next( 5, 6, 'mlp_migrator_step_5' );
break;
case '6_cleanup':
self::handle_step_6_cleanup();
break;
}
}
/**
* Handle "Next" from Step 1 (Preflight).
*/
private static function handle_step_1_next(): void {
check_admin_referer( 'mlp_migrator_step_1', 'mlp_migrator_nonce' );
$checks = Robotstxt_Mlp2_Mlp5_Step_Preflight::run();
if ( $checks['can_proceed'] ) {
Robotstxt_Mlp2_Mlp5_Wizard_State::mark_step_complete( 1 );
Robotstxt_Mlp2_Mlp5_Wizard_State::set_step( 2 );
}
wp_safe_redirect( self::page_url() );
exit;
}
/**
* Handle "Run Analysis" from Step 2.
*/
private static function handle_step_2_run(): void {
check_admin_referer( 'mlp_migrator_analysis', 'mlp_migrator_nonce' );
$result = Robotstxt_Mlp2_Mlp5_Step_Analysis::run();
Robotstxt_Mlp2_Mlp5_Wizard_State::set_step_data( 2, $result );
wp_safe_redirect( self::page_url() );
exit;
}
/**
* Handle "Start" from Step 3 (Site Relations).
*/
private static function handle_step_3_run(): void {
check_admin_referer( 'mlp_migrator_site_relations', 'mlp_migrator_nonce' );
$result = Robotstxt_Mlp2_Mlp5_Step_Site_Relations::run();
Robotstxt_Mlp2_Mlp5_Wizard_State::set_step_data( 3, $result );
wp_safe_redirect( self::page_url() );
exit;
}
/**
* Handle "Next" for a standard step (advance to next, mark complete).
*
* @param int $current_step Current step number.
* @param int $next_step Next step number.
* @param string $nonce_action Nonce action string.
*/
private static function handle_step_next( int $current_step, int $next_step, string $nonce_action ): void {
check_admin_referer( $nonce_action, 'mlp_migrator_nonce' );
Robotstxt_Mlp2_Mlp5_Wizard_State::mark_step_complete( $current_step );
Robotstxt_Mlp2_Mlp5_Wizard_State::set_step( $next_step );
wp_safe_redirect( self::page_url() );
exit;
}
/**
* Handle the cleanup POST from Step 6.
*/
private static function handle_step_6_cleanup(): void {
check_admin_referer( 'mlp_migrator_cleanup', 'mlp_migrator_nonce' );
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
$confirm = isset( $_POST['cleanup_confirm'] ) ? wp_unslash( $_POST['cleanup_confirm'] ) : '';
if ( 'DELETE' !== $confirm ) {
wp_safe_redirect( self::page_url( array( 'cleanup_error' => '1' ) ) );
exit;
}
$deactivate = ! empty( $_POST['cleanup_deactivate'] );
$drop_tables = ! empty( $_POST['cleanup_drop_tables'] ) && $deactivate;
$sitemeta = ! empty( $_POST['cleanup_sitemeta'] );
if ( $deactivate ) {
Robotstxt_Mlp2_Mlp5_Step_Cleanup::deactivate_mlp2();
}
if ( $drop_tables ) {
Robotstxt_Mlp2_Mlp5_Step_Cleanup::drop_backup_tables();
}
if ( $sitemeta ) {
Robotstxt_Mlp2_Mlp5_Step_Cleanup::remove_mlp2_sitemeta();
}
Robotstxt_Mlp2_Mlp5_Wizard_State::mark_step_complete( 6 );
wp_safe_redirect( self::page_url( array( 'cleanup_done' => '1' ) ) );
exit;
}
/**
* Handle the wizard reset POST action.
*/
public static function handle_reset_action(): void {
check_admin_referer( 'mlp_migrator_reset', 'mlp_migrator_nonce' );
if ( ! current_user_can( self::CAPABILITY ) ) {
wp_die( esc_html__( 'You do not have permission to perform this action.', 'robotstxt-mlp2-mlp5' ) );
}
Robotstxt_Mlp2_Mlp5_Wizard_State::reset();
Robotstxt_Mlp2_Mlp5_Logger::clear();
wp_safe_redirect( self::page_url( array( 'reset' => '1' ) ) );
exit;
}
// -------------------------------------------------------------------------
// Rendering
// -------------------------------------------------------------------------
/**
* Render the full page.
*/
public static function render(): void {
if ( ! current_user_can( self::CAPABILITY ) ) {
wp_die( esc_html__( 'You do not have permission to access this page.', 'robotstxt-mlp2-mlp5' ) );
}
$has_original = Robotstxt_Mlp2_Mlp5_Table_Preparer::has_original_tables();
$has_backup = Robotstxt_Mlp2_Mlp5_Table_Preparer::has_backup_tables();
$mlp5 = new Robotstxt_Mlp2_Mlp5_Detector_Mlp5();
$mlp5_active = $mlp5->is_active();
// Once MLP5 is active its own tables match the mlp_* pattern.
// They are not leftover MLP2 tables, so suppress the "must be renamed" signal.
if ( $mlp5_active ) {
$has_original = false;
}
// Migration is complete when wizard step 6 is marked done.
$wizard_done = Robotstxt_Mlp2_Mlp5_Wizard_State::is_step_complete( Robotstxt_Mlp2_Mlp5_Wizard_State::TOTAL_STEPS );
$ready = ( $has_backup && $mlp5_active ) || ( $wizard_done && $mlp5_active );
?>
<div class="wrap">
<h1><?php esc_html_e( 'MLP2 to MLP5 Migrator', 'robotstxt-mlp2-mlp5' ); ?></h1>
<?php self::render_feedback_notices(); ?>
<?php if ( $ready ) : ?>
<?php self::render_wizard( $has_original, $has_backup, $mlp5_active, $mlp5 ); ?>
<?php else : ?>
<?php self::render_state_banner( $has_original, $has_backup, $mlp5_active ); ?>
<?php self::render_status_card( $has_original, $has_backup, $mlp5_active, $mlp5 ); ?>
<?php self::render_action_forms( $has_original, $has_backup, $mlp5_active ); ?>
<?php endif; ?>
</div>
<?php
}
/**
* Render the full wizard when the system is ready (State C).
*
* @param bool $has_original Whether original MLP2 tables exist.
* @param bool $has_backup Whether backup MLP2 tables exist.
* @param bool $mlp5_active Whether MLP5 is network-active.
* @param Robotstxt_Mlp2_Mlp5_Detector_Mlp5 $mlp5 MLP5 detector instance.
*/
private static function render_wizard(
bool $has_original,
bool $has_backup,
bool $mlp5_active,
Robotstxt_Mlp2_Mlp5_Detector_Mlp5 $mlp5
): void {
$current_step = Robotstxt_Mlp2_Mlp5_Wizard_State::get_current_step();
$step_labels = array(
1 => __( 'Preflight', 'robotstxt-mlp2-mlp5' ),
2 => __( 'Analysis', 'robotstxt-mlp2-mlp5' ),
3 => __( 'Site Relations', 'robotstxt-mlp2-mlp5' ),
4 => __( 'Content Relations', 'robotstxt-mlp2-mlp5' ),
5 => __( 'Verification', 'robotstxt-mlp2-mlp5' ),
6 => __( 'Cleanup', 'robotstxt-mlp2-mlp5' ),
);
?>
<div style="background:#fff;border:1px solid #c3c4c7;padding:1.5em;max-width:780px;">
<?php /* Step indicator */ ?>
<ol style="display:flex;list-style:none;margin:0 0 1.5em;padding:0;gap:0;">
<?php for ( $i = 1; $i <= Robotstxt_Mlp2_Mlp5_Wizard_State::TOTAL_STEPS; $i++ ) : ?>
<?php
$is_done = Robotstxt_Mlp2_Mlp5_Wizard_State::is_step_complete( $i );
$is_current = ( $i === $current_step );
if ( $is_current ) {
$bg = '#2271b1';
$color = '#fff';
} elseif ( $is_done ) {
$bg = '#00a32a';
$color = '#fff';
} else {
$bg = '#f0f0f1';
$color = '#50575e';
}
?>
<li style="flex:1;text-align:center;padding:.5em .25em;background:<?php echo esc_attr( $bg ); ?>;color:<?php echo esc_attr( $color ); ?>;font-size:.85em;font-weight:<?php echo $is_current ? '700' : '400'; ?>;border-right:2px solid #fff;">
<?php echo esc_html( $i . '. ' . $step_labels[ $i ] ); ?>
<?php echo $is_done ? ' ✓' : ''; ?>
</li>
<?php endfor; ?>
</ol>
<?php /* Step content */ ?>
<div style="min-height:200px;">
<?php
switch ( $current_step ) {
case 1:
Robotstxt_Mlp2_Mlp5_Step_Preflight::render();
break;
case 2:
Robotstxt_Mlp2_Mlp5_Step_Analysis::render();
break;
case 3:
Robotstxt_Mlp2_Mlp5_Step_Site_Relations::render();
break;
case 4:
Robotstxt_Mlp2_Mlp5_Step_Content_Relations::render();
break;
case 5:
Robotstxt_Mlp2_Mlp5_Step_Verification::render();
break;
case 6:
Robotstxt_Mlp2_Mlp5_Step_Cleanup::render();
break;
}
?>
</div>
<?php /* Reset disclosure */ ?>
<details style="margin-top:2em;border-top:1px solid #e2e2e2;padding-top:1em;">
<summary style="cursor:pointer;color:#646970;"><?php esc_html_e( 'Reset migration (start over)', 'robotstxt-mlp2-mlp5' ); ?></summary>
<div style="margin-top:.75em;padding:.75em;border:1px solid #dcdcde;background:#fff8f8;">
<p><?php esc_html_e( 'This will reset the wizard to Step 1 and clear the migration log. It does not modify MLP5 data.', 'robotstxt-mlp2-mlp5' ); ?></p>
<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>">
<?php wp_nonce_field( 'mlp_migrator_reset', 'mlp_migrator_nonce' ); ?>
<input type="hidden" name="action" value="mlp_migrator_reset_wizard" />
<button type="submit" class="button button-secondary"><?php esc_html_e( 'Reset wizard', 'robotstxt-mlp2-mlp5' ); ?></button>
</form>
</div>
</details>
</div>
<?php /* Status sidebar (compact, always visible) */ ?>
<div style="margin-top:1em;max-width:780px;">
<details>
<summary style="cursor:pointer;color:#646970;"><?php esc_html_e( 'System status', 'robotstxt-mlp2-mlp5' ); ?></summary>
<div style="margin-top:.5em;">
<?php self::render_status_card( $has_original, $has_backup, $mlp5_active, $mlp5 ); ?>
</div>
</details>
</div>
<?php
}
// -------------------------------------------------------------------------
// Shared UI helpers (used in both preparation and wizard views)
// -------------------------------------------------------------------------
/**
* Show feedback notices after redirects.
*/
private static function render_feedback_notices(): void {
// phpcs:disable WordPress.Security.NonceVerification.Recommended
if ( isset( $_GET['renamed'] ) ) {
$count = (int) $_GET['renamed'];
/* translators: %d: number of renamed tables */
printf( '<div class="notice notice-success is-dismissible"><p>%s</p></div>', esc_html( sprintf( _n( '%d table renamed successfully.', '%d tables renamed successfully.', $count, 'robotstxt-mlp2-mlp5' ), $count ) ) ); // phpcs:ignore WordPress.WP.I18n.MismatchedPlaceholders
}
if ( isset( $_GET['rename_errors'] ) ) {
$count = (int) $_GET['rename_errors'];
/* translators: %d: number of tables that could not be renamed */
printf( '<div class="notice notice-error"><p>%s</p></div>', esc_html( sprintf( _n( '%d table could not be renamed. Check database permissions.', '%d tables could not be renamed. Check database permissions.', $count, 'robotstxt-mlp2-mlp5' ), $count ) ) ); // phpcs:ignore WordPress.WP.I18n.MismatchedPlaceholders
}
if ( isset( $_GET['restored'] ) ) {
$count = (int) $_GET['restored'];
/* translators: %d: number of restored tables */
printf( '<div class="notice notice-success is-dismissible"><p>%s</p></div>', esc_html( sprintf( _n( '%d table restored to original name.', '%d tables restored to original names.', $count, 'robotstxt-mlp2-mlp5' ), $count ) ) ); // phpcs:ignore WordPress.WP.I18n.MismatchedPlaceholders
}
if ( isset( $_GET['restore_errors'] ) ) {
$count = (int) $_GET['restore_errors'];
/* translators: %d: number of tables that could not be restored */
printf( '<div class="notice notice-error"><p>%s</p></div>', esc_html( sprintf( _n( '%d table could not be restored. Check database permissions.', '%d tables could not be restored. Check database permissions.', $count, 'robotstxt-mlp2-mlp5' ), $count ) ) ); // phpcs:ignore WordPress.WP.I18n.MismatchedPlaceholders
}
if ( isset( $_GET['reset'] ) ) {
printf( '<div class="notice notice-success is-dismissible"><p>%s</p></div>', esc_html__( 'Wizard reset. You can start the migration from Step 1.', 'robotstxt-mlp2-mlp5' ) );
}
if ( isset( $_GET['cleanup_done'] ) ) {
printf( '<div class="notice notice-success is-dismissible"><p>%s</p></div>', esc_html__( 'Cleanup completed.', 'robotstxt-mlp2-mlp5' ) );
}
if ( isset( $_GET['cleanup_error'] ) ) {
printf( '<div class="notice notice-error"><p>%s</p></div>', esc_html__( 'Cleanup confirmation invalid. Type DELETE exactly.', 'robotstxt-mlp2-mlp5' ) );
}
// phpcs:enable WordPress.Security.NonceVerification.Recommended
}
/**
* Show a banner communicating the overall system state (preparation view only).
*
* @param bool $has_original Whether original MLP2 tables exist.
* @param bool $has_backup Whether backup MLP2 tables exist.
* @param bool $mlp5_active Whether MLP5 is network-active.
*/
private static function render_state_banner( bool $has_original, bool $has_backup, bool $mlp5_active ): void {
if ( $has_original && ! $has_backup ) {
$color = '#d63638';
$msg = __( 'Action required: MLP2 tables must be renamed before MultilingualPress 5 can be activated.', 'robotstxt-mlp2-mlp5' );
} elseif ( $has_backup && ! $mlp5_active ) {
$color = '#dba617';
$msg = __( 'MLP2 tables renamed. Now go to Network Admin &gt; Plugins and activate MultilingualPress 5.', 'robotstxt-mlp2-mlp5' );
} elseif ( $has_original && $has_backup ) {
$color = '#dba617';
$msg = __( 'Warning: both original and backup MLP2 tables were found. Investigate before proceeding.', 'robotstxt-mlp2-mlp5' );
} else {
$color = '#d63638';
$msg = __( 'No MLP2 tables found. Migration cannot proceed. Restore your database from a backup.', 'robotstxt-mlp2-mlp5' );
}
printf(
'<div style="border-left:4px solid %s;padding:.75em 1em;margin:1em 0;background:#fff;max-width:640px;"><strong>%s</strong></div>',
esc_attr( $color ),
wp_kses_post( $msg )
);
}
/**
* Show the system status card.
*
* @param bool $has_original Whether original MLP2 tables exist.
* @param bool $has_backup Whether backup MLP2 tables exist.
* @param bool $mlp5_active Whether MLP5 is network-active.
* @param Robotstxt_Mlp2_Mlp5_Detector_Mlp5 $mlp5 MLP5 detector instance.
*/
private static function render_status_card(
bool $has_original,
bool $has_backup,
bool $mlp5_active,
Robotstxt_Mlp2_Mlp5_Detector_Mlp5 $mlp5
): void {
$orig_count = count( Robotstxt_Mlp2_Mlp5_Table_Preparer::get_original_tables() );
$backup_count = count( Robotstxt_Mlp2_Mlp5_Table_Preparer::get_backup_tables() );
?>
<div class="card" style="max-width:640px;margin-top:1em;">
<h2 style="margin-top:0;"><?php esc_html_e( 'System Status', 'robotstxt-mlp2-mlp5' ); ?></h2>
<table class="widefat striped" style="border:0;">
<tbody>
<tr>
<td><?php esc_html_e( 'MLP2 tables (original names)', 'robotstxt-mlp2-mlp5' ); ?></td>
<td>
<?php if ( $has_original ) : ?>
<span style="color:#d63638;">&#9679; <?php echo esc_html( sprintf( /* translators: %d: number of tables */ _n( '%d table — must be renamed', '%d tables — must be renamed', $orig_count, 'robotstxt-mlp2-mlp5' ), $orig_count ) ); // phpcs:ignore WordPress.WP.I18n.MismatchedPlaceholders ?></span>
<?php else : ?>
<span style="color:#46b450;">&#10003; <?php esc_html_e( 'None', 'robotstxt-mlp2-mlp5' ); ?></span>
<?php endif; ?>
</td>
</tr>
<tr>
<td><?php esc_html_e( 'MLP2 tables (backup copies)', 'robotstxt-mlp2-mlp5' ); ?></td>
<td>
<?php if ( $has_backup ) : ?>
<span style="color:#46b450;">&#10003; <?php echo esc_html( sprintf( /* translators: %d: number of backup tables */ _n( '%d backup table ready', '%d backup tables ready', $backup_count, 'robotstxt-mlp2-mlp5' ), $backup_count ) ); // phpcs:ignore WordPress.WP.I18n.MismatchedPlaceholders ?></span>
<?php else : ?>
<span style="color:#888;">&#8212; <?php esc_html_e( 'Not yet renamed', 'robotstxt-mlp2-mlp5' ); ?></span>
<?php endif; ?>
</td>
</tr>
<tr>
<td><?php esc_html_e( 'MultilingualPress 5 (network-active)', 'robotstxt-mlp2-mlp5' ); ?></td>
<td>
<?php if ( $mlp5_active ) : ?>
<span style="color:#46b450;">&#10003; <?php echo esc_html( sprintf( /* translators: %s: version */ __( 'Active (v%s)', 'robotstxt-mlp2-mlp5' ), $mlp5->get_version() ) ); ?></span>
<?php else : ?>
<span style="color:#888;">&#8212; <?php esc_html_e( 'Not active', 'robotstxt-mlp2-mlp5' ); ?></span>
<?php endif; ?>
</td>
</tr>
</tbody>
</table>
</div>
<?php
}
/**
* Render action forms for the preparation view.
*
* @param bool $has_original Whether original MLP2 tables exist.
* @param bool $has_backup Whether backup MLP2 tables exist.
* @param bool $mlp5_active Whether MLP5 is network-active.
*/
private static function render_action_forms( bool $has_original, bool $has_backup, bool $mlp5_active ): void {
if ( $has_original ) {
?>
<div style="max-width:640px;margin-top:1.5em;">
<h2><?php esc_html_e( 'Step 1 — Rename MLP2 Tables', 'robotstxt-mlp2-mlp5' ); ?></h2>
<p><?php esc_html_e( 'MultilingualPress 5 cannot activate while the original MLP2 table names are present. Click below to rename them to temporary backup copies ({prefix}mlp2bak_*). This is safe and fully reversible.', 'robotstxt-mlp2-mlp5' ); ?></p>
<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>">
<?php wp_nonce_field( 'mlp_migrator_rename', 'mlp_migrator_nonce' ); ?>
<input type="hidden" name="action" value="mlp_migrator_rename_tables" />
<p><button type="submit" class="button button-primary"><?php esc_html_e( 'Rename MLP2 tables (prepare for MLP5 activation)', 'robotstxt-mlp2-mlp5' ); ?></button></p>
</form>
</div>
<?php
}
if ( $has_backup && ! $mlp5_active ) {
?>
<div style="max-width:640px;margin-top:1.5em;">
<h2><?php esc_html_e( 'Step 2 — Activate MultilingualPress 5', 'robotstxt-mlp2-mlp5' ); ?></h2>
<p><?php esc_html_e( 'MLP2 tables have been renamed. MultilingualPress 5 can now be activated without the old-version compatibility error.', 'robotstxt-mlp2-mlp5' ); ?></p>
<p><a href="<?php echo esc_url( network_admin_url( 'plugins.php' ) ); ?>" class="button button-primary"><?php esc_html_e( 'Go to Network Admin › Plugins', 'robotstxt-mlp2-mlp5' ); ?></a></p>
</div>
<?php
}
if ( $has_backup ) {
?>
<div style="max-width:640px;margin-top:2em;">
<details>
<summary style="cursor:pointer;color:#646970;"><?php esc_html_e( 'Emergency: restore original MLP2 table names', 'robotstxt-mlp2-mlp5' ); ?></summary>
<div style="margin-top:.75em;padding:.75em;border:1px solid #dcdcde;background:#fff8f8;">
<p><?php esc_html_e( 'This renames backup tables back to their original MLP2 names. Only use this before MLP5 has been activated.', 'robotstxt-mlp2-mlp5' ); ?></p>
<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>">
<?php wp_nonce_field( 'mlp_migrator_restore', 'mlp_migrator_nonce' ); ?>
<input type="hidden" name="action" value="mlp_migrator_restore_tables" />
<button type="submit" class="button button-secondary"><?php esc_html_e( 'Restore original table names', 'robotstxt-mlp2-mlp5' ); ?></button>
</form>
</div>
</details>
</div>
<?php
}
}
}