SEO-оценка — прозрачная, версионируемая, принадлежащая Pro
Сканирование Pro присваивает каждой странице SEO-оценку 0–100 — то самое число, которое ищут при переходе с RankMath или Yoast. В отличие от непрозрачной оценки, её можно полностью проверить: каждый вычтенный балл относится ровно к одной проблеме сканирования, а одинаковый набор проблем всегда даёт одинаковое число.
score = 100 − Σ penalty(issue) for each scored issue (floored at 0)Одно число — один владелец
Числовая оценка — функция Pro. Она хранится в записи seo_scan_results Pro и никогда не записывается обратно в seo_meta ядра (старый столбец seo_score удалён в Core 3). Бесплатный seo:audit ядра сообщает pass / warn / fail для каждой страницы без числа: оценка — платная дополнительная возможность.
Методика
Оценка вычисляется по опубликованной версионируемой методике — Rankbeam\Seo\Pro\Scanning\ScoreRubric. Её определяют две вещи: явный список учитываемых кодов проблем и фиксированный штраф для каждой степени серьёзности.
| Серьёзность | Штраф | Значение |
|---|---|---|
critical | −40 | Значимая проблема в этой методике. |
warning | −15 | Проблема, которую следует вскоре изучить. |
notice | −5 | Желательное улучшение. |
Серьёзность каждого кода читается прямо из реестра проблем, единственного источника истины: методика не вычисляет её заново. Одному коду соответствует одна степень серьёзности, чтобы оценка оставалась детерминированной.
Что учитывает оценка
Это детерминированные проверки, выбранные продуктовой методикой Rankbeam, включая эвристики, требующие редакторской интерпретации. Critical вычитает 40, warning — 15, notice — 5; оценка не прогнозирует результаты в поиске.
| Код | Серьёзность | Штраф |
|---|---|---|
missing_title | critical | −40 |
missing_description | warning | −15 |
missing_og_image | notice | −5 |
duplicate_title | warning | −15 |
duplicate_description | warning | −15 |
title_too_long | warning | −15 |
title_too_short | notice | −5 |
description_too_long | warning | −15 |
description_too_short | notice | −5 |
robots_conflict_indexing | critical | −40 |
robots_conflict_following | warning | −15 |
noindex_warning | warning | −15 |
invalid_canonical | critical | −40 |
cross_domain_canonical | warning | −15 |
shared_canonical | notice | −5 |
insecure_canonical | warning | −15 |
http_error | critical | −40 |
empty_response | critical | −40 |
missing_canonical | notice | −5 |
missing_h1 | notice | −5 |
missing_image_alt | warning | −15 |
thin_content | notice | −5 |
mixed_content | warning | −15 |
canonical_target_broken | critical | −40 |
canonical_target_redirect | warning | −15 |
canonical_target_noindex | warning | −15 |
Коды метаданных обнаруживаются при сканировании модели, а коды отрендеренной страницы/сети — только при сканировании URL (см. классы выполнения). Поэтому оценка цели-модели отражает проверки метаданных, а цели-URL — отрендеренную страницу. Оценка 100 у модели означает «нет дефектов метаданных», а не «отрендеренная страница идеальна»: для этого сканируйте URL.
Что оценка намеренно НЕ учитывает
Эти коды реестра исключены намеренно. Исключения входят в контракт: тест проверяет, что каждый код реестра либо оценивается, либо перечислен здесь:
| Код | Почему исключён |
|---|---|
missing_focus_keyword | Рекомендация. Зависит от включаемого по желанию процесса seo.keywords.enabled: страница не должна получать меньше баллов за отсутствие фокусных ключевых слов, а оценка не должна зависеть от флага конфигурации. |
noindex_page | Информация. Состояние noindex — сознательный выбор, а не дефект метаданных. Эвристика «noindex со ссылкой canonical на себя» оценивается через noindex_warning. |
multiple_h1 | Информация. Google допускает несколько H1 — штрафа за это нет. |
blocked_url | Нет доказательств. SsrfGuard отклонил запрос, страница не проверялась: это не её дефект. |
canonical_target_blocked | Нет доказательств. Канонический адрес назначения не удалось проверить: это не дефект страницы. |
hreflang_invalid_code, hreflang_missing_self_reference, hreflang_duplicate_code, hreflang_missing_x_default | Рекомендация (пока). Эти коды hreflang Pro появляются при сканировании; у бесплатного аудита есть собственные коды hreflang, но они пока не меняют оценку — для включения потребуется увеличить VERSION. |
html_lang_missing, html_lang_invalid, html_lang_mismatch | Рекомендация. Языковые проверки не входят в эту методику. |
hreflang_not_reciprocal | Рекомендация. Необязательная проверка взаимности ссылок не оценивается. |
hreflang_target_unverified | Нет доказательств. Взаимность ссылок не удалось проверить. |
aeo_missing_author, aeo_article_missing_date | Рекомендация. Сигналы готовности к ответам (AEO): отмечают отсутствие сущности автора или даты публикации у статьи в сканировании и бесплатном аудите, но не меняют оценку (понадобится увеличить VERSION). |
Плотность ключевых слов, эмоционально окрашенные слова и остальные пункты чек-листа страницы вообще не входят в оценку: это рекомендации (отдельный список pass/warn/fail), а не коды реестра.
Версионирование: исторические оценки не меняются незаметно
Каждая сохранённая оценка помечается создавшей её ScoreRubric::VERSION (rubric_version). Следствия:
- Новый код проблемы не влияет на оценку, пока его явно не добавят в список учитываемых. Поэтому выпуск новой проверки не может задним числом изменить сохранённую оценку. (Изменение списка или веса само является изменением методики и повышает её версию.)
- Оценка сохраняется, а не вычисляется при чтении. Число прошлой недели останется тем же сегодня, вместе с объясняющей его методикой.
Где она хранится
Каждое сканирование создаёт или обновляет одну строку на цель в seo_scan_results:
| Столбец | Содержимое |
|---|---|
scannable_type / scannable_id | Оцениваемая модель (null для URL-целей). |
url | Оцениваемый URL. |
score | Число 0–100. |
rubric_version | Методика, по которой оно получено. |
penalty_total | Исходная сумма штрафов до ограничения снизу нулём. |
scored_issues | Сколько проблем повлияло на число. |
breakdown | [{code, severity, penalty}, …] — полная трассировка. |
keywords_enabled | Состояние seo.keywords.enabled на момент сканирования (для прозрачности; оценка от него не зависит). |
scan_run_id | Запуск, рассчитавший оценку (при очистке запуска становится null, а не удаляется: оценки — текущее состояние, не история запусков). |
scored_at | Время расчёта. |
Чтение оценки
Без интерфейса — последняя оценка модели:
use Rankbeam\Seo\Pro\Facades\SeoPro;
$result = SeoPro::resultFor($post);
$result?->score; // e.g. 85
$result?->grade(); // 'A'..'F'
$result?->breakdown; // [['code' => 'cross_domain_canonical', 'severity' => 'warning', 'penalty' => 15]]php artisan seo-pro:scan-status выводит среднюю оценку сайта в сводке. Панель Filament показывает её как основной показатель «Средний SEO-балл» с цветом по буквенной категории.
Буквенные категории
Буквенная категория для отображения выводится из числа (контракт определяет именно число):
| Оценка | Категория |
|---|---|
| 90-100 | A |
| 75-89 | B |
| 50-74 | C |
| 25-49 | D |
| 0-24 | F |
Сигнал для проверки перед публикацией (noindex_warning)
noindex_warning срабатывает при сочетании noindex с канонической ссылкой на саму страницу. Rankbeam считает это сигналом для проверки перед публикацией. Ссылка canonical на себя не доказывает, что индексация желательна: сочетание может быть намеренным. Канонический URL на другом домене не вызывает эту эвристику. Проблема содержит context.shipping_signal (например, self_canonical), а также сравниваемые canonical и page_url.
Проверку применяют оба сканера. Сканирование модели (PageScanner) сравнивает сохранённый канонический URL с URL модели. Сканирование отрендеренного URL (UrlScanner) повышает проблему страницы noindex с canonical на себя с информационного noindex_page до учитываемого noindex_warning. Поэтому сам noindex_page исключён: потенциальный конфликт в обоих путях обрабатывается через noindex_warning. Перед изменением директивы индексации проверьте реальное назначение страницы.
Конфигурация
// config/seo-pro.php → 'scan'
'score' => [
'enabled' => true, // turn the scoring pass + its persistence on/off
],Список учитываемых кодов и веса не настраиваются: для данной rubric_version оценка должна быть детерминированной во всех установках. Поэтому способ расчёта меняется на уровне кода методики, а не настройкой.