is_plugin_admin_page($hook_suffix)) { return; } $admin_css = function_exists('aetos_seo_asset_url') ? aetos_seo_asset_url('assets/admin.css') : AETOS_SEO_URL . 'assets/admin.css'; $admin_js = function_exists('aetos_seo_asset_url') ? aetos_seo_asset_url('assets/admin.js') : AETOS_SEO_URL . 'assets/admin.js'; wp_enqueue_style( 'aetos-seo-admin', $admin_css, [], AETOS_SEO_VERSION ); wp_enqueue_script( 'aetos-seo-admin', $admin_js, ['jquery'], AETOS_SEO_VERSION, true ); $settings = Settings::get(); // v3.0.0 — delegate to shared Utils\I18n so the JS-side i18n payload // honors the Settings → Admin Locale toggle. Pre-3.0.0 the local $txt // closure used is_rtl() only, ignoring the plugin-level override. $rtl = \AetosSeo\Utils\I18n::is_arabic(); $txt = static function (string $en, string $ar): string { return \AetosSeo\Utils\I18n::tr($en, $ar); }; wp_localize_script('aetos-seo-admin', 'AetosSeoData', [ 'ajaxUrl' => admin_url('admin-ajax.php'), 'nonces' => [ // 2026-06-12 — the external-AI chat / provider-test / analyze // and knowledge-reindex nonces were removed with the // external-AI feature (internal-only direction): their wp_ajax // handlers no longer exist, so the nonces were dead weight. 'crawlBatch' => wp_create_nonce('aetos_seo_crawl_batch'), 'markFinding' => wp_create_nonce('aetos_seo_mark_finding'), 'getFinding' => wp_create_nonce('aetos_seo_get_finding'), 'auditStatus' => wp_create_nonce('aetos_seo_audit_status'), 'resetData' => wp_create_nonce('aetos_seo_reset_data'), ], // Delay between crawl batches (shared hosting friendly). // 4.0.18: labels for evidence keys shown in the details dialog. 'evidenceKeys' => [ 'url' => $txt('Address', 'العنوان'), 'found_on' => $txt('Found on', 'موجود في'), 'status' => $txt('Response code', 'رمز الاستجابة'), 'target' => $txt('Redirects to', 'يحوّل إلى'), 'error' => $txt('Error', 'الخطأ'), 'item' => $txt('Item', 'العنصر'), 'title' => $txt('Title', 'العنوان الظاهر'), 'name' => $txt('Name', 'الاسم'), 'taxonomy' => $txt('Type', 'النوع'), 'word_count' => $txt('Words', 'عدد الكلمات'), 'inbound_links' => $txt('Links pointing here', 'الروابط المشيرة إليها'), 'similarity' => $txt('Similarity', 'نسبة التشابه'), 'url_a' => $txt('Page A', 'الصفحة الأولى'), 'url_b' => $txt('Page B', 'الصفحة الثانية'), 'guid' => $txt('File address', 'عنوان الملف'), 'id' => $txt('ID', 'الرقم'), 'missing' => $txt('Missing', 'الناقص'), 'recommendation' => $txt('Suggested change', 'التعديل المقترح'), 'skip' => $txt('Heading order', 'ترتيب العناوين'), 'sequence' => $txt('Heading levels in order', 'مستويات العناوين بالترتيب'), 'offending_heading' => $txt('Heading to change', 'العنوان المطلوب تعديله'), 'from_heading' => $txt('Heading before the jump', 'العنوان قبل القفزة'), 'to_heading' => $txt('Heading after the jump', 'العنوان بعد القفزة'), 'h2_texts' => $txt('H2 headings', 'عناوين H2'), 'h3_texts' => $txt('H3 headings', 'عناوين H3'), 'edit_link' => $txt('Edit in WordPress', 'التعديل في ووردبريس'), 'details' => $txt('Details', 'التفاصيل'), 'risk_factors' => $txt('Risks found', 'المخاطر المرصودة'), 'size' => $txt('Size', 'الحجم'), 'size_kb' => $txt('Size (KB)', 'الحجم (كيلوبايت)'), 'file' => $txt('File', 'الملف'), 'path' => $txt('Path', 'المسار'), 'accept' => $txt('Requested format', 'الصيغة المطلوبة'), 'returned_ctype' => $txt('Returned format', 'الصيغة المُعادة'), 'endpoint' => $txt('Address checked', 'العنوان المفحوص'), 'users' => $txt('Usernames', 'أسماء المستخدمين'), 'count' => $txt('Count', 'العدد'), 'ratio' => $txt('Share', 'النسبة'), ], 'crawlDelayMs' => (int) apply_filters('aetos_seo_crawl_delay_ms', (int) ($settings['scan_limits']['crawl_delay_ms'] ?? 1500)), 'i18n' => [ // Evidence modal labels 'label_category' => $txt('Category', 'التصنيف'), 'label_severity' => $txt('Severity', 'الخطورة'), 'label_status' => $txt('Status', 'الحالة'), 'label_impact' => $txt('Impact', 'التأثير'), 'label_description' => $txt('Description', 'الوصف'), 'label_why_it_matters' => $txt('Why it matters', 'لماذا هذا مهم'), 'label_evidence' => $txt('Evidence', 'الدليل'), 'label_steps' => $txt('Fix steps', 'خطوات الإصلاح'), 'label_retest' => $txt('How to verify the fix', 'طريقة التحقق بعد الإصلاح'), 'label_how' => $txt('Method', 'الطريقة'), 'label_pass' => $txt('Pass condition', 'شرط النجاح'), 'label_affected_items' => $txt('Affected items/pages', 'العناصر أو الصفحات المتأثرة'), 'label_stack_refs' => $txt('Related tools found on the site', 'أدوات مرتبطة موجودة في الموقع'), 'label_external_verification' => $txt('External verification', 'التحقق الخارجي'), 'label_open_external_check' => $txt('Open external check', 'فتح الفحص الخارجي'), 'label_raw_evidence' => $txt('Technical data for developers', 'بيانات تقنية للمطورين'), 'label_finding_id' => $txt('Finding id', 'معرّف النتيجة'), 'impact_points' => $txt('Costs {n} points', 'تخصم {n} نقاط'), 'shown_of_total' => $txt('{shown} of {total}', '{shown} من {total}'), 'and_more' => $txt('And {n} more not shown here. The full list is in the export.', 'وهناك {n} غيرها غير معروضة هنا، والقائمة الكاملة في ملف التصدير.'), 'mark_fixed' => $txt('Mark as fixed', 'تم حلها'), 'copy_ai_prompt' => $txt('Copy a prompt for your AI assistant', 'انسخ طلبًا جاهزًا لمساعد الذكاء الاصطناعي'), 'ignore' => $txt('Ignore', 'تجاهل'), 'cancel' => $txt('Cancel', 'إلغاء'), 'external_verification_note' => $txt( 'This finding needs an external check because server-side loopback may not see headers added by CDN or edge services.', 'هذا الفحص يحتاج تحققاً خارجياً لأن الطلب الداخلي من السيرفر قد لا يرى الهيدرز التي يضيفها CDN أو طبقة الحافة.' ), 'copy_link_title' => $txt('Copy link', 'نسخ الرابط'), 'copy' => $txt('Copy', 'نسخ'), 'copied' => $txt('Copied', 'تم النسخ'), // Severity labels 'severity_high' => \AetosSeo\Admin\Labels::severity('high'), 'severity_med' => \AetosSeo\Admin\Labels::severity('med'), 'severity_low' => \AetosSeo\Admin\Labels::severity('low'), 'severity_info' => \AetosSeo\Admin\Labels::severity('info'), // Findings stats-bar chip labels (admin.js buildFindingsStatsBar). // These keys MUST match the t('...') lookups in admin.js, else the // chips fall back to the Arabic literal even under an English UI. 'findings_stats_label' => $txt('Findings:', 'النتائج:'), 'sev_high' => \AetosSeo\Admin\Labels::severity('high'), 'sev_med' => \AetosSeo\Admin\Labels::severity('med'), 'sev_low' => \AetosSeo\Admin\Labels::severity('low'), 'status_open' => \AetosSeo\Admin\Labels::status('open'), 'status_done' => \AetosSeo\Admin\Labels::status('done'), 'total' => $txt('All', 'الكل'), // Evidence stack labels 'detected_optimizers' => $txt('Detected image optimizers', 'إضافات تحسين الصور المرصودة'), 'active_security_plugins' => $txt('Active security plugins', 'إضافات الأمان النشطة'), 'related_plugins' => $txt('Related plugins', 'الإضافات المرتبطة'), 'detected_cdn' => $txt('Detected CDN', 'الـ CDN المرصود'), 'server_software' => $txt('Server software', 'برنامج السيرفر'), // Wizard / status messages 'wizard_updated' => $txt('Saved: {status}.', 'تم الحفظ: {status}.'), 'update_failed' => $txt('Update failed.', 'فشل التحديث.'), 'request_failed' => $txt('Request failed.', 'فشل الطلب.'), 'done' => $txt('Done.', 'تم.'), 'failed' => $txt('Failed.', 'فشل.'), // Crawl 'crawl_error' => $txt('Error: {message}', 'خطأ: {message}'), 'crawl_done_refresh' => $txt('Done. Refresh the page to see results.', 'تم. حدّث الصفحة لرؤية النتائج.'), 'crawl_done_reloading' => $txt('Done. Reloading...', 'تم. جارٍ تحديث الصفحة...'), 'crawl_paused' => $txt('Paused.', 'متوقف مؤقتاً.'), 'pages_per_min' => $txt('pages/min', 'صفحة/دقيقة'), // Background audit 'audit_completed_refresh' => $txt('Audit completed. Refreshing...', 'اكتمل الفحص. جارٍ تحديث الصفحة...'), 'audit_failed_try' => $txt('Audit failed. Try again from this page. If it fails again, use Help and include the audit number.', 'فشل الفحص. حاول مرة أخرى من هذه الصفحة. إذا فشل مجدداً فاستخدم المساعدة وأرفق رقم الفحص.'), 'status_updates_auto' => $txt('Status updates automatically.', 'يتم تحديث الحالة تلقائياً.'), 'audit_queued_waiting' => $txt('Queued scan. Waiting for first batch...', 'الفحص في الطابور. في انتظار أول دفعة...'), 'audit_running_batches' => $txt('Running scan in background batches...', 'الفحص يعمل في دفعات بالخلفية...'), 'progress_label' => $txt('Progress', 'التقدم'), 'audit_state_queued' => $txt('waiting to start', 'في انتظار البدء'), 'audit_state_collecting' => $txt('collecting pages', 'يجمع الصفحات'), 'audit_state_running' => $txt('scanning now', 'يفحص الآن'), 'audit_state_completed' => $txt('finished', 'انتهى'), 'page_notices' => $txt('Page notices', 'إشعارات الصفحة'), 'other_plugin_notices' => $txt('Other plugin notices', 'إشعارات إضافات أخرى'), 'yes' => $txt('yes', 'نعم'), 'no' => $txt('no', 'لا'), 'refreshing' => $txt('Refreshing...', 'جارٍ التحديث...'), 'starting' => $txt('Starting...', 'جارٍ البدء...'), 'ok_status' => $txt('OK: {status}', 'سليم: {status}'), 'ok_message' => $txt('OK: {message}', 'سليم: {message}'), 'failed_message' => $txt('Failed: {message}', 'فشل: {message}'), 'security_token_expired' => $txt('Security token expired. Refresh the page and try again.', 'انتهت صلاحية رمز الأمان. حدّث الصفحة ثم حاول مرة أخرى.'), 'ajax_blocked_fallback' => $txt('AJAX blocked or timed out. Trying fallback...', 'تم حظر AJAX أو انتهت المهلة. جارٍ تجربة المسار الاحتياطي...'), // Reset 'reset_scan_confirm' => $txt( "Clear scan results?\n\nPast audits, their findings, crawl data and reports will be deleted.\n\nYour settings will stay.", "مسح نتائج الفحص؟\n\nسيتم حذف الفحوصات السابقة ونتائجها وبيانات الزحف والتقارير.\n\nستبقى إعداداتك كما هي." ), 'reset_factory_confirm' => $txt( "Factory reset plugin data?\n\nThis clears scan data, settings, generated reports, locks, and scheduled scan jobs.\n\nThis cannot be undone.", "إعادة الإضافة إلى حالتها الأولى؟\n\nسيتم مسح بيانات الفحص والإعدادات والتقارير.\n\nلا يمكن التراجع عن هذا الإجراء." ), 'reset_confirm' => $txt( "Are you sure?\n\nAll scan, crawl, finding, and export data will be deleted.\n\nSettings will not be changed.\n\nThis action cannot be undone.", "هل أنت متأكد؟\n\nسيتم حذف كل بيانات الفحص والزحف والنتائج والتصديرات.\n\nالإعدادات لن تتأثر.\n\nلا يمكن التراجع عن هذا الإجراء." ), 'resetting' => $txt('Clearing data...', 'جارٍ مسح البيانات...'), 'reset_all_data' => $txt('Clear all data', 'مسح كل البيانات'), ], ]); } private function is_plugin_admin_page(string $hook_suffix): bool { $page_raw = filter_input(INPUT_GET, 'page', FILTER_UNSAFE_RAW); $page = is_string($page_raw) ? sanitize_key(wp_unslash($page_raw)) : ''; return strpos($hook_suffix, 'aetos-seo') !== false || strpos($page, 'aetos-seo') !== false; } }