step_index( $current ); $next = self::STEPS[ $idx + 1 ] ?? null; return $next ? $this->step_url( $next ) : admin_url( 'admin.php?page=' . AEOMATIC_Admin::MENU_SLUG ); } public function prev_step_url( string $current ): string { $idx = $this->step_index( $current ); $prev = self::STEPS[ $idx - 1 ] ?? null; return $prev ? $this->step_url( $prev ) : $this->step_url( self::STEPS[0] ); } public function step_label( string $step ): string { switch ( $step ) { case 'welcome': return __( 'Welcome', 'aeomatic' ); case 'import': return __( 'Import existing settings', 'aeomatic' ); case 'org': return __( 'Your organisation', 'aeomatic' ); case 'crawlers': return __( 'AI crawlers', 'aeomatic' ); case 'readiness': return __( 'Your first audit', 'aeomatic' ); case 'verify': return __( 'Verify & finish', 'aeomatic' ); } return $step; } /** * Handle POST submissions for each step (skip and completion also come here). */ public function maybe_handle_submit(): void { if ( empty( $_POST['aeomatic_wizard_submit'] ) ) { return; } if ( ! current_user_can( 'manage_options' ) ) { wp_die( esc_html__( 'Permission denied.', 'aeomatic' ) ); } check_admin_referer( self::NONCE_ACTION ); $step = isset( $_POST['step'] ) ? sanitize_key( wp_unslash( (string) $_POST['step'] ) ) : ''; if ( ! in_array( $step, self::STEPS, true ) ) { return; } switch ( $step ) { case 'import': $this->handle_import(); break; case 'org': $this->handle_org(); break; case 'crawlers': $this->handle_crawlers(); break; case 'verify': update_option( self::COMPLETED_KEY, time() ); AEOMATIC_Activity::log( 'wizard_completed', __( 'Setup wizard completed.', 'aeomatic' ) ); wp_safe_redirect( admin_url( 'admin.php?page=' . AEOMATIC_Admin::MENU_SLUG . '&aeomatic_wizard=done' ) ); exit; } wp_safe_redirect( $this->next_step_url( $step ) ); exit; } private function handle_import(): void { // phpcs:ignore WordPress.Security.NonceVerification.Missing $sources = isset( $_POST['import_sources'] ) ? (array) wp_unslash( $_POST['import_sources'] ) : array(); if ( empty( $sources ) ) { return; } $sources = array_map( 'sanitize_key', $sources ); $available = AEOMATIC_SEO_Importer::inspect(); foreach ( $sources as $slug ) { if ( isset( $available[ $slug ] ) ) { AEOMATIC_SEO_Importer::apply( $available[ $slug ] ); AEOMATIC_Activity::log( 'wizard_import', sprintf( /* translators: %s: source plugin label */ __( 'Imported organisation settings from %s.', 'aeomatic' ), $available[ $slug ]['label'] ) ); } } } private function handle_org(): void { $all = AEOMATIC_Settings::all(); $schema = $all['schema']; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput $org_name = isset( $_POST['org_name'] ) ? sanitize_text_field( wp_unslash( (string) $_POST['org_name'] ) ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput $org_logo = isset( $_POST['org_logo'] ) ? esc_url_raw( wp_unslash( (string) $_POST['org_logo'] ) ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput $org_sameas_raw = isset( $_POST['org_sameas'] ) ? (string) wp_unslash( $_POST['org_sameas'] ) : ''; $urls = array_filter( array_map( 'trim', preg_split( '/\r\n|\r|\n/', $org_sameas_raw ) ) ); $urls = array_map( 'esc_url_raw', $urls ); $schema['org_name'] = $org_name; $schema['org_logo'] = $org_logo; $schema['org_sameas'] = implode( "\n", array_filter( $urls ) ); $all['schema'] = $schema; AEOMATIC_Settings::put( $all ); } private function handle_crawlers(): void { $all = AEOMATIC_Settings::all(); // phpcs:ignore WordPress.Security.NonceVerification.Missing $crawlers = isset( $_POST['crawlers'] ) ? (array) wp_unslash( $_POST['crawlers'] ) : array(); foreach ( $all['crawlers'] as $bot => $_ ) { $all['crawlers'][ $bot ] = ! empty( $crawlers[ $bot ] ); } AEOMATIC_Settings::put( $all ); flush_rewrite_rules(); } /** * Render the wizard shell. Loads the step body from admin/views/wizard.php. */ public function render(): void { if ( ! current_user_can( 'manage_options' ) ) { wp_die( esc_html__( 'Permission denied.', 'aeomatic' ) ); } $wizard = $this; $step = $this->current_step(); $sources = AEOMATIC_SEO_Importer::inspect(); $schema = AEOMATIC_Settings::get( 'schema' ); $crawlers = AEOMATIC_Settings::get( 'crawlers' ); // Force a fresh audit on the readiness step: the user has just changed // organisation and crawler settings, so a cached summary from before // those saves would show them stale numbers on their very first look. $readiness = 'readiness' === $step ? AEOMATIC_Site_Readiness::summary( true ) : null; require AEOMATIC_DIR . 'admin/views/wizard.php'; } }