|null */ private static $excluded_cache = null; /** @var array|null */ private static $legit_short_cache = null; /** @var array|null */ private static $archive_cache = null; /** * Auto-redirect routes, admin/cart/login pages, REST endpoints, feeds. * Pages crawled but excluded from SEO findings. * * @return array */ public static function excluded_patterns(): array { if (self::$excluded_cache !== null) { return self::$excluded_cache; } $defaults = [ '#^/\d{8,}/?$#', // numeric-only paths (phone numbers, IDs) '#^/(redirect|go|qr|out|track|r|u)/.+#i', // redirect prefixes '#^/(login|admin|cart|checkout|my-account|wp-admin|wp-login)#i', '#^/wp-json/#i', // REST endpoints '#^/feed/?$#i', // feeds '#^/(tag|author)/.+#i', // tag/author archives '#\?(p|page_id|preview)=#', // raw query-string only URLs ]; if (function_exists('apply_filters')) { self::$excluded_cache = (array) apply_filters('aetos_seo_excluded_url_patterns', $defaults); } else { self::$excluded_cache = $defaults; } return self::$excluded_cache; } /** * URLs whose short content is legitimate (legal pages, contact pages, * cart/checkout, archive indexes). Used by thin-content checks. * * @return array */ public static function legitimately_short_substrings(): array { if (self::$legit_short_cache !== null) { return self::$legit_short_cache; } $defaults = [ // Trust / legal '/contact', '/التواصل', '/اتصل-بنا', '/اتصل', '/تواصل', '/disclaimer', '/إخلاء-المسؤولية', '/اخلاء-المسؤولية', '/privacy', '/سياسة-الخصوصية', '/terms', '/الشروط', '/شروط-الاستخدام', '/refund', '/الاسترجاع', '/سياسة-الاسترجاع', '/cookies', '/كوكيز', // Commerce flow '/cart', '/سلة', '/checkout', '/الدفع', '/login', '/تسجيل-الدخول', '/register', '/إنشاء-حساب', '/my-account', '/حسابي', '/thank-you', '/شكرا', '/404', '/not-found', // Site machinery '/sitemap', '/خريطة-الموقع', '/sla', '/service-level-agreement', '/intellectual-property', '/dmca', '/gdpr', '/accessibility', '/مركز-المساعدة', '/مركز-المساعده', '/help-center', '/support', ]; if (function_exists('apply_filters')) { self::$legit_short_cache = (array) apply_filters('aetos_seo_short_path_substrings', $defaults); } else { self::$legit_short_cache = $defaults; } return self::$legit_short_cache; } /** * Substrings that identify archive/listing pages. AI-Overview-style * checks (DirectAnswerPattern, AiOverview, QuestionCoverage) should * skip these since they aggregate content rather than answer queries. * * @return array */ public static function archive_substrings(): array { if (self::$archive_cache !== null) { return self::$archive_cache; } $defaults = [ '/blog', '/news', '/articles', '/posts', '/portfolio', '/gallery', '/category/', '/tag/', '/author/', '/page/', // paginated listing '/المدونة', '/مقالات', '/أخبار', '/الأخبار', ]; if (function_exists('apply_filters')) { self::$archive_cache = (array) apply_filters('aetos_seo_archive_substrings', $defaults); } else { self::$archive_cache = $defaults; } return self::$archive_cache; } public static function is_excluded(string $url): bool { $path = wp_parse_url($url, PHP_URL_PATH); if (!is_string($path) || $path === '') { $path = '/'; } foreach (self::excluded_patterns() as $pattern) { if (is_string($pattern) && $pattern !== '' && @preg_match($pattern, $path)) { return true; } } return false; } public static function is_legitimately_short(string $url): bool { if (self::is_archive_index($url)) { return true; } $u = Str::lower(rawurldecode($url)); foreach (self::legitimately_short_substrings() as $sub) { if (is_string($sub) && $sub !== '' && strpos($u, $sub) !== false) { return true; } } return false; } public static function is_archive_index(string $url): bool { $path = wp_parse_url($url, PHP_URL_PATH); if (!is_string($path) || $path === '') { $path = '/'; } $path = '/' . trim(Str::lower(rawurldecode($path)), '/'); foreach (self::archive_substrings() as $sub) { if (!is_string($sub) || $sub === '') { continue; } $normalized = Str::lower(rawurldecode($sub)); if (substr($normalized, -1) === '/' && strpos($path, $normalized) === 0) { return true; } $root = '/' . trim($normalized, '/'); if ($path === $root || preg_match('~^' . preg_quote($root, '~') . '/page/\d+/?$~', $path)) { return true; } } return false; } /** * Reset internal caches. Call from tests or when filters change at runtime. */ public static function reset_cache(): void { self::$excluded_cache = null; self::$legit_short_cache = null; self::$archive_cache = null; } }