Создадим инфоблок фотогалерий
Итак, у меня установлено коробочное решение, «Мебельная компания» на основе редакции «Старт», на момент написания статьи, версия ядра 18.1.5. Создаём инфоблок со следующими основными настройками:
Как видите настройки шаблонов URL адресов нам не нужны, оставляем название, символьный код и привязку к сайту. Так же обратите внимание что свойства инфоблока хранятся в отдельной таблице.
Во вкладке «Доступ» устанавливаем «Чтение» для всех пользователей, чтобы наши фотографии могли видеть все посетители сайта просматривающие новость с фотогалереей. Затем добавляем единственное свойство «Фотографии».
Свойство должно быть множественным т.к. фотографий в галерее у нас может быть сколько угодно, а так же обязательным к заполнению (мы ведь не можем выводить пустую фотогалерею).
В дополнительных настройках свойства «Фотографии» необходимо отметить флажок «Выводить поле для описания значения», это нужно для того, чтобы контент-менеджер мог описать загружаемое изображение и позже пользователь мог видеть это описание при просмотре галереи. Та же я рекомендую ограничить тип загружаемых файлов, будем позволять грузить только изображение, защита от дурака так сказать. Инфоблок готов к использованию.
Давайте создадим тестовый элемент галереи для одной из существующих новостей и закинем несколько фотографий найденных в Google по запросу «выставка мебели», у меня получилось следующее:
Если кто-то не знает как задать описание фотографии, щёлкните по значку карандаша под фото и во всплывающем окне заполните поле «Описание» вот так:
Можно готовить компонент галереи.
Готовим шаблон компонента фото-галереи
Т.к. наша галерея основана на инфоблоке, самым очевидным компонентом для её показа будет обычная детальная страница новости т.е. bitrix:news.detail. Создадим тестовый раздел и разместим там компонент bitrix:news.detail, компонент необходимо настроить на работу с только что созданным инфоблоком «Фотогалерея», отключить все параметры устанавливающие заголовки и описания страницы, отключить показ всевозможных доп.свойств типа дата изменения элемента, детальное описание и т.п.
В свойстве «ID новости» можно сразу указать ID тестовой галереи, в моём случае это 33, это нужно для удобства настройки шаблона. В параметрах компонента в поле «Свойства», свойство MORE_PHOTO нужно указать вручную, его не будет в списке доступных свойств инфоблока т.к. это свойство типа «Файл»:
Обязательно отключите режим Ajax в параметрах компонента!Базовые настройки сделаны, можно сохранять и копировать шаблон компонента для последующей кастомизации. Я скопировал шаблон компонента bitrix:news.detail в дефолтный шаблон сайт и назвал его gallary, вам советую сделать так же чтобы не запутаться в дальнейшем:
В качестве плагина для фотогалереи я предлагаю использовать всем хорошо знакомый Fancybox, который можно скачать с официального сайта http://fancyapps.com/fancybox/3/ в последней версии этот плагин предоставляет очень симпатичное оформление фотогалереи прямо из коробки.
Что необходимо подключить:
- последнюю стабильную минифицированную версию JQuery
- сам плагин jquery.fancybox.min.js
- стили jquery.fancybox.min.css
Подключаем, файлы я предварительно раскидал по папкам css и js внутри папки шаблон /bitrix/templates/furniture_gray/
<?
//Где-то вначале
use Bitrix\Main\Page\Asset;
//и в блоке header
//Подключаем и выводим CSS
Asset::getInstance()->addCss(SITE_TEMPLATE_PATH. '/css/jquery.fancybox.min.css' );
//Подключаем пользовательские и выводим стандартные js скрипты
Asset::getInstance()->addJs(SITE_TEMPLATE_PATH."/js/jquery-3.2.1.min.js");
Asset::getInstance()->addJs(SITE_TEMPLATE_PATH."/js/jquery.fancybox.min.js");
Теперь необходимо настроить сам шаблон. Идём в папку с шаблоном, у меня это /bitrix/templates/.default/components/bitrix/news.detail/gallary/ , здесь необходимо создать файл result_modifier.php в котором предварительно подготовить картинки к показу в галереи.
<? if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) die();
//Предварительно готовим картинки
if($arResult['PROPERTIES']['MORE_PHOTO']['VALUE']){
$photos = [];
foreach ($arResult['PROPERTIES']['MORE_PHOTO']['VALUE'] as $key => $photoId) {
$arPhoto = CFile::ResizeImageGet($photoId, ["width" => 150, "height" => 150], BX_RESIZE_IMAGE_EXACT, true, false, false, 100);
$arPhotoBig = CFile::ResizeImageGet($photoId, ["width" => 800, "height" => 600], BX_RESIZE_IMAGE_PROPORTIONAL, true, false, false, 100);
$photos[] = ['SRC'=>$arPhoto['src'], 'SRC_BIG' => $arPhotoBig['src'], 'ALT'=>$arResult['PROPERTIES']['MORE_PHOTO']['DESCRIPTION'][$key]];
}
//И сохраняем в кеш только нужные данные
$arResult['GALLARY_PHOTOS'] = $photos;
$this->__component->SetResultCacheKeys(['GALLARY_PHOTOS']);
}
Всегда используйте конструкцию $this->__component->SetResultCacheKeys([‘CUSTOM_PROPERTY_KEY’]); для кеширования данных в result_modifier.php, так вы будете хранить в кеше строго-ограниченные данные, не переполняя его, чем сэкономите память и повысите быстродействие сайта.И сам шаблон template.php:
<?if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true)die();
$this->setFrameMode(true);
if($arResult['GALLARY_PHOTOS']) { //А есть ли вообще картинки?>
<div class="gallary">
<? foreach ($arResult['GALLARY_PHOTOS'] as $key => $photo) { ?>
<div class="gallary_item">
<a href="<?=$photo['SRC_BIG'];?>" class="fancybox" data-fancybox="images" data-caption="<?=$photo['ALT'];?>" >
<img src="<?=$photo['SRC'];?>" alt="<?=$photo['ALT'];?>">
</a>
</div>
<? } ?>
</div>
<? } ?>
Если вы всё подключили правильно галерея уже начнёт работать. Давайте добавим немного красоты путём стилизации наших классов gallary и gallary_item и изображений внутри. Для универсальности предлагаю использовать файл стилей компонента галереи. Пропишем следующий стиль:.gallary {
display: flex;
flex-direction: row;
justify-content: space-between;
}
.gallary_item {
overflow: hidden;
position: relative;
}
.gallary_item img {
width: 100%;
height: auto;
max-width: 100%;
display:block;
-webkit-transition:all 0.2s ease-out;
-moz-transition:all 0.2s ease-out;
-o-transition:all 0.2s ease-out;
-ms-transition:all 0.2s ease-out;
transition:all 0.2s ease-out;
}
.gallary_item:hover img {
-webkit-transform:scale(1.1);
-moz-transform:scale(1.1);
-o-transform:scale(1.1);
-ms-transform:scale(1.1);
transform:scale(1.1);
}
Получается примерно такой эффект:Внешний вид галереи после применения стилей. В реальности эффект более плавныйНу что же, компонент готов, теперь можно заняться его вставкой в детальный текст элемента инфоблока, например новостной статьи.
Вставка галереи в тело статьи
Для начала нам нужно кастомизировать компонент news.detail новостного раздела, не важно отдельный это компонент или входит в состав комплексного. Нам потребуется отредактировать файл result_modifier.php, template.php и component_epilog.php, начнём с result_modifier.php.
Первым делом скопируйте шаблон компонента на основе которого сделан раздел новостей, в моём случае это комплексный компонент bitrix:news, копируем шаблон компонента в дефолтный шаблон сайта, я назвал его news_block. Далее идём в папку компонент news.detail, т.е. /bitrix/templates/.default/components/bitrix/news/news_block/bitrix/news.detail/.default/ и создаём файлыresult_modifier.php иcomponent_epilog.php. В result_modifier.php необходимо добавить следующий код для кеширования шаблона.
<? if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true)die();
//Кешируем данные после обновления буфера шаблона
$this->__component->SetResultCacheKeys(array("CACHED_TPL")); ?>
В файл component_epilog.php нужно вставить специальную конструкцию, которая будет искать в теле статьи «хеш-тег» #GALLARY_ID_123# где 123 — идентификатор галереи (элемента инфоблока) и подгружать на его место компонент галереи (который мы ранее настроили) с переданным в него ID-шником 123. Весь код выглядит так:
<?if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true)die();
//Заменяем хеш-тег GALLARY_ID на компонент
echo preg_replace_callback(
"/#GALLARY_ID_([\d]+)#/is".BX_UTF_PCRE_MODIFIER,
create_function('$matches', 'ob_start();
$GLOBALS["APPLICATION"]->IncludeComponent("bitrix:news.detail", "gallary", Array(
"ACTIVE_DATE_FORMAT" => "d.m.Y",
"ADD_ELEMENT_CHAIN" => "N",
"ADD_SECTIONS_CHAIN" => "N",
"AJAX_MODE" => "N",
"AJAX_OPTION_ADDITIONAL" => "",
"AJAX_OPTION_HISTORY" => "N",
"AJAX_OPTION_JUMP" => "N",
"AJAX_OPTION_STYLE" => "N",
"BROWSER_TITLE" => "-",
"CACHE_GROUPS" => "N",
"CACHE_TIME" => "36000000",
"CACHE_TYPE" => "A",
"CHECK_DATES" => "N",
"DETAIL_URL" => "",
"DISPLAY_BOTTOM_PAGER" => "N",
"DISPLAY_DATE" => "N",
"DISPLAY_NAME" => "N",
"DISPLAY_PICTURE" => "N",
"DISPLAY_PREVIEW_TEXT" => "N",
"DISPLAY_TOP_PAGER" => "N",
"ELEMENT_CODE" => "",
"ELEMENT_ID" => $matches[1], // ID галереи найденный в теге #GALLARY_ID_xxx#
"FIELD_CODE" => array(
0 => "",
1 => "",
),
"IBLOCK_ID" => "5", //Код инфоблока галери
"IBLOCK_TYPE" => "news", //Тип инфоблока
"IBLOCK_URL" => "",
"INCLUDE_IBLOCK_INTO_CHAIN" => "N",
"MESSAGE_404" => "",
"META_DESCRIPTION" => "-",
"META_KEYWORDS" => "-",
"PAGER_BASE_LINK_ENABLE" => "N",
"PAGER_SHOW_ALL" => "N",
"PAGER_TEMPLATE" => ".default",
"PAGER_TITLE" => "Страница",
"PROPERTY_CODE" => array( // Свойства
0 => "",
1 => "MORE_PHOTO",
2 => "",
),
"SET_BROWSER_TITLE" => "N",
"SET_CANONICAL_URL" => "N",
"SET_LAST_MODIFIED" => "N",
"SET_META_DESCRIPTION" => "N",
"SET_META_KEYWORDS" => "N",
"SET_STATUS_404" => "N",
"SET_TITLE" => "N",
"SHOW_404" => "N",
"STRICT_SECTION_CHECK" => "N",
"USE_PERMISSIONS" => "N",
"USE_SHARE" => "N",
),
false
);
$retrunStr = @ob_get_contents();
ob_get_clean();
return $retrunStr;'),
$arResult["CACHED_TPL"]);
?>
Обратите внимание что вместо привычного $APPLICATION использовано $GLOBALS[«APPLICATION»], это нужно для видимости объекта внутри временной функции. Так же обратите внимание на $matches[1] это динамический параметр передаваемый в параметры вызова компонента news.detail, в нём содержится ID галереи.Осталось поправить файл шаблона template.php, на второй сточке, сразу после проверки обращения к файлу пишем код:
<? ob_start(); ?>
а в конце кода пишем:
<?
$this->__component->arResult["CACHED_TPL"] = @ob_get_contents();
ob_get_clean();
?>
Манипуляции с component_epilog.php сделаны чтобы обойти кеширование. Как вы уже поняли весь этот «финт» основан на манипуляции буфера вывода.
Вместо заключения
Теперь ваш контент-менеджер может без труда вставлять фото-галереи прямо в тело статьи и ему не нужно разбираться в вёрстке и стилях. Порядок действия теперь такой:
- Создание галереи в инфоблоке галерей, после сохранения менеджер запоминает ID элемента инфоблока ( в моём случае это ID 33)
- В нужном месте детального описания новости (инфоблок новости) необходимо вставить следующий код #GALLARY_ID_33#
Вставка галереи в тело статьи в форме редактирования элемента инфоблока. И вот результат:
Я думаю не надо объяснять что так можно вставлять что угодно, слайдеры, формы опроса, товарные предложения и т.д. Желаю удачи!
Огромное спасибо!
Супер! Спасибо большое автору, все получилось (хотя и не с первого раза) и прекрасно работает! Не заострено внимание на том, что в файле "component_epilog.php" нужно поменять на свои значения тип инфоблока ("IBLOCK_TYPE" => "news", //Тип инфоблока ) и код инфоблока галереи ("IBLOCK_ID" => "5", //Код инфоблока галери"), ну и сложные компоненты иногда не так разложены по подпапкам, как тут описано, но все-таки разобраться можно. ЕЩЕ РАЗ ОГРОМНАЯ БЛАГОДАРНОСТЬ!
Рад был помочь! Спасибо за обратную связь! Учту эти моменты и допишу в статью.
Спасибо за решение! А как быть если таким образом нужно вывести не 1 а 2 разных компонента, например?
Здравствуйте. Нужно будет добавить ещё один "хеш-тег" и вызов preg_replace_callback() в component_epilog.php
Добрый день, спасибо за Ваше решение. Но попробовал сделать 2 хэштега разных в одном описании, ничего не вышло //Заменяем хеш-тег GALLARY_ID на компонент
В итоге контент страницы вывелся два раза, в первом заменился один хэш тег, во второй за второй хэш-тег, как их обьединить в один кэш
Вам нужно сохранять результат работы preg_replace_callback() в переменную. Например так:
не особо понял, куда девать код компонетов, вот полный код что написал я по Вашим мотивам $ploshadka = function($matches) { ob_start(); $GLOBALS["APPLICATION"]->IncludeComponent( "bitrix:news.detail", "short_gallery", Array( "ACTIVE_DATE_FORMAT" => "d.m.Y", "ADD_ELEMENT_CHAIN" => "N", "ADD_SECTIONS_CHAIN" => "N", "AJAX_MODE" => "N", "AJAX_OPTION_ADDITIONAL" => "", "AJAX_OPTION_HISTORY" => "N", "AJAX_OPTION_JUMP" => "N", "AJAX_OPTION_STYLE" => "N", "BROWSER_TITLE" => "-", "CACHE_GROUPS" => "Y", "CACHE_TIME" => "3600", "CACHE_TYPE" => "A", "CHECK_DATES" => "Y", "DETAIL_URL" => "", "DISPLAY_BOTTOM_PAGER" => "N", "DISPLAY_DATE" => "N", "DISPLAY_NAME" => "N", "DISPLAY_PICTURE" => "N", "DISPLAY_PREVIEW_TEXT" => "N", "DISPLAY_TOP_PAGER" => "N", "ELEMENT_CODE" => "", "ELEMENT_ID" => $matches[1], "FIELD_CODE" => array("","", "FILE_404" => "", "GROUP_PERMISSIONS" => array("2", "IBLOCK_ID" => "28", "IBLOCK_TYPE" => "vbf_production_content", "IBLOCK_URL" => "", "INCLUDE_IBLOCK_INTO_CHAIN" => "N", "MESSAGE_404" => "", "META_DESCRIPTION" => "-", "META_KEYWORDS" => "-", "PAGER_BASE_LINK" => "", "PAGER_BASE_LINK_ENABLE" => "N", "PAGER_PARAMS_NAME" => "arrPager", "PAGER_SHOW_ALL" => "N", "PAGER_TEMPLATE" => "", "PAGER_TITLE" => "Страница", "PROPERTY_CODE" => array("","MORE_PHOTO","", "SET_BROWSER_TITLE" => "N", "SET_CANONICAL_URL" => "N", "SET_LAST_MODIFIED" => "N", "SET_META_DESCRIPTION" => "N", "SET_META_KEYWORDS" => "N", "SET_STATUS_404" => "N", "SET_TITLE" => "N", "SHARE_HANDLERS" => array("delicious", "SHARE_HIDE" => "N", "SHARE_SHORTEN_URL_KEY" => "", "SHARE_SHORTEN_URL_LOGIN" => "", "SHARE_TEMPLATE" => "", "SHOW_404" => "N", "STRICT_SECTION_CHECK" => "N", "USE_PERMISSIONS" => "Y", "USE_SHARE" => "N" ), false ); $retrunStr = @ob_get_contents(); ob_get_clean(); return $retrunStr; }; $ploshadka_f = function($matches_f) { ob_start(); $GLOBALS["APPLICATION"]->IncludeComponent( "bitrix:news.detail", "short_faq", Array( "ACTIVE_DATE_FORMAT" => "d.m.Y", "ADD_ELEMENT_CHAIN" => "N", "ADD_SECTIONS_CHAIN" => "N", "AJAX_MODE" => "N", "AJAX_OPTION_ADDITIONAL" => "", "AJAX_OPTION_HISTORY" => "N", "AJAX_OPTION_JUMP" => "N", "AJAX_OPTION_STYLE" => "N", "BROWSER_TITLE" => "-", "CACHE_GROUPS" => "Y", "CACHE_TIME" => "3600", "CACHE_TYPE" => "A", "CHECK_DATES" => "Y", "DETAIL_URL" => "", "DISPLAY_BOTTOM_PAGER" => "N", "DISPLAY_DATE" => "N", "DISPLAY_NAME" => "N", "DISPLAY_PICTURE" => "N", "DISPLAY_PREVIEW_TEXT" => "N", "DISPLAY_TOP_PAGER" => "N", "ELEMENT_CODE" => "", "ELEMENT_ID" => $matches_f[1], "FIELD_CODE" => array("","", "FILE_404" => "", "GROUP_PERMISSIONS" => array("2", "IBLOCK_ID" => "14", "IBLOCK_TYPE" => "vbf_production_content", "IBLOCK_URL" => "", "INCLUDE_IBLOCK_INTO_CHAIN" => "N", "MESSAGE_404" => "", "META_DESCRIPTION" => "-", "META_KEYWORDS" => "-", "PAGER_BASE_LINK" => "", "PAGER_BASE_LINK_ENABLE" => "N", "PAGER_PARAMS_NAME" => "arrPager", "PAGER_SHOW_ALL" => "N", "PAGER_TEMPLATE" => "", "PAGER_TITLE" => "Страница", "PROPERTY_CODE" => array("","MORE_PHOTO","", "SET_BROWSER_TITLE" => "N", "SET_CANONICAL_URL" => "N", "SET_LAST_MODIFIED" => "N", "SET_META_DESCRIPTION" => "N", "SET_META_KEYWORDS" => "N", "SET_STATUS_404" => "N", "SET_TITLE" => "N", "SHARE_HANDLERS" => array("delicious", "SHARE_HIDE" => "N", "SHARE_SHORTEN_URL_KEY" => "", "SHARE_SHORTEN_URL_LOGIN" => "", "SHARE_TEMPLATE" => "", "SHOW_404" => "N", "STRICT_SECTION_CHECK" => "N", "USE_PERMISSIONS" => "Y", "USE_SHARE" => "N" ), false ); $retrunStr = @ob_get_contents(); ob_get_clean(); return $retrunStr; }; //Заменяем хеш-тег GALLARY_ID на компонент echo preg_replace_callback( "/#GALLARY_ID_([\d]+)#/is".BX_UTF_PCRE_MODIFIER,$ploshadka,$arResult["CACHED_TPL"]); echo preg_replace_callback( "/#FAQ_ID_([\d]+)#/is".BX_UTF_PCRE_MODIFIER,$ploshadka_f,$arResult["CACHED_TPL"]);
Сделайте проще. Заранее вызовите компонент и воспользуйтесь функциями буферизации вывода. Сохраните результат работы компонента в переменную
$text;
а дальше воспользуйтесь моим примером. Т.е.:далее заменяете в полученном от компонент HTML (он будет лежать в
$text
) всё что вам нужно при помощиpreg_replace_callback();
и в концеecho $text;
Тут можно подробнее прочитать про буфер вывода https://www.php.net/manual/ru/book.outcontrol.php