$finding shaped like FindingsPage::finding_payload() */ public static function build(array $finding): string { $arabic = I18n::is_arabic(); $details = self::finding_details($finding); $lines = array_merge( self::intro_lines($arabic), self::context_lines($arabic), self::finding_lines($arabic, $details), self::request_lines($arabic) ); return implode("\n", $lines); } /** * @param array $finding * @return array */ private static function finding_details(array $finding): array { $evidence = is_array($finding['evidence'] ?? null) ? $finding['evidence'] : []; return [ 'title' => self::string_field($finding, 'title'), 'finding_id' => self::string_field($finding, 'id') !== '' ? self::string_field($finding, 'id') : self::string_field($finding, 'finding_id'), 'severity' => self::string_field($finding, 'severity'), 'category' => self::string_field($finding, 'category'), 'why' => self::string_field($finding, 'why_it_matters'), 'steps' => self::recommendation_steps($finding), 'sample_urls' => self::sample_urls($evidence), 'affected' => (int) ($finding['affected_count'] ?? ($evidence['affected_count'] ?? 0)), ]; } /** * @param array $source */ private static function string_field(array $source, string $key): string { return trim((string) ($source[$key] ?? '')); } /** * @param array $finding * @return string[] */ private static function recommendation_steps(array $finding): array { $raw_steps = is_array($finding['recommendation_steps'] ?? null) ? $finding['recommendation_steps'] : []; return array_values(array_filter(array_map( static fn($step): string => trim((string) (is_array($step) ? ($step['text'] ?? '') : $step)), $raw_steps ))); } /** * @param array $evidence * @return string[] */ private static function sample_urls(array $evidence): array { if (!isset($evidence['sample_urls']) || !is_array($evidence['sample_urls'])) { return []; } $urls = []; foreach (array_slice(array_values($evidence['sample_urls']), 0, 5) as $sample) { $url = trim((string) (is_array($sample) ? ($sample['url'] ?? '') : $sample)); if ($url !== '') { $urls[] = $url; } } return $urls; } /** * @return string[] */ private static function intro_lines(bool $arabic): array { return [ $arabic ? 'أنت خبير WordPress وSEO. لديّ مشكلة واحدة محددة في موقعي، وأريد مساعدتك لإصلاحها خطوة بخطوة.' : 'You are a WordPress and SEO expert. I have one specific issue on my site and I want you to help me fix it step by step.', '', ]; } /** * @return string[] */ private static function context_lines(bool $arabic): array { $lines = [$arabic ? '## عن الموقع' : '## Site context']; foreach (self::site_context($arabic) as $label => $value) { if ($value !== '') { $lines[] = '- ' . $label . ': ' . $value; } } $lines[] = ''; return $lines; } /** * @param array $details * @return string[] */ private static function finding_lines(bool $arabic, array $details): array { $lines = [$arabic ? '## المشكلة (من فحص Aetos SEO الداخلي)' : '## Issue from the internal Aetos SEO audit']; $lines[] = '- ' . self::label($arabic, 'Title', 'العنوان') . ': ' . (string) $details['title']; foreach (['finding_id', 'severity', 'category', 'why'] as $key) { if ((string) $details[$key] !== '') { $lines[] = '- ' . self::detail_label($arabic, $key) . ': ' . (string) $details[$key]; } } $lines = array_merge($lines, self::affected_url_lines($arabic, $details)); $lines = array_merge($lines, self::step_lines($arabic, $details)); $lines[] = ''; return $lines; } private static function detail_label(bool $arabic, string $key): string { $labels = [ 'finding_id' => ['Technical ID', 'المعرّف التقني'], 'severity' => ['Severity', 'الخطورة'], 'category' => ['Category', 'التصنيف'], 'why' => ['Why it matters', 'لماذا يهم'], ]; [$en, $ar] = $labels[$key] ?? [$key, $key]; return self::label($arabic, $en, $ar); } /** * @param array $details * @return string[] */ private static function affected_url_lines(bool $arabic, array $details): array { $sample_urls = is_array($details['sample_urls']) ? $details['sample_urls'] : []; if (empty($sample_urls) && (int) $details['affected'] <= 0) { return []; } $lines = []; if (!empty($sample_urls)) { $lines[] = '- ' . self::label($arabic, 'Affected pages (sample)', 'صفحات متأثرة (عينة)') . ':'; foreach ($sample_urls as $url) { $lines[] = ' - ' . $url; } } if ((int) $details['affected'] > count($sample_urls)) { $lines[] = '- ' . self::label($arabic, 'Total affected pages', 'إجمالي الصفحات المتأثرة') . ': ' . (int) $details['affected']; } return $lines; } /** * @param array $details * @return string[] */ private static function step_lines(bool $arabic, array $details): array { $steps = is_array($details['steps']) ? $details['steps'] : []; if (empty($steps)) { return []; } $lines = ['- ' . self::label($arabic, 'Suggested fix steps from the audit', 'خطوات الإصلاح المقترحة من الفحص') . ':']; foreach (array_slice($steps, 0, 5) as $index => $step) { $lines[] = ' ' . ((int) $index + 1) . '. ' . $step; } return $lines; } /** * @return string[] */ private static function request_lines(bool $arabic): array { if ($arabic) { return [ '## المطلوب منك', '1. اشرح المشكلة بلغة بسيطة، ولماذا تؤثر في ظهور الموقع في البحث وإجابات AI.', '2. أعطني خطوات إصلاح تفصيلية لهذا الموقع تحديدًا باستخدام نفس القالب وإضافة الـ SEO المذكورين أعلاه.', '3. إذا وُجدت أكثر من طريقة للإصلاح فرشّح الأنسب لمستوى مبتدئ واشرح السبب.', '4. اذكر اسم الشاشة أو الإعداد أو الملف الذي أعدّله بالضبط إن أمكن.', '5. وضّح كيف أتحقق من نجاح الإصلاح بعد التنفيذ.', '6. مهم: لا تعطيني نصائح SEO عامة. ركّز على هذه المشكلة وهذا الموقع فقط، واسألني عن أي معلومة ناقصة قبل الإجابة.', ]; } return [ '## What I need from you', '1. Explain this issue in simple language and why it can affect search visibility or AI answers.', '2. Give me detailed fix steps for this specific site, using the theme and SEO plugin listed above.', '3. If there is more than one fix path, recommend the best beginner-friendly option and explain why.', '4. Name the exact WordPress screen, setting, plugin option, or file to edit when possible.', '5. Tell me how to verify that the fix worked after I implement it.', '6. Important: do not give generic SEO advice. Focus only on this issue and this site, and ask for any missing information before answering.', ]; } private static function label(bool $arabic, string $english, string $arabic_text): string { return $arabic ? $arabic_text : $english; } /** * Local site context only (WP APIs, no external calls). * * @return array */ private static function site_context(bool $arabic): array { $home = function_exists('home_url') ? (string) home_url('/') : ''; $name = function_exists('get_bloginfo') ? (string) get_bloginfo('name') : ''; $wp = function_exists('get_bloginfo') ? (string) get_bloginfo('version') : ''; $lang = function_exists('get_bloginfo') ? (string) get_bloginfo('language') : ''; $theme = self::active_theme_label(); $permalinks = function_exists('get_option') ? (string) get_option('permalink_structure', '') : ''; $seo_plugin = self::detected_seo_plugin(); return [ self::label($arabic, 'URL', 'الرابط') => $home, self::label($arabic, 'Site name', 'اسم الموقع') => $name, self::label($arabic, 'Content language', 'لغة المحتوى') => $lang, 'WordPress' => $wp, self::label($arabic, 'Active theme', 'الثيم النشط') => trim($theme), self::label($arabic, 'Detected SEO plugin', 'إضافة SEO المرصودة') => $seo_plugin !== '' ? $seo_plugin : self::label($arabic, 'None detected', 'لا يوجد'), self::label($arabic, 'Permalink structure', 'شكل الروابط') => $permalinks !== '' ? $permalinks : 'default (?p=)', self::label($arabic, 'Audit tool', 'أداة الفحص') => self::label( $arabic, 'Aetos SEO (local WordPress audit, no external service)', 'Aetos SEO (فحص داخلي من داخل WordPress، بدون أي خدمة خارجية)' ), ]; } private static function active_theme_label(): string { if (!function_exists('wp_get_theme')) { return ''; } $theme = wp_get_theme(); if (!is_object($theme) || !method_exists($theme, 'get')) { return ''; } return trim((string) $theme->get('Name') . ' ' . (string) $theme->get('Version')); } private static function detected_seo_plugin(): string { if (defined('WPSEO_VERSION')) { return 'Yoast SEO'; } if (class_exists('RankMath') || defined('RANK_MATH_VERSION')) { return 'Rank Math'; } if (defined('AIOSEO_VERSION')) { return 'All in One SEO'; } if (defined('SEOPRESS_VERSION')) { return 'SEOPress'; } return ''; } }