string, 'reason' => string ] */ public static function evaluate($inspection, $url) { // 1. Check HTTP Status // If not 200, it's strictly not indexable content (though 3xx redirects index flow) if ($inspection['code'] !== 200) { return [ 'status' => self::STATUS_NOINDEX, 'reason' => 'HTTP ' . $inspection['code'] ]; } // 2. Check Robots.txt (Plugin Controlled) if (self::is_robots_blocked($url)) { return [ 'status' => self::STATUS_BLOCKED, 'reason' => 'Blocked by robots.txt' ]; } // 3. Check Directives (Meta & Headlines) $noindex = self::has_directive($inspection, 'noindex'); $index = self::has_directive($inspection, 'index'); if ($noindex && $index) { return [ 'status' => self::STATUS_INDETERMINATE, 'reason' => 'Conflicting "index" and "noindex" directives' ]; } if ($noindex) { return [ 'status' => self::STATUS_NOINDEX, 'reason' => 'Explicit "noindex" directive' ]; } // Default: Indexable return [ 'status' => self::STATUS_INDEXABLE, 'reason' => 'Indexable (Default)' ]; } private static function has_directive($inspection, $directive) { $sources = array_merge($inspection['robots_meta'], $inspection['x_robots_tag']); foreach ($sources as $source) { // Parse "noindex, follow" -> ["noindex", "follow"] $parts = explode(',', $source); foreach ($parts as $part) { if (trim(strtolower($part)) === $directive) { return true; } } } return false; } private static function is_robots_blocked($url) { // Get effective robots.txt content $content = \ActiveTwist\SEO\Settings\Options::get('robots_txt_content'); if (empty($content)) { $content = \ActiveTwist\SEO\Features\RobotsController::get_default_content(); } // Parse path from URL $path = wp_parse_url($url, PHP_URL_PATH); if (empty($path)) { $path = '/'; } // Simple User-Agent: * parser $lines = explode("\n", $content); $ua_applies = true; // Assuming * or matching UA logic is simple here foreach ($lines as $line) { $line = trim($line); if (empty($line) || strpos($line, '#') === 0) continue; // Very basic parser: User-agent reset if (stripos($line, 'User-agent:') === 0) { $ua = trim(substr($line, 11)); $ua_applies = ($ua === '*'); // Only care about global rules for now continue; } if (!$ua_applies) continue; if (stripos($line, 'Disallow:') === 0) { $rule = trim(substr($line, 9)); if (empty($rule)) continue; // Disallow: empty means allow all // Check prefix match // Rule: /wp-admin/ matches /wp-admin/foo if (strpos($path, $rule) === 0) { return true; } } } return false; } }