Как сгенерировать картинки анонса из детальных изображений в 1С-Битрикс
В 1С-Битрикс у инфоблока есть настройка, которая позволяет создавать картинку анонса из детальной картинки. Обычно она находится в настройках инфоблока, в параметрах обработки изображений.
Однако на практике часто возникает ситуация: у части товаров или элементов каталога уже есть детальная картинка, но отсутствует картинка анонса. При этом простое повторное сохранение элемента в административной панели не всегда приводит к автоматическому созданию анонсного изображения.
В чем задача
Нужно пройти по элементам инфоблока и заполнить поле PREVIEW_PICTURE из поля DETAIL_PICTURE, но только для тех элементов, у которых картинка анонса отсутствует.
При этом важно не перегружать сервер. Если элементов много, нельзя запускать массовое обновление всех записей за один проход. Лучше обрабатывать элементы небольшими пачками, например по 20–50 штук.
Почему простое пересохранение элемента может не помочь
Настройка «создавать картинку анонса из детальной» обычно срабатывает при добавлении или изменении изображения. Если детальная картинка уже была загружена ранее, а элемент просто открыли и снова сохранили, Битрикс может не воспринимать это как новую загрузку файла.
Поэтому для уже существующих элементов надежнее использовать отдельный скрипт, который явно возьмет детальное изображение и передаст его в поле картинки анонса.
Что должен делать скрипт
Скрипт должен выполнять следующие действия:
- подключать ядро 1С-Битрикс;
- проверять, что пользователь является администратором;
- выбирать элементы нужного инфоблока;
- брать только элементы, у которых есть детальная картинка;
- брать только элементы, у которых нет картинки анонса;
- создавать картинку анонса из детальной картинки;
- обрабатывать элементы небольшими пачками;
- после каждого прохода автоматически запускать следующий шаг.
Важный момент про размер картинки анонса
Если в настройках инфоблока для картинки анонса указана максимальная ширина и высота, например 300 пикселей, нужно вызвать метод обновления элемента так, чтобы Битрикс применил настройки обработки изображений инфоблока.
Для этого в методе CIBlockElement::Update() используется пятый параметр со значением true:
$el->Update($item['ID'], $arFields, false, true, true);Именно этот параметр позволяет применить настройки обработки изображений, заданные в инфоблоке.
Готовый скрипт
Создайте файл, например:
/local/tools/fill_preview_from_detail.phpИ разместите в нем следующий код:
<?php
define('NO_KEEP_STATISTIC', true);
define('NOT_CHECK_PERMISSIONS', false);
require($_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/prolog_before.php');
global $USER;
if (!$USER->IsAdmin()) {
die('Access denied');
}
if (!CModule::IncludeModule('iblock')) {
die('IBlock module not installed');
}
/**
* Настройки
*/
$iblockId = 11; // ID инфоблока
$step = isset($_GET['step']) ? (int)$_GET['step'] : 30;
$run = isset($_GET['run']) && $_GET['run'] === 'Y';
if ($step <= 0) {
$step = 30;
}
if ($step > 100) {
$step = 100;
}
/**
* Считаем, сколько элементов осталось
*/
$totalLeft = CIBlockElement::GetList(
[],
[
'IBLOCK_ID' => $iblockId,
'!DETAIL_PICTURE' => false,
'PREVIEW_PICTURE' => false,
'CHECK_PERMISSIONS' => 'N',
],
[]
);
echo '<h2>Генерация картинок анонса из детальных</h2>';
echo '<p>Инфоблок ID: <b>' . $iblockId . '</b></p>';
echo '<p>Шаг: <b>' . $step . '</b> элементов</p>';
echo '<p>Осталось элементов без картинки анонса: <b>' . (int)$totalLeft . '</b></p>';
if (!$run) {
echo '<p><a href="?run=Y&step=' . $step . '">Запустить обработку</a></p>';
require($_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/epilog_after.php');
exit;
}
if ((int)$totalLeft <= 0) {
echo '<h3>Готово. Элементов для обработки больше нет.</h3>';
require($_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/epilog_after.php');
exit;
}
/**
* Берем только ближайшую пачку.
* Offset не нужен: после обновления элементы перестают попадать под фильтр PREVIEW_PICTURE = false.
*/
$rsElements = CIBlockElement::GetList(
['ID' => 'ASC'],
[
'IBLOCK_ID' => $iblockId,
'!DETAIL_PICTURE' => false,
'PREVIEW_PICTURE' => false,
'CHECK_PERMISSIONS' => 'N',
],
false,
['nTopCount' => $step],
[
'ID',
'IBLOCK_ID',
'NAME',
'DETAIL_PICTURE',
'PREVIEW_PICTURE',
]
);
$el = new CIBlockElement();
$processed = 0;
$updated = 0;
$errors = [];
echo '<hr>';
echo '<h3>Текущий проход</h3>';
echo '<ul>';
while ($item = $rsElements->Fetch()) {
$processed++;
$detailFile = CFile::GetFileArray($item['DETAIL_PICTURE']);
if (!$detailFile || empty($detailFile['SRC'])) {
$errors[] = 'ID ' . $item['ID'] . ': не найден файл DETAIL_PICTURE';
echo '<li>ID ' . $item['ID'] . ' — ошибка: не найден DETAIL_PICTURE</li>';
continue;
}
$sourcePath = $_SERVER['DOCUMENT_ROOT'] . $detailFile['SRC'];
if (!file_exists($sourcePath)) {
$errors[] = 'ID ' . $item['ID'] . ': файл не существует на диске: ' . $sourcePath;
echo '<li>ID ' . $item['ID'] . ' — ошибка: файл не существует</li>';
continue;
}
$fileArray = CFile::MakeFileArray($sourcePath);
if (!$fileArray || empty($fileArray['tmp_name'])) {
$errors[] = 'ID ' . $item['ID'] . ': не удалось подготовить файл через CFile::MakeFileArray';
echo '<li>ID ' . $item['ID'] . ' — ошибка подготовки файла</li>';
continue;
}
/**
* Важно:
* Пятый параметр true включает обработку картинок по настройкам инфоблока.
* Если в инфоблоке для PREVIEW_PICTURE задано максимум 300x300,
* Битрикс должен применить эти настройки при сохранении.
*/
$result = $el->Update(
$item['ID'],
[
'PREVIEW_PICTURE' => $fileArray,
],
false,
true,
true
);
if ($result) {
$updated++;
echo '<li>ID ' . $item['ID'] . ' — обновлено: ' . htmlspecialcharsbx($item['NAME']) . '</li>';
} else {
$errors[] = 'ID ' . $item['ID'] . ': ' . $el->LAST_ERROR;
echo '<li>ID ' . $item['ID'] . ' — ошибка: ' . htmlspecialcharsbx($el->LAST_ERROR) . '</li>';
}
}
echo '</ul>';
echo '<hr>';
echo '<p>Обработано в этом проходе: <b>' . $processed . '</b></p>';
echo '<p>Успешно обновлено: <b>' . $updated . '</b></p>';
if (!empty($errors)) {
echo '<h3>Ошибки</h3>';
echo '<pre>';
print_r($errors);
echo '</pre>';
}
/**
* Считаем остаток после прохода
*/
$totalLeftAfter = CIBlockElement::GetList(
[],
[
'IBLOCK_ID' => $iblockId,
'!DETAIL_PICTURE' => false,
'PREVIEW_PICTURE' => false,
'CHECK_PERMISSIONS' => 'N',
],
[]
);
echo '<p>Осталось после прохода: <b>' . (int)$totalLeftAfter . '</b></p>';
if ((int)$totalLeftAfter > 0) {
$nextUrl = '?run=Y&step=' . $step;
echo '<p>Следующий проход запустится автоматически.</p>';
echo '<p><a href="' . $nextUrl . '">Запустить следующий проход вручную</a></p>';
echo '<script>
setTimeout(function() {
window.location.href = "' . $nextUrl . '";
}, 1500);
</script>';
} else {
echo '<h3>Готово. Все элементы обработаны.</h3>';
}
require($_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/epilog_after.php');Как запустить скрипт
После размещения файла откройте его в браузере:
https://site.ru/local/tools/fill_preview_from_detail.phpПри необходимости можно указать размер шага:
https://site.ru/local/tools/fill_preview_from_detail.php?step=20Затем нажмите ссылку «Запустить обработку». Скрипт начнет обрабатывать элементы небольшими партиями и автоматически переходить к следующему проходу.
Какие элементы будут обработаны
Скрипт обрабатывает элементы по следующему фильтру:
[
'IBLOCK_ID' => $iblockId,
'!DETAIL_PICTURE' => false,
'PREVIEW_PICTURE' => false,
'CHECK_PERMISSIONS' => 'N',
]Это означает, что будут выбраны элементы, у которых:
- принадлежность к нужному инфоблоку;
- есть детальная картинка;
- нет картинки анонса.
Важно: в данном варианте скрипт обрабатывает как активные, так и неактивные элементы. Если нужно обрабатывать только активные элементы, в фильтр следует добавить условие:
'ACTIVE' => 'Y',Как обрабатывать только активные элементы
Если нужно генерировать картинки анонса только для активных элементов, фильтр должен выглядеть так:
[
'IBLOCK_ID' => $iblockId,
'ACTIVE' => 'Y',
'!DETAIL_PICTURE' => false,
'PREVIEW_PICTURE' => false,
'CHECK_PERMISSIONS' => 'N',
]Такой фильтр исключит из обработки неактивные товары или элементы каталога.
Почему скрипт не использует offset
В скрипте не используется смещение выборки. Это сделано специально.
После успешного обновления элемента у него появляется картинка анонса. Значит, он больше не попадает под условие PREVIEW_PICTURE = false. Поэтому на следующем проходе скрипт снова берет первую пачку элементов, у которых анонсной картинки еще нет.
Безопасность
В скрипте есть проверка:
if (!$USER->IsAdmin()) {
die('Access denied');
}Это означает, что запустить обработку сможет только администратор сайта.
Тем не менее после завершения работы файл лучше удалить с сервера или закрыть к нему доступ. Такие технические скрипты не стоит оставлять в открытом доступе.
Итог
Если в каталоге 1С-Битрикс есть элементы с детальными картинками, но без картинок анонса, их можно заполнить автоматически. Для этого достаточно пройти по элементам инфоблока, выбрать только те, у которых отсутствует PREVIEW_PICTURE, и записать в это поле файл из DETAIL_PICTURE.
Пошаговая обработка помогает не перегружать сервер, а параметр true в методе CIBlockElement::Update() позволяет применить настройки инфоблока для обработки изображений, включая ограничение размера картинки анонса.


