Зачем нужны кастомные canonical в MODX
Управление канонические ссылками — одна из задач, где MODX требует дополнительной настройки. Стандартные средства системы генерируют canonical автоматически на основе URL ресурса, но этого недостаточно в ряде сценариев: когда один контент доступен по нескольким URL, когда нужно указать каноническую версию на внешний ресурс, или когда страница является фильтрованной версией другой страницы. В таких случаях нужен гибкий механизм ручного управления canonical для каждого ресурса.
Что такое canonical URL и почему он важен для SEO
Тег <link rel="canonical"> — это директива для поисковых систем, указывающая, какая версия страницы является «главной» и должна индексироваться. Когда один и тот же контент доступен по нескольким адресам, поисковик получает сигнал об «истинном» URL и не расщепляет ссылочный вес между дублями.
Canonical особенно важен в следующих ситуациях:
- Контент доступен с
wwwи без него, по HTTP и HTTPS одновременно. - Страницы пагинации (
/catalog/?page=2) ссылаются на основную страницу каталога. - Фильтры и сортировка генерируют уникальные URL с одинаковым контентом.
- Один материал опубликован в нескольких разделах сайта.
Проблема дублирования контента в MODX
MODX Revolution по умолчанию формирует URL ресурсов по иерархии родительских страниц. Если ресурс перемещается или переименовывается, старые URL могут продолжать работать через псевдонимы. Кроме того, при использовании дополнений типа getPage или pdoPage для пагинации возникают десятки URL с идентичным или почти идентичным контентом. Без кастомного canonical все эти страницы конкурируют между собой в поисковой выдаче.
Решение — TV-поле, в котором редактор может указать каноническую ссылку для каждого ресурса вручную, а сниппет автоматически подставит её в тег <head>.
Шаг 1. Создание TV-поля custom_canonical
В административной панели MODX перейдите в Элементы → TV-параметры → Создать TV-параметр. Заполните следующие поля:
- Имя:
custom_canonical - Заголовок: «Кастомный canonical URL»
- Тип ввода: Текст (text)
- Шаблоны: отметьте шаблоны, в которых нужна эта возможность
Сохраните TV-параметр. Теперь в редакторе каждого ресурса появится вкладка «TV-параметры» с полем для ввода canonical URL.
Шаг 2. Создание сниппета set_canonical
Перейдите в Элементы → Сниппеты → Создать сниппет. Назовите его set_canonical и вставьте следующий код:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
<?php // Функция для добавления слеша в конец пути function addTrailingSlash2($path) { if (substr($path, -1) !== '/') { $path .= '/'; } return $path; } // Получение текущего домена с протоколом $currentDomain = (!empty($_SERVER['HTTPS']) ? 'https' : 'http') . '://' . $_SERVER['HTTP_HOST']; // Получение ID текущего ресурса $currentResourceId = $modx->resource->get('id'); // Получение объекта ресурса $resource = $modx->getObject('modResource', $currentResourceId); if (!$resource) { // Логирование ошибки, если ресурс не найден $modx->log(modX::LOG_LEVEL_ERROR, '[CanonicalSnippet] Resource not found for ID: ' . $currentResourceId); // Вывод стандартного canonical return '<link rel="canonical" href="' . $modx->makeUrl($currentResourceId, '', '', 'full') . '" />'; } // Получение значения TV-параметра $customCanonical = trim($resource->getTVValue('custom_canonical')); // Отладка: логируем значение TV $modx->log(modX::LOG_LEVEL_DEBUG, '[CanonicalSnippet] TV custom_canonical for resource ' . $currentResourceId . ': ' . ($customCanonical ?: 'empty')); // Обработка TV-поля if (!empty($customCanonical)) { // Извлекаем путь из TV (удаляем домен, если есть) $parsedUrl = parse_url($customCanonical); $path = isset($parsedUrl['path']) ? $parsedUrl['path'] : $customCanonical; // Удаляем начальный слеш, если он есть, чтобы избежать дублирования $path = ltrim($path, '/'); // Добавляем конечный слеш $path = addTrailingSlash2($path); // Формируем полный URL: текущий домен + путь из TV $canonicalUrl = $currentDomain . '/' . $path; // Проверяем, что URL валидный if (filter_var($canonicalUrl, FILTER_VALIDATE_URL)) { return '<link rel="canonical" href="' . htmlspecialchars($canonicalUrl, ENT_QUOTES, 'UTF-8') . '" />'; } else { // Логируем ошибку, если TV содержит невалидный URL $modx->log(modX::LOG_LEVEL_ERROR, '[CanonicalSnippet] Invalid URL in custom_canonical TV: ' . $customCanonical); } } // Если TV пустое или невалидное, используем стандартный URL ресурса return '<link rel="canonical" href="' . $modx->makeUrl($currentResourceId, '', '', 'full') . '" />'; ?> |
Логика кода построчно
- addTrailingSlash2() — вспомогательная функция, добавляющая завершающий слеш к пути, если его нет. Это нужно для единообразия canonical URL.
- $currentDomain — получаем текущий домен с протоколом (http или https) из серверных переменных. Canonical всегда будет содержать актуальный протокол.
- $modx->getObject(‘modResource’) — загружаем объект текущего ресурса MODX для доступа к его TV-параметрам.
- $resource->getTVValue(‘custom_canonical’) — читаем значение TV-поля. Если оно пустое — сниппет вернёт стандартный canonical, сгенерированный MODX.
- parse_url() — разбираем значение TV на составляющие. Это позволяет редакторам вводить как полный URL (
https://example.ru/path/), так и просто путь (/path/) — сниппет корректно обработает оба варианта. - filter_var(FILTER_VALIDATE_URL) — финальная проверка сформированного URL. Если URL невалиден — используется стандартный canonical MODX, а ошибка попадает в лог.
Шаг 3. Вызов сниппета в шаблоне
Разместите вызов сниппета в разделе <head> шаблона MODX между существующими мета-тегами:
|
1 |
[[!set_canonical]] |
Восклицательный знак означает некешируемый вызов. Это важно: если использовать кешируемый вариант ([[set_canonical]]), сниппет выполнится один раз при первом обращении и закешируется, что может привести к отображению неверного canonical на других страницах при горячем кеше.
Как использовать: примеры значений TV-поля
В поле custom_canonical редактор может вводить:
catalog/category/— путь без домена, сниппет добавит текущий домен автоматически.https://example.ru/catalog/category/— полный URL, домен будет заменён на текущий (из$_SERVER['HTTP_HOST'])./about/— путь с начальным слешем, сниппет корректно обработает и этот вариант.- Пустое поле — сниппет использует стандартный URL ресурса MODX.
Проверка работы canonical
После добавления сниппета в шаблон откройте любую страницу сайта в браузере и просмотрите исходный код (Ctrl+U). Найдите тег <link rel="canonical"> в разделе <head>. Убедитесь, что href содержит корректный URL. Для страниц без заполненного TV-поля canonical должен совпадать со стандартным URL ресурса. Для страниц с заполненным TV — отображаться указанный URL.
Советы по SEO: когда использовать custom canonical
- Используйте кастомный canonical для страниц пагинации — указывайте на первую страницу раздела.
- При миграции или редизайне сайта с изменением URL-структуры укажите canonical на новые адреса до настройки 301-редиректов.
- Для страниц с фильтрами (цвет, размер, цена) указывайте canonical на базовую страницу каталога без параметров.
- Не используйте canonical для перенаправления на принципиально другой контент — это не замена 301-редиректу, а подсказка для поисковиков о предпочтительной версии.
