Для вывода TV-изображения нужны три проверки: поле заполнено, путь ведёт к файлу, а подготовленный размер соответствует месту в макете. Разберём полный путь от создания TV до обложки, карточки и адаптивного srcset.
Загруженная фотография может быть шириной 4000 пикселей, а карточка в каталоге — всего 400. Если отправлять посетителю оригинал, браузер загрузит лишние данные. При этом простая обрезка подходит не всем изображениям: у схемы или скриншота важные детали могут оказаться у края.
Примеры рассчитаны на MODX Revolution с pdoTools, включённым Fenom и установленным pThumb. TV preview_img и чанки с учебными именами нужно создать. Документация компонента — в репозитории pThumb. Эти примеры не требуют пользовательских сниппетов.
Создайте TV и заполните поле
В разделе «Элементы» создайте TV preview_img с типом ввода «Изображение». Привяжите его к шаблону страницы, назначьте подходящий источник медиа, затем откройте ресурс и выберите файл. Тип ввода помогает редактору выбрать изображение, но сам по себе не задаёт разметку на странице.
В шаблоне текущего ресурса проверяйте значение перед открытием тега:
{if $_modx->resource.preview_img?}
<img src="{$_modx->resource.preview_img | escape}" alt="">
{/if}
Этот минимальный пример подходит, если значение TV уже является корректным URL. Проверка ? убирает пустой тег, но не выясняет, существует ли файл. Для окончательной версии понадобятся размер и атрибуты, которые разберём ниже.
Проверьте, что именно хранится в TV
У изображения могут быть разные формы значения. Посмотрите поле ресурса и настройки источника медиа, затем откройте итоговый адрес в браузере. Не добавляйте базовый путь, пока не знаете, содержится ли он в значении.
| Значение | Что проверить |
|---|---|
| /assets/images/photo.jpg | Путь от корня сайта: база уже указана |
| assets/images/photo.jpg | Относительный URL: результат зависит от base URL страницы |
| blog/photo.jpg | Возможно, путь относительно источника медиа: нужна его база |
| https://example.com/photo.jpg | Полный внешний URL: локальную базу добавлять не нужно |
Допустим, источник хранит файлы под /assets/images/, а TV возвращает только blog/photo.jpg. Тогда путь можно собрать явно:
{if $_modx->resource.preview_img?}
{set $src = '/assets/images/' ~ $_modx->resource.preview_img}
<img src="{$src | escape}" alt="">
{/if}
Этот фрагмент рассчитан именно на такой формат поля. Если база уже пришла вместе со значением, получится дубль. Не применяйте его к произвольной строке или внешнему адресу. При работе через pdoResources используйте подготовку TV и отдельно проверьте результат.
Получите производный файл через pThumb
Для фотографической обложки с пропорциями 3:2 запросим 960 × 640 пикселей. В этом примере значение TV уже содержит правильный путь:
{if $_modx->resource.preview_img?}
{set $src = $_modx->resource.preview_img | pthumb : 'w=960&h=640&zc=1&q=80'}
<img src="{$src | escape}" alt=""
width="960" height="640" loading="lazy">
{/if}
w и h задают целевой размер, zc=1 включает кадрирование, q задаёт качество для поддерживающих его форматов. Исходник должен подходить по размеру; проверьте фактический результат обработки. Оригинал остаётся исходником, а производные файлы можно использовать для разных мест в макете.
Вычисленный URL сохраняется в $src, а при выводе в HTML-атрибут экранируется. Если адрес пустой или файл не создан, смотрите исходный путь, доступность компонента, права на каталог кэша и журнал ошибок MODX.
Когда обрезать, а когда сохранить весь кадр
Кадрирование удобно для сетки фотографий: карточки сохраняют одинаковую высоту. Для скриншотов, схем и документов обрезка может убрать часть смысла. Когда весь кадр важен, начните с уменьшения только по ширине:
{if $_modx->resource.preview_img?}
{set $src = $_modx->resource.preview_img | pthumb : 'w=960&q=80'}
<img src="{$src | escape}"
alt="Схема подключения оборудования" loading="lazy">
{/if}
Высота такого файла зависит от пропорций оригинала. Не ставьте ему height="640" только потому, что это значение использовалось у соседней обложки. Для стабильного макета добавьте размеры по известным пропорциям или используйте подходящий контейнер, сохраняя весь кадр.
Две ширины для разных экранов
srcset перечисляет варианты файла, а sizes сообщает браузеру, сколько места изображение занимает в макете. В примере ниже картинка на узком экране занимает ширину окна, а на широком — 640 пикселей. Исходник должен быть не меньше 1280 пикселей по ширине.
{if $_modx->resource.preview_img?}
{set $small = $_modx->resource.preview_img | pthumb : 'w=640&q=80'}
{set $large = $_modx->resource.preview_img | pthumb : 'w=1280&q=80'}
<img src="{$small | escape}"
srcset="{$small | escape} 640w, {$large | escape} 1280w"
sizes="(max-width: 680px) 100vw, 640px"
alt="" loading="lazy">
{/if}
Дескрипторы 640w и 1280w должны совпадать с реальной шириной производных файлов. Для маленького оригинала нельзя просто объявить большую ширину в разметке. Подставьте sizes из своего макета: если есть боковые поля или две колонки, 100vw уже не описывает место точно.
Обложки в карточках pdoResources
В списке нужно запросить TV у выбранных ресурсов, а не брать поле открытого раздела. В шаблоне раздела:
{'pdoResources' | snippet : [
'parents' => $_modx->resource.id,
'depth' => 0,
'tpl' => 'wm-image-card',
'includeTVs' => 'preview_img',
'prepareTVs' => 1,
'tvPrefix' => '',
'limit' => 12
]}
Создайте чанк wm-image-card:
<article class="wm-image-card">
{if $preview_img?}
{set $src = $preview_img | pthumb : 'w=640&h=480&zc=1&q=80'}
<img src="{$src | escape}" alt=""
width="640" height="480" loading="lazy">
{/if}
<h2>
<a href="{$_modx->makeUrl($id) | escape}">
{$pagetitle | escape}
</a>
</h2>
</article>
includeTVs добавляет поле, prepareTVs подготавливает значение по типу TV, пустой tvPrefix позволяет обращаться к нему как к $preview_img. Согласуйте эти параметры с чанком и источником медиа. Все карточки не должны повторять обложку страницы каталога.
Alt, размеры и отложенная загрузка
Пустой alt подходит декоративной обложке рядом с названием материала. Если изображение передаёт информацию, напишите краткое описание: например, что показывает схема или какая ошибка видна на скриншоте. Имя файла и повтор ключевых слов обычно не помогают понять изображение.
width и height позволяют браузеру заранее учесть пропорции. Указывайте их по результату обработки. loading="lazy" подходит изображениям ниже первого экрана; главную видимую обложку обычно загружают сразу, поэтому этот атрибут для неё убирают.
Те же правила действуют для галерей, но набор изображений уже потребует повторяемых данных — например, MIGX с getImageList. Начать можно с раздела о MIGX.
Что проверить после сохранения
- Откройте страницу с обложкой и страницу без неё. Не должно быть пустого
img. - Откройте итоговый URL изображения отдельно. Проверьте HTTP-ответ, размеры, резкость и края кадра.
- Проверьте первый и повторный запрос: обработка не должна давать ошибку или ссылку на отсутствующий файл.
- На узком и широком экране посмотрите выбранный вариант
srcsetв инструментах браузера. - В списке из двух ресурсов убедитесь, что карточки получают разные обложки из своих TV.
- Посмотрите консоль и сетевые ошибки. Если файл не найден, сначала исправьте путь, затем разбирайтесь с обработкой.
Если поле есть в менеджере, но недоступно на странице, проверьте привязку TV к шаблону. Если изображение пропадает из-за условия, отдельно разберите проверку переменных.