plugin = $plugin; } /** * Registers hooks. */ public function register() { add_action( 'admin_menu', array( $this, 'menu' ), 16 ); add_action( 'admin_post_' . self::ACTION, array( $this, 'handle' ) ); } /** * Adds the submenu page. */ public function menu() { add_submenu_page( Admin::SLUG, __( 'Repair', 'orbitstem-seo' ), __( 'Repair', 'orbitstem-seo' ), Admin::capability(), self::SLUG, array( $this, 'render' ) ); } /** * Handles apply and rollback. */ public function handle() { if ( ! current_user_can( Admin::capability() ) ) { wp_die( esc_html__( 'You do not have permission to do this.', 'orbitstem-seo' ), 403 ); } check_admin_referer( self::ACTION ); $task = isset( $_POST['task'] ) ? sanitize_key( wp_unslash( $_POST['task'] ) ) : ''; $args = array( 'page' => self::SLUG ); if ( 'apply' === $task ) { $fixer = isset( $_POST['fixer'] ) ? sanitize_key( wp_unslash( $_POST['fixer'] ) ) : ''; $keys = isset( $_POST['keys'] ) && is_array( $_POST['keys'] ) ? array_map( 'sanitize_text_field', wp_unslash( $_POST['keys'] ) ) : array(); $results = $this->plugin->repair->apply( $fixer, $keys, ! empty( $_POST['confirm'] ) ); if ( is_wp_error( $results ) ) { RedirectsPage::notice( 'error', $results->get_error_message() ); $args['fixer'] = $fixer; } elseif ( ! $results ) { RedirectsPage::notice( 'error', __( 'Select at least one item.', 'orbitstem-seo' ) ); $args['fixer'] = $fixer; } else { set_transient( 'orbitstem_seo_repair_results_' . get_current_user_id(), $results, 10 * MINUTE_IN_SECONDS ); $args['results'] = 1; } } elseif ( 'rollback' === $task ) { $result = $this->plugin->repair->rollback( isset( $_POST['change'] ) ? absint( $_POST['change'] ) : 0 ); RedirectsPage::notice( is_wp_error( $result ) ? 'error' : 'success', is_wp_error( $result ) ? $result->get_error_message() : __( 'Change rolled back.', 'orbitstem-seo' ) ); $args['tab'] = 'history'; } wp_safe_redirect( add_query_arg( $args, admin_url( 'admin.php' ) ) ); exit; } /** * Renders the page. */ public function render() { if ( ! current_user_can( Admin::capability() ) ) { wp_die( esc_html__( 'You do not have permission to view this page.', 'orbitstem-seo' ) ); } // phpcs:disable WordPress.Security.NonceVerification.Recommended -- view state only. $tab = isset( $_GET['tab'] ) && 'history' === $_GET['tab'] ? 'history' : 'repairs'; $preview = isset( $_GET['fixer'] ) ? sanitize_key( wp_unslash( $_GET['fixer'] ) ) : ''; $results = ! empty( $_GET['results'] ); // phpcs:enable Ui::open( self::SLUG, __( 'Repair Center', 'orbitstem-seo' ), __( 'Preview each repair, apply it, and roll it back from History if needed.', 'orbitstem-seo' ) ); ?> render_results(); } if ( 'history' === $tab ) { $this->render_history(); } elseif ( '' !== $preview && isset( $this->plugin->repair->repair_fixers()[ $preview ] ) ) { $this->render_preview( $preview ); } else { $this->render_repairs(); } Ui::close(); } /** * Overview of available repairs. */ private function render_repairs() { ?>
plugin->repair->repair_fixers() as $id => $fixer ) : ?> candidates( self::PREVIEW + 1 ) ); ?>

label() ); ?>

description() ); ?>

self::PREVIEW ? self::PREVIEW . '+' : (string) $count ) ) : Ui::badge( 'success', __( 'Items to repair: 0', 'orbitstem-seo' ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- escaped in Ui::badge(). ?>
render_autopilot(); ?>

plugin->autopilot; $enabled = $autopilot->enabled_fixers(); $fixers = $this->plugin->repair->fixers(); $last = $autopilot->last(); $state = $autopilot->status(); $settings = admin_url( 'admin.php?page=' . Admin::SETTINGS_SLUG . '#orbitstem-seo-automation' ); ?>

label(); } /* translators: %s: list of repairs */ echo esc_html( sprintf( __( 'On after each scan: %s.', 'orbitstem-seo' ), implode( ', ', $names ) ) ); $user = get_userdata( $autopilot->run_user() ); if ( $user ) { echo ' '; /* translators: %s: user display name */ echo esc_html( sprintf( __( 'Changes are made as %s.', 'orbitstem-seo' ), $user->display_name ) ); } ?>

plugin->repair->repair_fixers()[ $fixer_id ]; $items = $fixer->candidates( self::PREVIEW ); ?>

label() ); ?>

description() ); ?>

←

%s', esc_url( (string) $edit ), esc_html( $item['summary'] ) ); ?>
= self::PREVIEW ) : ?>

is_destructive() ) : ?>

plugin->changes; // phpcs:disable WordPress.Security.NonceVerification.Recommended -- view state only. $paged = isset( $_GET['paged'] ) ? max( 1, absint( $_GET['paged'] ) ) : 1; $kind = isset( $_GET['kind'] ) ? sanitize_key( wp_unslash( $_GET['kind'] ) ) : 'all'; // phpcs:enable $kinds = array( 'all' => array( __( 'Everything', 'orbitstem-seo' ), array() ), 'content' => array( __( 'Content and links', 'orbitstem-seo' ), array( 'redirected_links', 'broken_links', 'outdated_links', 'orphan_links', 'csv_import', 'guardian' ) ), 'redirects' => array( __( 'Redirects', 'orbitstem-seo' ), array( 'redirects', 'redirect_chains' ) ), 'settings' => array( __( 'Settings and imports', 'orbitstem-seo' ), array( 'settings_import', 'guardian' ) ), 'updates' => array( __( 'Site updates', 'orbitstem-seo' ), array( 'site_event' ) ), ); $kind = isset( $kinds[ $kind ] ) ? $kind : 'all'; $filter = $kinds[ $kind ][1]; $rows = $filter ? $log->recent_for( $filter, self::PER_PAGE, ( $paged - 1 ) * self::PER_PAGE ) : $log->recent( self::PER_PAGE, ( $paged - 1 ) * self::PER_PAGE ); $total = $filter ? $log->count_for( $filter ) : $log->count(); $fixers = $this->plugin->repair->fixers(); ?>

plugin->settings->get( 'change_retention_days' ) ) ); ?>

$info ) : ?>

display_name : '—' ); ?> label() : $row['fixer'] ); ?>
' . esc_html( $row['verify_note'] ) . ''; } ?> —
add_query_arg( 'paged', '%#%' ), 'format' => '', 'current' => $paged, 'total' => max( 1, (int) ceil( $total / self::PER_PAGE ) ), ) ) ); } }