job_store = $job_store; } /** * Add the single-site Tools page. */ public function register_site_menu() { if ( is_multisite() ) { return; } $hook = add_management_page( __( '1Gbits Site Move Inspector', '1gbits-site-move-inspector' ), __( 'Site Move Inspector', '1gbits-site-move-inspector' ), 'manage_options', self::PAGE_SLUG, array( $this, 'render_page' ) ); if ( is_string( $hook ) ) { $this->page_hooks[] = $hook; } } /** * Add the multisite Network Settings page. */ public function register_network_menu() { if ( ! is_multisite() ) { return; } $hook = add_submenu_page( 'settings.php', __( '1Gbits Site Move Inspector', '1gbits-site-move-inspector' ), __( 'Site Move Inspector', '1gbits-site-move-inspector' ), 'manage_network_options', self::PAGE_SLUG, array( $this, 'render_page' ) ); if ( is_string( $hook ) ) { $this->page_hooks[] = $hook; } } /** * Load local assets only on this plugin's page. * * @param string $hook_suffix Current admin hook. */ public function enqueue_assets( $hook_suffix ) { if ( ! in_array( $hook_suffix, $this->page_hooks, true ) ) { return; } wp_enqueue_style( 'ogsmi-admin', OGSMI_PLUGIN_URL . 'assets/admin.css', array(), OGSMI_VERSION ); wp_enqueue_script( 'ogsmi-admin', OGSMI_PLUGIN_URL . 'assets/admin.js', array(), OGSMI_VERSION, true ); wp_localize_script( 'ogsmi-admin', 'ogsmiAdmin', array( 'restRoot' => esc_url_raw( rest_url( OGSMI_REST_Controller::REST_NAMESPACE ) ), 'nonce' => wp_create_nonce( 'wp_rest' ), 'activeJob' => $this->job_store->get_active_id( get_current_user_id() ), 'strings' => array( 'starting' => __( 'Preparing the inspection…', '1gbits-site-move-inspector' ), 'scanning' => __( 'Scanning filesystem metadata…', '1gbits-site-move-inspector' ), 'complete' => __( 'Inspection complete. Loading the report…', '1gbits-site-move-inspector' ), 'canceling' => __( 'Canceling the inspection…', '1gbits-site-move-inspector' ), 'canceled' => __( 'Inspection canceled. No site data was changed.', '1gbits-site-move-inspector' ), 'genericError' => __( 'The inspection could not continue. No site data was changed.', '1gbits-site-move-inspector' ), /* translators: %s: number of files scanned. */ 'filesScanned' => __( 'Files scanned: %s', '1gbits-site-move-inspector' ), /* translators: %s: human-readable number of bytes scanned. */ 'bytesScanned' => __( '%s scanned', '1gbits-site-move-inspector' ), ), ) ); } /** * Render the scan form and latest short-lived report. */ public function render_page() { if ( ! $this->current_user_can_scan() ) { wp_die( esc_html__( 'You are not allowed to view this page.', '1gbits-site-move-inspector' ) ); } $user_id = get_current_user_id(); $active_job = $this->job_store->get_active_id( $user_id ); $report = $this->job_store->get_latest_report( $user_id ); ?>

>

>

render_report( $report ); ?>

current_user_can_scan() ) { wp_die( esc_html__( 'You are not allowed to export this report.', '1gbits-site-move-inspector' ), esc_html__( 'Export denied', '1gbits-site-move-inspector' ), array( 'response' => 403 ) ); } check_admin_referer( 'ogsmi_export_report' ); $format = isset( $_POST['format'] ) ? sanitize_key( wp_unslash( $_POST['format'] ) ) : ''; if ( ! in_array( $format, array( 'json', 'txt' ), true ) ) { wp_die( esc_html__( 'The requested export format is not supported.', '1gbits-site-move-inspector' ), esc_html__( 'Invalid export', '1gbits-site-move-inspector' ), array( 'response' => 400 ) ); } $report = $this->job_store->get_latest_report( get_current_user_id() ); if ( ! is_array( $report ) ) { wp_die( esc_html__( 'The temporary report expired. Run a new inspection.', '1gbits-site-move-inspector' ), esc_html__( 'Report expired', '1gbits-site-move-inspector' ), array( 'response' => 404 ) ); } if ( 'json' === $format ) { $content_type = 'application/json; charset=utf-8'; $content = OGSMI_Exporter::to_json( $report ); } else { $content_type = 'text/plain; charset=utf-8'; $content = OGSMI_Exporter::to_text( $report ); } $filename = sprintf( '1gbits-site-move-report-%s.%s', gmdate( 'Ymd-His' ), $format ); nocache_headers(); header( 'Content-Type: ' . $content_type ); header( 'Content-Disposition: attachment; filename="' . $filename . '"' ); header( 'X-Content-Type-Options: nosniff' ); header( 'Content-Length: ' . strlen( $content ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Purpose-built plain text or JSON download. echo $content; exit; } /** * Render the report summary, checks, and admin-only inventory. * * @param array $report Internal report. */ private function render_report( array $report ) { $summary = $report['summary'] ?? OGSMI_Report_Builder::summarize( $report ); $overall = $summary['overall'] ?? 'review_recommended'; $status = $this->overall_label( $overall ); $time = strtotime( $report['generated_at'] ?? '' ); ?>

__( 'Critical', '1gbits-site-move-inspector' ), 'warning' => __( 'Warnings', '1gbits-site-move-inspector' ), 'unknown' => __( 'Unknown', '1gbits-site-move-inspector' ), 'pass' => __( 'Passed', '1gbits-site-move-inspector' ), ) as $key => $label ) : ?>

render_section( $section ); ?>
render_inventory( $report['inventory'] ?? array() ); ?> render_exports(); ?>

check_status_label( $status ) ); ?>

__( 'Download TXT', '1gbits-site-move-inspector' ), 'json' => __( 'Download JSON', '1gbits-site-move-inspector' ), ) as $format => $label ) : ?>
__( 'High risk', '1gbits-site-move-inspector' ), 'review_recommended' => __( 'Review recommended', '1gbits-site-move-inspector' ), 'no_blockers' => __( 'No blockers detected', '1gbits-site-move-inspector' ), ); return $labels[ $overall ] ?? $labels['review_recommended']; } /** * Return a translatable check status label. * * @param string $status Status key. * @return string */ private function check_status_label( $status ) { $labels = array( 'pass' => __( 'Pass', '1gbits-site-move-inspector' ), 'warning' => __( 'Warning', '1gbits-site-move-inspector' ), 'critical' => __( 'Critical', '1gbits-site-move-inspector' ), 'unknown' => __( 'Unknown', '1gbits-site-move-inspector' ), 'not_applicable' => __( 'Not applicable', '1gbits-site-move-inspector' ), ); return $labels[ $status ] ?? $labels['unknown']; } /** * Apply site/network authorization consistently. * * @return bool */ private function current_user_can_scan() { if ( is_multisite() ) { return is_super_admin() && current_user_can( 'manage_network_options' ); } return current_user_can( 'manage_options' ); } }