0 ) { set_transient( contai_site_gen_notice_transient_key( $user_id ), array( 'notice' => $notice, 'form_values' => $form_values, ), MINUTE_IN_SECONDS ); } wp_safe_redirect( admin_url( 'admin.php?page=contai-ai-site-generator' ) ); exit; } function contai_handle_ai_site_generator_submission() { // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce is verified below via wp_verify_nonce(). if ( ! isset( $_POST['contai_start_site_generation'] ) ) { return; } $nonce_value = isset( $_POST['contai_site_generator_nonce'] ) ? sanitize_key( wp_unslash( $_POST['contai_site_generator_nonce'] ) ) : ''; if ( ! wp_verify_nonce( $nonce_value, 'contai_site_generator_nonce' ) ) { contai_redirect_with_notice( array( 'type' => 'error', 'message' => __( 'Your session expired before the form could be submitted. Your data is preserved below — click Launch Site Generation again to retry.', '1platform-content-ai' ), ), contai_capture_submitted_form_values() ); } if ( ! current_user_can( 'manage_options' ) ) { wp_die( esc_html__( 'You do not have permission to perform this action.', '1platform-content-ai' ) ); } try { $error = contai_process_site_generation_submission(); if ( $error ) { contai_redirect_with_notice( $error, contai_capture_submitted_form_values() ); } } catch ( \Throwable $e ) { contai_log( 'Site generation submission failed: ' . $e->getMessage() ); // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped contai_redirect_with_notice( array( 'type' => 'error', 'message' => __( 'An unexpected error occurred while starting site generation. Please try again.', '1platform-content-ai' ), ), contai_capture_submitted_form_values() ); } } function contai_process_site_generation_submission() { $site_category = sanitize_text_field( wp_unslash( $_POST['contai_site_category'] ?? '' ) ); if ( empty( $site_category ) ) { return array( 'type' => 'error', 'message' => __( 'Please select a category before starting the site generation process.', '1platform-content-ai' ), ); } require_once __DIR__ . '/../services/billing/CreditGuard.php'; $creditGuard = new ContaiCreditGuard(); $creditCheck = $creditGuard->validateCredits(); if ( ! $creditCheck['has_credits'] ) { return array( 'type' => 'error', 'message' => $creditCheck['message'], ); } $jobRepository = new ContaiJobRepository(); $activeJob = $jobRepository->findActiveSiteGenerationJob(); if ( $activeJob ) { return array( 'type' => 'error', 'message' => __( 'There is already an active site generation process running.', '1platform-content-ai' ), ); } $site_language = sanitize_text_field( wp_unslash( $_POST['contai_site_language'] ?? 'english' ) ); $target_language = ContaiCategoryAPIService::normalizeLanguage( $site_language ); $payload = array( 'config' => array( 'site_config' => array( 'site_topic' => sanitize_text_field( wp_unslash( $_POST['contai_site_topic'] ?? '' ) ), 'site_language' => $site_language, 'site_category' => sanitize_text_field( wp_unslash( $_POST['contai_site_category'] ?? '' ) ), 'wordpress_theme' => sanitize_text_field( wp_unslash( $_POST['contai_wordpress_theme'] ?? 'astra' ) ), ), 'legal_info' => array( 'owner' => sanitize_text_field( wp_unslash( $_POST['contai_legal_owner'] ?? '' ) ), 'email' => sanitize_email( wp_unslash( $_POST['contai_legal_email'] ?? '' ) ), 'address' => sanitize_text_field( wp_unslash( $_POST['contai_legal_address'] ?? '' ) ), 'activity' => sanitize_text_field( wp_unslash( $_POST['contai_legal_activity'] ?? '' ) ), ), 'keyword_extraction' => array( 'source_topic' => sanitize_text_field( wp_unslash( $_POST['contai_source_topic'] ?? '' ) ), 'target_country' => sanitize_text_field( wp_unslash( $_POST['contai_target_country'] ?? 'us' ) ), 'target_language' => $target_language, ), 'post_generation' => array( 'num_posts' => absint( $_POST['contai_num_posts'] ?? 100 ), 'target_country' => sanitize_text_field( wp_unslash( $_POST['contai_target_country'] ?? 'us' ) ), 'target_language' => $target_language, 'image_provider' => sanitize_text_field( wp_unslash( $_POST['contai_image_provider'] ?? 'pexels' ) ), ), 'comments' => array( 'num_posts' => absint( $_POST['contai_num_posts'] ?? 100 ), 'comments_per_post' => absint( $_POST['contai_comments_per_post'] ?? 1 ), ), 'adsense' => array( 'publisher_id' => sanitize_text_field( wp_unslash( $_POST['contai_adsense_publisher'] ?? '' ) ), ), ), 'progress' => array( 'current_step' => 0, 'current_step_name' => '', 'completed_steps' => array(), 'total_steps' => ( new ContaiSiteGenerationJob() )->getStepCount(), 'started_at' => current_time( 'mysql' ), ), ); $job = ContaiJob::create( ContaiSiteGenerationJob::TYPE, $payload, 0 ); $created = $jobRepository->create( $job ); if ( ! $created ) { return array( 'type' => 'error', 'message' => __( 'Failed to start site generation process.', '1platform-content-ai' ), ); } update_option( 'contai_site_language', $site_language ); if ( ! empty( $_POST['contai_site_category'] ) ) { update_option( 'contai_site_category', sanitize_text_field( wp_unslash( $_POST['contai_site_category'] ) ) ); } $adsense_publisher = sanitize_text_field( wp_unslash( $_POST['contai_adsense_publisher'] ?? '' ) ); if ( ! empty( $adsense_publisher ) && preg_match( '/^pub-\d+$/', $adsense_publisher ) ) { update_option( 'contai_adsense_publishers', $adsense_publisher ); if ( function_exists( 'contai_generate_adsense_ads' ) ) { contai_generate_adsense_ads(); } } contai_redirect_with_notice( array( 'type' => 'success', 'message' => __( 'Site generation process has been started successfully!', '1platform-content-ai' ), ) ); } add_action( 'admin_init', 'contai_handle_ai_site_generator_submission' ); function contai_ai_site_generator_page() { if ( contai_render_connection_required_notice() ) { return; } $jobRepository = new ContaiJobRepository(); $activeJob = $jobRepository->findActiveSiteGenerationJob(); $hasActiveJob = ! empty( $activeJob ); $notice = null; $preserved_form_data = array(); $user_id = get_current_user_id(); if ( $user_id > 0 ) { $transient_key = contai_site_gen_notice_transient_key( $user_id ); $payload = get_transient( $transient_key ); if ( ! empty( $payload ) && is_array( $payload ) ) { delete_transient( $transient_key ); if ( ! empty( $payload['notice'] ) && is_array( $payload['notice'] ) ) { $notice = $payload['notice']; } if ( ! empty( $payload['form_values'] ) && is_array( $payload['form_values'] ) ) { $preserved_form_data = $payload['form_values']; } } } $GLOBALS['contai_site_gen_preserved_form_data'] = $preserved_form_data; if ( $notice ) { $type = in_array( $notice['type'], array( 'success', 'error', 'warning', 'info' ), true ) ? $notice['type'] : 'info'; $msg = $notice['message'] ?? ''; if ( ! empty( $msg ) ) { $icon_map = array( 'success' => 'dashicons-yes-alt', 'error' => 'dashicons-warning', 'warning' => 'dashicons-warning', 'info' => 'dashicons-info', ); printf( '

%3$s

', esc_attr( $type ), esc_attr( $icon_map[ $type ] ), esc_html( $msg ) ); } } ?>

findLastSiteGenerationJob(); if ( ! $lastJob ) { return; } $status = $lastJob->getStatus(); if ( $status !== 'failed' ) { return; } $errorMessage = $lastJob->getErrorMessage() ?? __( 'Unknown error', '1platform-content-ai' ); $completedSteps = $lastJob->getPayload()['progress']['completed_steps'] ?? array(); $totalSteps = $lastJob->getPayload()['progress']['total_steps'] ?? 0; $failedStep = $lastJob->getPayload()['progress']['current_step_name'] ?? ''; // Failed job notice (#55) — status === 'failed' ?>

getPayload(); $progress = $payload['progress'] ?? array(); $currentStep = $progress['current_step_name'] ?? 'Unknown'; $completedSteps = $progress['completed_steps'] ?? array(); $totalSteps = $progress['total_steps'] ?? ( new ContaiSiteGenerationJob() )->getStepCount(); $completedCount = count( $completedSteps ); $percentage = $totalSteps > 0 ? round( ( $completedCount / $totalSteps ) * 100 ) : 0; $status = $job->getStatus(); $statusLower = strtolower( $status ); $statusBadge = 'contai-badge-info'; if ( in_array( $statusLower, array( 'done', 'completed', 'success' ), true ) ) { $statusBadge = 'contai-badge-success'; } elseif ( in_array( $statusLower, array( 'failed', 'error' ), true ) ) { $statusBadge = 'contai-badge-danger'; } elseif ( in_array( $statusLower, array( 'processing', 'running' ), true ) ) { $statusBadge = 'contai-badge-info'; } elseif ( in_array( $statusLower, array( 'pending', 'queued' ), true ) ) { $statusBadge = 'contai-badge-neutral'; } ?>

getErrorMessage() ?? __( 'Unknown error', '1platform-content-ai' ); $isBalanceError = ContaiCreditGuard::isInsufficientCreditsError( $jobError ) || stripos( $jobError, 'Insufficient balance' ) !== false; ?>