1С Bitrix

Добавление OG разместик
og:title и og:description из meta title и meta description 
 global $APPLICATION;

$APPLICATION->AddHeadString('<meta property="og:title" content="' . $arResult["IPROPERTY_VALUES"]["ELEMENT_META_TITLE"] . '" />');
$APPLICATION->AddHeadString('<meta property="og:description" content="' . $arResult["IPROPERTY_VALUES"]["ELEMENT_META_DESCRIPTION"] . '" />');
$APPLICATION->AddHeadString('<meta property="og:image" content="' . $arResult["PREVIEW_PICTURE"]["SRC"] . '" />');

Преобразование pdf в jpeg
$file = $_SERVER['DOCUMENT_ROOT'].CFile::GetPath($arResult["PROPERTIES"]["_2D_SCHEME"]["VALUE"][0]);
$image = new Imagick();
$image->setResolution(300,300);
$image->setBackgroundColor('white');
$image->readImage($file);
$image->setGravity(Imagick::GRAVITY_CENTER);
$image->setOption('pdf:fit-to-page',true);
$image->setImageFormat('jpeg');
$image->setImageCompression(imagick::COMPRESSION_JPEG);
$image->setImageCompressionQuality(40);
$image->scaleImage(1200,1200, true);
$image->mergeImageLayers(Imagick::LAYERMETHOD_FLATTEN);
$image->writeImage($_SERVER['DOCUMENT_ROOT'].'/include/'.$arResult["NAME"].'.jpeg');
$pathImage = str_replace("/var/www/u0876248/data/www/new.allfresco.ru/", "/", $image->getImageFilename());

Шпаргалка по работе с highload-инфоблоками
Подготовка к работе 
 Для работы с highload-ами, нужно подключить подключить модуль highloadblock к сущности highload: 
 // подключаем пространство имен класса HighloadBlockTable и даём ему псевдоним HLBT для удобной работы 
use Bitrix\Highloadblock\HighloadBlockTable as HLBT; 

// ID highloadblock'a

const EXP_HL_BLOCK_ID = 1; 

//подключаем модуль highloadblock 
CModule::IncludeModule('highloadblock'); 

//Функция получения экземпляра класса: 
function GetEntityDataClass($iHlBlockId) { 
 if (empty($iHlBlockId) || $iHlBlockId < 1)
 {
 return false;
 }
 $hlblock = HLBT::getById($iHlBlockId)->fetch(); 
 $entity = HLBT::compileEntity($hlblock);
 $entity_data_class = $entity->getDataClass();
 return $entity_data_class;
}
 
 Данная функция получает сущность хайлоадов для дальнейшей работы. 
 Получение названий полей 
 use Bitrix\Highloadblock\HighloadBlockTable as HLBT;
const EXP_HL_BLOCK_ID = 1;
CModule::IncludeModule('highloadblock');
$hlblock = HLBT::getById(EXP_HL_BLOCK_ID)->fetch();
$entity = HLBT::compileEntity($hlblock);
var_dump($entity->getFields());
 
 Получаем массив, где ключи это поля highload-блока, а значения — объекты, соответствующие типу поля (строка — Bitrix\Main\Entity\StringField , число — Bitrix\Main\Entity\IntegerField ). Тип можно получить следующим образом(ID имя поля): 
 var_dump(get_class($entity->getFields()['ID']));
 
 Получить элементы highload-инфоблока 
 const MY_HL_BLOCK_ID = 1;

CModule::IncludeModule('highloadblock');

$entity_data_class = GetEntityDataClass(MY_HL_BLOCK_ID);
$rsData = $entity_data_class::getList(array(
 'select' => array('*')
));

while($el = $rsData->fetch()){
 print_r($el);
}
 
 Количество элементов highload-инфоблока 
 const EXP_HL_BLOCK_ID = 1;
CModule::IncludeModule('highloadblock');
$entity_data_class = GetEntityDataClass(EXP_HL_BLOCK_ID);
var_dump($entity_data_class::getCount());
 
 Добавить новый элемент в highload-инфоблок 
 const EXP_HL_BLOCK_ID = 1;

CModule::IncludeModule('highloadblock');

$entity_data_class = GetEntityDataClass(EXP_HL_BLOCK_ID);

$result = $entity_data_class::add(array(
 'UF_NAME' => 'Желтый',
 'UF_CODE' => 'YELLOW',
 'UF_VALUE' => '#ffff00',
 'UF_ACTIVE' => '1'
 ));
 
 Удалить новый элемент в highload-инфоблок 
 const EXP_HL_BLOCK_ID = 1;

CModule::IncludeModule('highloadblock');

$id = 9;
$entity_data_class = GetEntityDataClass(EXP_HL_BLOCK_ID);
$result = $entity_data_class::delete($id);
 
 Обновить новый элемент в highload-инфоблок 
 const EXP_HL_BLOCK_ID = 1;

CModule::IncludeModule('highloadblock');

$id = 10;
$entity_data_class = GetEntityDataClass(MY_HL_BLOCK_ID);
$result = $entity_data_class::update($id, array(
 'UF_NAME' => 'Фиолетовый',
 'UF_CODE' => 'PURPLE',
 'UF_VALUE' => '#5A009D',
 'UF_ACTIVE' => '1'
));
 
 В качестве дополнения, рекомендую ознакомиться с оффициальной документацией здесь и здесь 
 Источник

Обновление доступного кол-ва у товара
$arFields = Array(
 "PRODUCT_ID" => $product_id[$key], 
 "STORE_ID" => $data['2'], 
 "AMOUNT" => 100
);
CCatalogStoreProduct::UpdateFromForm($arFields);

Обновление стоимости товара
$product_id = [0, 0, 47, 45, 46, 158, 136, 137, 140, 51, 42];

if (($handle = fopen("price.csv", "r")) !== FALSE) {
 $i = 1;

 while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
 foreach ($data as $key => $value) {
 if ($key <= 2){ continue; }
 echo '<b>ID_PRICE:</b> '.$data['0'].' || <b>CURRENT:</b> '.$data['1'].' || <b>ID_PRODUCT:</b> '.$product_id[$key].' || <b>PRICE:</b> '.$value;
 echo '<br>';
 $arFields = Array( "PRODUCT_ID" => $product_id[$key], "CATALOG_GROUP_ID" => $data['0'], "PRICE" => $value, "CURRENCY" => $data['1']);
 $res = CPrice::GetList(
 array(),
 array(
 "PRODUCT_ID" => $product_id[$key],
 "CATALOG_GROUP_ID" => $data['0'],
 )
 );
 if ($arr = $res->Fetch()) {
 CPrice::Update($arr["ID"], $arFields);
 echo '<b>Цена обновлена</b>';
 } else {
 CPrice::Add($arFields);
 echo '<b>Цена добавлена</b>';
 }
 echo '<br>';

 }

 $i++;
 echo '<br><br><br>';
 }
}
 
 $product_id = [0, 0, 76, 77, 78, 79, 80, 129, 130, 114, 115];

if (($handle = fopen("price-1.csv", "r")) !== FALSE) {
 $i = 1;

 while (($data = fgetcsv($handle, 1000, ";")) !== FALSE) {
 foreach ($data as $key => $value) {
 if ($key <= 1){ continue; }
 echo '<b>ID_PRICE:</b> '.$data['0'].' || <b>CURRENT:</b> '.$data['1'].' || <b>ID_PRODUCT:</b> '.$product_id[$key].' || <b>PRICE:</b> '.$value;
 echo '<br>';

 $arFields = Array( "PRODUCT_ID" => $product_id[$key], "CATALOG_GROUP_ID" => $data['0'], "PRICE" => $value, "CURRENCY" => $data['1']);
 $res = CPrice::GetList(
 array(),
 array(
 "PRODUCT_ID" => $product_id[$key],
 "CATALOG_GROUP_ID" => $data['0'],
 )
 );
 if ($arr = $res->Fetch()) {
 CPrice::Update($arr["ID"], $arFields);
 echo '<b>Цена обновлена</b>';
 } else {
 CPrice::Add($arFields);
 echo '<b>Цена добавлена</b>';
 }
 echo '<br>';

 }

 $i++;
 echo '<br><br><br>';
 }
}

Информация необходимая для регистрации ключа Bitrix
Полное юридическое название компании-владельца продукта или ФИО частного владельца 
 
 
 Список адресов, включая тестовые, по которым будет доступна данная копия продукта "1С-Битрикс: Управление сайтом" 
 
 
 Телефон владельца данной копии продукта (с указанием кода города) 
 
 
 E-mail владельца для связи по вопросам лицензирования и использования программного продукта 
 
 
 Контактное лицо, ответственное за использование данной копии программного продукта 
 
 
 E-mail контактного лица 
 
 
 Телефон контактного лица 
 
 
 Прочая контактная информация

Определение города
Определить город по IP 
 static function getCity($ip = ""){
 if($ip){
 return \Bitrix\Main\Service\GeoIp\Manager::getCityName($ip,'ru');
 }else{
 return \Bitrix\Main\Service\GeoIp\Manager::getCityName(\Bitrix\Main\Service\GeoIp\Manager::getRealIp(),'ru');
 }
 }
 
 Получаем IP 
 function getUserIp(){
 return \Bitrix\Main\Service\GeoIp\Manager::getRealIp();
}
 
 Геокодирование адреса 
 function askYandex($address){
 $params = array(
 'geocode' => $address, // адрес
 'format' => 'json', // формат ответа
 'results' => 1, // количество выводимых результатов
 'apikey' => 'cd351fdb-0d22-4dd6-a6e5-a400114e552c', // ваш api key
 );
 $response = json_decode(file_get_contents('https://geocode-maps.yandex.ru/1.x/?' . http_build_query($params, '', '&')));
 if ($response->response->GeoObjectCollection->metaDataProperty->GeocoderResponseMetaData->found > 0)
 {
 $pos = $response->response->GeoObjectCollection->featureMember[0]->GeoObject->Point->pos;

 $arrCoords = explode(' ', $pos);
 return ['lat' => $arrCoords[1], 'lng' => $arrCoords[0]];
 }
 else
 {
 return 'Ничего не найдено';
 }
}
 
 Геокодирование адреса 
 function getListAddr($address){
 $params = array(
 'geocode' => $address, // адрес
 'format' => 'json', // формат ответа
 'results' => 5, // количество выводимых результатов
 'apikey' => 'cd351fdb-0d22-4dd6-a6e5-a400114e552c', // ваш api key
 );
 $response = json_decode(file_get_contents('http://geocode-maps.yandex.ru/1.x/?' . http_build_query($params, '', '&')));

 if ($response->response->GeoObjectCollection->metaDataProperty->GeocoderResponseMetaData->found > 0)
 {
 $arResult = [];
 foreach($response->response->GeoObjectCollection->featureMember as $k => $data){
 $arResult[$k]['name'] = $data->GeoObject->name;
 $arResult[$k]['street'] = $data->GeoObject->metaDataProperty->GeocoderMetaData->Address->Components[4]->name;
 $arResult[$k]['house'] = $data->GeoObject->metaDataProperty->GeocoderMetaData->Address->Components[5]->name;
 }
 return $arResult;
 }
 else
 {
 return 'Ничего не найдено';
 }
}

Создание типов цен и складов
if(CModule::IncludeModule("catalog")){

 if (($handle = fopen("partner.csv", "r")) !== FALSE) {
 while (($data = fgetcsv($handle, 1000, ";")) !== FALSE) {
 $rsCity = CIBlockElement::GetList(Array(), Array("IBLOCK_ID" => 14, "NAME" => $data['1']), false, Array(), Array("ID", "NAME", "DATE_ACTIVE_FROM"));
 while($arCity = $rsCity->GetNextElement()) {
 $arFieldsCity = $arCity->GetFields();
 }

 if ($arFieldsCity['ID']):
 $trans = Cutil::translit($data['2'], "ru", array("replace_space" => "-", "replace_other" => "-"));

 $arFieldsPrice = array(
 "NAME" => $trans,
 "SORT" => 100,
 "USER_GROUP" => array(1, 2),
 "USER_GROUP_BUY" => array(1,2),
 "USER_LANG" => array(
 "ru" => $data['2'],
 "en" => $data['2']
 )
 );

 $ID_PRICE = CCatalogGroup::Add($arFieldsPrice);

 if ($ID_PRICE){
 echo $ID_PRICE.'Тип цены для дилера: '.$data['2'].'<br>';
 }

 $arFieldsWarehouse = Array(
 "TITLE" => $data['2'],
 "ACTIVE" => "Y",
 "ADDRESS" => $data['7'],
 );

 $ID_WAREHOUSE = CCatalogStore::Add($arFieldsWarehouse);

 if($ID_WAREHOUSE) {
 echo 'Склад создан для дилера:'.$data['2'].'<br><br>';
 }

 CIBlockElement::SetPropertyValueCode($arFieldsCity['ID'], "ID_PRICE", $ID_PRICE);
 CIBlockElement::SetPropertyValueCode($arFieldsCity['ID'], "ID_WAREHOUSE", $ID_WAREHOUSE);
 endif;
 }
 }
}

Создание превьюшки из PDF и запись картинки в PREVIEW_PICTURE на лету по событию создания элемента
// проверить включено ли расширение Imagick (зайти через putty, в меню битрикс env, и там 8 -> 2 -> 7).
AddEventHandler("iblock", "OnAfterIBlockElementAdd", Array("Preview_PDF", "OnAfterIBlockElementAddHandler")); // вызываем функцию при событии "после добавления элемента в инфоблок

class Preview_PDF{

 // создаем обработчик события "OnAfterIBlockElementAdd"
 function OnAfterIBlockElementAddHandler(&$arFields){
 if(CModule::IncludeModule("iblock")) // подключаем модуль для работы с инфоблоком
 {
 $arFile = ''; // создаем переменную в которой будет записан путь к файлу
 $res = CIBlockElement::GetProperty($arFields["IBLOCK_ID"], $arFields["ID"], array("sort" => "asc"), Array("CODE"=>"FILE"));
 if ($ob = $res->GetNext()){
 $arFile = CFile::GetFileArray($ob['VALUE']); // получаем массив данных по файлу
 }
 }
 //генерация превью
 $pdf = $_SERVER["DOCUMENT_ROOT"].$arFile['SRC'];
 $image = new Imagick($pdf.'[0]');
 $image->setImageFormat( "jpg" );
 $image->writeImage($_SERVER["DOCUMENT_ROOT"]. "/include/picture/".str_replace('pdf', 'jpg', $arFile["ORIGINAL_NAME"]));

 // запись превью в массив arFields
 $el = new CIBlockElement;
 $arLoadProductArray = Array(
 "PREVIEW_PICTURE" => CFile::MakeFileArray($_SERVER["DOCUMENT_ROOT"]. "/include/picture/".str_replace('pdf', 'jpg', $arFile["ORIGINAL_NAME"]))
 );
 $res = $el->Update($arFields["ID"], $arLoadProductArray);

 }
}

Получить SEO данные элемента и секции Bitrix
Задача: Получить данные из вкладки SEO админ панели Битрикс 
 Не всегда получается решить задачу базовыми компонентами, однако оставить пользователям возможность устанавливать свои мета теги, через стандартный интерфейс необходимо. 
 Чтобы вытянуть данные из полей, которые находятся во вкладке SEO битрикс, используем следующий код: 
 Для элементов: 
 $ipropElementValues = new \\Bitrix\\Iblock\\InheritedProperty\\ElementValues($arParams['IBLOCK_ID'],$element['ID']);
$pageProperties = $ipropElementValues->getValues();

$APPLICATION->SetTitle($pageProperties['ELEMENT_PAGE_TITLE']);
$APPLICATION->SetPageProperty('title',$pageProperties['ELEMENT_META_TITLE']);
$APPLICATION->SetPageProperty('description',$pageProperties['ELEMENT_META_DESCRIPTION']);
 
 Для секций: 
 $ipropValues = new \\Bitrix\\Iblock\\InheritedProperty\\SectionValues($arParams['IBLOCK_ID'], $arParams['SECTION_ID']);
$IPROPERTY = $ipropValues->getValues();
 
 Конечно, не забываем про то,что необходимо подключить необходимый класс. 
 use Bitrix\\Iblock\\InheritedProperty\\ElementValues; 
 или 
 Bitrix\\Iblock\\InheritedProperty\\SectionValues 
 В остальном проблем быть не должно.

Оптимизация сайта для PageSpeed Insights
Оптимизация сайта для PageSpeed Insights 
 Задача 
 Провести оптимизацию выдачи контента Битрикс, контроль качества оптимизации провести при помощи PageSpeed Insights. 
 Решение 
 Инструменты для проверки скорости 
 
 https://developers.google.com/speed/pagespeed/insights/?hl=ru 
 https://tools.pingdom.com/ https://tools.pingdom.com 
 
 Сервисы оптимизации изображений 
 
 https://compressor.io/compress 
 https://tinypng.com/ 
 http://optimizilla.com/ru/ 
 
 Общие рекомендации 
 
 Привести в соответствие изображения, таким образом, что бы браузеру не приходилось их масштабировать 
 Включить сжатие файлов в nginx 
 При помощи настроек битрикс перенести js и css в конец страницы 
 Минифицировать js и css при помощи gulp или иными средствами 
 Исключить служебные скрипты и стили битрикс из формирования пользовательских страниц сайта 
 Минифицировать html 
 
 https://github.com/addyosmani/critical-path-css-tools 
 Перенос js и css в конец страницы 
 JS 
 Для корректной работы битрикс с файлами стилей и скриптов их нужно подключать при помощи функций Битрикс: 
 $asset = \\Bitrix\\Main\\Page\\Asset::getInstance();

// подключение стилей 
$asset->addCss(SITE_TEMPLATE_PATH."/some.css");

// подключение скриптов
$asset->addJs(SITE_TEMPLATE_PATH."/some.js");

// подключение произвольных кусков кода
$asset->addString('<link rel="canonical" href="https://' . $_SERVER['HTTP_HOST'] . $APPLICATION->GetCurPage(false) . '" />');
 
 Для объединения всех стилей и скриптов в единый файл нужно в настройках Битрикс Настройки -> Настройки продукта -> Настройки модулей -> Главный модуль активировать галки Объединять CSS файлы и Объединять JS файлы 
 Так же можно проставить галки Создавать сжатую копию объединенных CSS и JS файлов и Переместить весь Javascript в конец страницы 
 Программно опцию "Переместить весь Javascript в конец страницы" можно активировать так: 
 $asset->setJsToBody(true);
 
 В случае программной активации галочка в админке работать не будет, т.е. скрипты всегда будут помещаться в конец страницы. 
 Не все скрипты нужно помещать в футер. например tagManager от гугла должен быть вверху. Для исключения скрипта из переносимых нужно добавить атрибут data-skip-moving=true в тег script. Пример: 
 <script data-skip-moving="true">
 // your script code
</script>
 
 CSS 
 Для переноса CSS в конец страницы у Битрикса нет стандартных средств, но т.к. за вывод css отвечает отдельный метод, то мы можем вывести его в footer.php самостоятельно. 
 Для этого нужно вместо: 
 <?php $APPLICATION->ShowHead(); ?>
 
 В файле header.php добавить: 
 // вместо $APPLICATION->ShowHead();
$bXhtmlStyle = true;
echo '<meta http-equiv="Content-Type" content="text/html; charset='.LANG_CHARSET.'"'.($bXhtmlStyle? ' /':'').'>'."\\n";
$APPLICATION->ShowMeta("robots", false, $bXhtmlStyle);
$APPLICATION->ShowMeta("keywords", false, $bXhtmlStyle);
$APPLICATION->ShowMeta("description", false, $bXhtmlStyle);
$APPLICATION->ShowLink("canonical", null, $bXhtmlStyle);
$APPLICATION->ShowHeadStrings();
$APPLICATION->ShowHeadScripts();
 
 В файле footer.php добавить: 
 $APPLICATION->ShowCSS(true, $bXhtmlStyle);
 
 Исключить служебные скрипты и стили битрикс из формирования пользовательских страниц сайта 
 Для этого нужно добавить обработку контента страницы перед выдачей его из буфера браузеру. 
 В init.php должно быть добавлено подключение файлов констант, обработчиков и функций, т.к. все действия уже будем совершать с ними. 
 Пример подключения файлов в init.php: 
 if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true) die();

// Подключение констант
if (file_exists($_SERVER["DOCUMENT_ROOT"]."/local/php_interface/include/constants.php")) {
 require_once($_SERVER["DOCUMENT_ROOT"] . "/local/php_interface/include/constants.php");
}

// Подключение обработчиков событий
if (file_exists($_SERVER["DOCUMENT_ROOT"]."/local/php_interface/include/handlers.php")) {
 require_once($_SERVER["DOCUMENT_ROOT"] . "/local/php_interface/include/handlers.php");
}

// Подключение глобальных функций (чаще всего используется для переноса кода сторонних разработчиков
// при получении проекта на доработку)
if (file_exists($_SERVER["DOCUMENT_ROOT"]."/local/php_interface/include/functions.php")) {
 require_once($_SERVER["DOCUMENT_ROOT"] . "/local/php_interface/include/functions.php");
}
 
 В файл functions.php добавим функции обработчиков событий: 
 <?
// удяляем скрипты ядра при отдаче сайта пользователям
function deleteKernelJs(&$content) {
 global $USER, $APPLICATION;
 if((is_object($USER) && $USER->IsAuthorized()) || strpos($APPLICATION->GetCurDir(), "/bitrix/")!==false) return;
 if($APPLICATION->GetProperty("save_kernel") == "Y") return;

 $arPatternsToRemove = Array(
 '/<script.+?src=".+?kernel_main\\/kernel_main\\.js\\?\\d+"><\\/script\\>/',
 '/<script.+?src=".+?bitrix\\/js\\/main\\/core\\/core[^"]+"><\\/script\\>/',
 '/<script.+?>BX\\.(setCSSList|setJSList)\\(\\[.+?\\]\\).*?<\\/script>/',
 '/<script.+?>if\\(\\!window\\.BX\\)window\\.BX.+?<\\/script>/',
 '/<script[^>]+?>\\(window\\.BX\\|\\|top\\.BX\\)\\.message[^<]+<\\/script>/',
 );

 $content = preg_replace($arPatternsToRemove, "", $content);
 $content = preg_replace("/\\n{2,}/", "\\n\\n", $content);
}

// удяляем css ядра при отдаче сайта пользователям
function deleteKernelCss(&$content) {
 global $USER, $APPLICATION;
 if((is_object($USER) && $USER->IsAuthorized()) || strpos($APPLICATION->GetCurDir(), "/bitrix/")!==false) return;
 if($APPLICATION->GetProperty("save_kernel") == "Y") return;

 $arPatternsToRemove = Array(
 '/<link.+?href=".+?kernel_main\\/kernel_main\\.css\\?\\d+"[^>]+>/',
 '/<link.+?href=".+?bitrix\\/js\\/main\\/core\\/css\\/core[^"]+"[^>]+>/',
 '/<link.+?href=".+?bitrix\\/templates\\/[\\w\\d_-]+\\/styles.css[^"]+"[^>]+>/',
 '/<link.+?href=".+?bitrix\\/templates\\/[\\w\\d_-]+\\/template_styles.css[^"]+"[^>]+>/',
 );

 $content = preg_replace($arPatternsToRemove, "", $content);
 $content = preg_replace("/\\n{2,}/", "\\n\\n", $content);
}
 
 В файл handlers.php добавим обработку событий: 
 <?php if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true) die();

$eventManager = \\Bitrix\\Main\\EventManager::getInstance();

// удяляем скрипты ядра при отдаче сайта пользователям
$eventManager->addEventHandler("main", "OnEndBufferContent", "deleteKernelJs");

// удяляем css ядра при отдаче сайта пользователям
$eventManager->addEventHandler("main", "OnEndBufferContent", "deleteKernelCss");
 
 Источник - https://gdecider.github.io/articles-bx-site-optimisation-for-google-pagespeed-insights.html

Пример формирование YML фида
require_once($_SERVER['DOCUMENT_ROOT']. "/bitrix/modules/main/include/prolog_before.php");
header("Content-Type: text/xml");
header("Expires: Thu, 19 Feb 1998 13:24:18 GMT");
header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT");
header("Cache-Control: no-cache, must-revalidate");
header("Cache-Control: post-check=0,pre-check=0");
header("Cache-Control: max-age=0");
header("Pragma: no-cache");

$IBLOCK_ID = 26;

// получения всех сайтов
$rsSites = CSite::GetList($by="sort", $order="desc", ['ACTIVE' => 'Y']);

// Исключить характеристики
$specificationsArr = array(
 'Рейтинг для микроразметки',
 'Картинки',
 'Похожие товары по фильтру',
 'Аксессуары по фильтру',
 'Товары комплекта',
 'Видео (код из Youtube)',
 'Сертификаты',
 'ID поста блога для комментариев',
 'Регион'
);

// https://site.com/bitrix/admin/cat_group_admin.php?lang=ru
// Розничная цена МСК - 1
// Розничная цена Ростов-на-Дону - 7
// Розничная цена Краснодар - 10
// Розничная цена СПБ - 16
// Розничная цена Новосибирск - 19
// Розничная цена Казань - 13

$text = '<yml_catalog date="'.date('Y-m-d H:i:s').'">';
while ($arSite = $rsSites->Fetch()){

 // site.com
 // spb.site.com
 // rostov.site.com
 // krasnodar.site.com

 if (empty($arSite['SITE_URL'])) {
 $arSite['SITE_URL'] = 'https://site.com';
 }

 if ($arSite['SITE_URL'] == 'https://site.com' OR $arSite['SITE_URL'] == 'https://spb.site.com' OR $arSite['SITE_URL'] == 'https://rostov.site.com' OR $arSite['SITE_URL'] == 'https://krasnodar.site.com' ) {

 $category_query = CIBlockSection::GetList( Array('name' => 'asc'), Array('IBLOCK_ID' => $IBLOCK_ID, 'ACTIVE' => 'Y') );
 $product_query = CIBlockElement::GetList( array("ID" => "ASC"), array("IBLOCK_ID" => $IBLOCK_ID, "ACTIVE"=>"Y"), false, Array(), array("ID", "IBLOCK_ID", "IBLOCK_SECTION_ID", "NAME", "DETAIL_TEXT", "DETAIL_PICTURE","DETAIL_PAGE_URL", "DATE_ACTIVE_FROM", "PROPERTY_*") );

 if ($arSite['SITE_URL'] == 'https://site.com' ) {
 $PRICE_TYPE_ID = 1;
 } elseif ($arSite['SITE_URL'] == 'https://novosibirsk.site.com'){
 $PRICE_TYPE_ID = 19;
 } elseif ($arSite['SITE_URL'] == 'https://rostov.site.com'){
 $PRICE_TYPE_ID = 7;
 } elseif ($arSite['SITE_URL'] == 'https://krasnodar.site.com'){
 $PRICE_TYPE_ID = 10;
 } elseif ($arSite['SITE_URL'] == 'https://kazan.site.com'){
 $PRICE_TYPE_ID = 13;
 } elseif ($arSite['SITE_URL'] == 'https://spb.site.com'){
 $PRICE_TYPE_ID = 16;
 }

 $text .= '<shop>';
 $text .= '<name>'.$arSite['NAME'].'</name>';
 $text .= '<company>КНАУФ Инсулейшн</company>';
 $text .= '<url>'.$arSite['SITE_URL'].'</url>';
 $text .= '<platform>BSM/Yandex/Market</platform>';
 $text .= '<version>2.3.4</version>';
 $text .= '<cpa>1</cpa>';
 $text .= '<currencies><currency id="RUR" rate="1"/></currencies>';

 $text .= '<categories>';
 while ($category = $category_query->GetNext()) {
 $text .= '<category id="'.$category['ID'].'">'.$category['NAME'].'</category>';
 }
 $text .= '</categories>';
 $text .= '<enable_auto_discounts>true</enable_auto_discounts>';
 $text .= '<offers>';

 while($product = $product_query->GetNextElement()){ 
 $productArFields = $product->GetFields(); 
 $productArProps = $product->GetProperties();

 // Определяем цену 
 $price_qury = CPrice::GetList(array(), array( "PRODUCT_ID" => $productArFields['ID'], "CATALOG_GROUP_ID" => $PRICE_TYPE_ID ));

 if ($price = $price_qury->Fetch()) {
 // Определяем категорию к которой относиться товар
 $category = CIBlockSection::GetByID($productArFields['IBLOCK_SECTION_ID']);
 $category_ID = $category->GetNext();

 $text .= '<offer id="'.$productArFields['ID'].'" available="true">';
 $text .= '<url>'.$arSite['SITE_URL'].$productArFields['DETAIL_PAGE_URL'].'</url>';
 $text .= '<price>'.substr($price["PRICE"], 0, -3).'</price>';
 $text .= '<currencyId>RUR</currencyId>';
 $text .= '<categoryId>'.$category_ID['ID'].'</categoryId>';

 $text .= '<picture>'.$arSite['SITE_URL'].CFile::GetPath($productArFields['DETAIL_PICTURE']).'</picture>';

 foreach($productArProps['MORE_PHOTO']['VALUE'] as $picture){
 $text .= '<picture>'.$arSite['SITE_URL'].CFile::GetPath($picture).'</picture>';
 }

 $text .= '<name>'.$productArFields['NAME'].'</name>';
 $text .= '<description><![CDATA['.$productArFields['DETAIL_TEXT'].']]></description>';

 foreach($productArProps as $specifications){
 if ($specifications['VALUE'] AND !in_array($specifications['NAME'], $specificationsArr)){

 if ($specifications['NAME'] == "Материал"){
 $text .= '<param name="'.$specifications['NAME'].'">'.$specifications['VALUE'][0].'</param>';
 } elseif ($specifications['NAME'] == "Преимущества") {
 $text .= '<param name="'.$specifications['NAME'].'"><![CDATA['.$specifications['VALUE']['TEXT'].']]></param>';
 } else {
 $text .= '<param name="'.$specifications['NAME'].'">'.$specifications['VALUE'].'</param>';
 }

 }
 }

 $text .= '</offer>';
 }
 // break;
 }

 $text .= '</offers>';
 $text .= '</shop>';
 // break;
 // die();
}
}

$text .= '</yml_catalog>';

echo $text;

Водяные знаки на фото
$arWaterMark = Array(
	array(
		"name" => "watermark",
		"position" => "bottomright", // Положение
		"type" => "image",
		"size" => "real",
		"file" => $_SERVER["DOCUMENT_ROOT"].'/upload/watermark.png', // Путь к картинке
		"fill" => "exact",
	)
);

$PreviewPict = CFile::ResizeImageGet($arItem["PREVIEW_PICTURE"]["ID"], ['width'=>200, 'height'=>200], BX_RESIZE_IMAGE_PROPORTIONAL, true, $arWaterMark, false, 80);

echo CFile::ShowImage($PreviewPict["src"], 200, 200, "id='".$arItemIDs['PICT']."' alt='".$arResult["NAME"]."' itemprop='image' class='catalogLuster' title='".$arResult["NAME"]."' ", "", false);
 
 $arFilters = array(
 array(
 "name" => "watermark", 
 "position" => "bc", // (доступные варианты tl|tc|tr|ml|mc|mr|bl|bc|br или topleft|topcenter|topright|centerleft|center|centerright|bottomleft|bottomcenter|bottomright) 
 "type" => "image", // (доступные варианты "image|text")
 "size" => "real", // ( доступные варианты big|medium|small|real; real доступен только для type=image )
 "coefficient" => "1", // ( альтернатива параметру size. В случае текстового варианта - от 1 до 7, по крайней мере так в исходниках; для картинок 0.1 до 1 )
 "fill" => "exact", // ( доступные варианты exact|resize|repeat )
 "file" => $_SERVER["DOCUMENT_ROOT"]."/watermark.png", // (абсолютный путь до картинки с водяным знаком)
 "text" => "Водяной знак!", // ( текст водяного знака )
 "color" => "ff0000", // ( hex формат цвета текста )
 "font" => $_SERVER["DOCUMENT_ROOT"]."/arial.ttf", // ( путь до файла шрифта в формате .ttf )
 "use_copyright" => "Y" // ( использовать ли знак копирайта перед текстом )
 )
 );

Настройка редиректов .htaccess
<IfModule mod_rewrite.c>
	Options +FollowSymLinks
	RewriteEngine On
		
	# редирект на www
	RewriteCond %{HTTP_HOST} ^site\.ru
	RewriteRule ^(.*)$ https://www.site.ru/$1 [R=302,L]

 # редирект с index.php на site.ru
 RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /index\.php\ HTTP/
 RewriteRule ^index\.php$ https://polymertx.ru/ [R=301,L]

	# редиректы на https
	RewriteCond %{SERVER_PORT} ^80$ [OR]
	RewriteCond %{HTTP} =on
 RewriteCond %{HTTP_HOST} ^www.site\.ru
	RewriteRule ^(.*)$ https://www.site.ru/$1 [R=302,L]
	

	# редирект с /test/index.php на /test/
	RewriteCond %{REQUEST_URI} !^/bitrix/
	RewriteCond %{REQUEST_METHOD} =GET
	RewriteCond %{REQUEST_URI} ^(.*)/index\.php$
	RewriteRule ^(.*)$ %1/ [R=302,L]

	# редирект с /test на /test/
	RewriteCond %{REQUEST_URI} !^/bitrix/
	RewriteCond %{REQUEST_URI} (.*/[^/.]+)($|\?)
	RewriteRule .* %1/ [R=302,L]

	# редирект с /test/// на /test/, а также с /test1///test2/ на /test1/test2/
	RewriteCond %{REQUEST_URI} !^/bitrix/
	RewriteCond %{REQUEST_URI} ^(.*?)/{2,}?(.*?)$
	RewriteRule .* %1/%2 [R=302,L]
	RewriteCond %{REQUEST_URI} !^/bitrix/
	RewriteCond %{THE_REQUEST} //
	RewriteCond %{QUERY_STRING} !http(s|)://
	RewriteRule .* /$0 [R=302,L]
	
	
	# "родное" правило битрикса
	RewriteCond %{REQUEST_FILENAME} !-f
	RewriteCond %{REQUEST_FILENAME} !-l
	RewriteCond %{REQUEST_FILENAME} !-d
	RewriteCond %{REQUEST_FILENAME} !/bitrix/urlrewrite.php$
	RewriteRule ^(.*)$ /bitrix/urlrewrite.php [L]
	RewriteRule .* - [E=REMOTE_USER:%{HTTP:Authorization}]
# RewriteRule ^robots.txt$ robots.php [L,QSA]
</IfModule>

<IfModule mod_rewrite.c>
	Options +FollowSymLinks
	RewriteEngine on
	
	# Редирект c www и с http #
	RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
	
	RewriteRule ^(.*)$ https://%1/$1 [L,R=301]
	RewriteCond %{HTTP:X-Forwarded-Proto} !https [NC]
	RewriteRule .* https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
	
	# Редирект со слеша в конце #
	RewriteCond %{THE_REQUEST} //
	RewriteRule .* https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
	RewriteCond %{REQUEST_FILENAME} !-f
	RewriteCond %{REQUEST_FILENAME} !-l
	RewriteCond %{REQUEST_FILENAME} !-d
	RewriteCond %{REQUEST_FILENAME} !/bitrix/urlrewrite.php$
	RewriteRule ^(.*)$ /bitrix/urlrewrite.php [L]
	RewriteRule .* - [E=REMOTE_USER:%{HTTP:Authorization}]
	
	Redirect 301 /index.html https://bonolit.ru/
</IfModule>

############################################################################
#### Cтандартный .htaccess для проектов студии Клондайк, версия 2.4 ####
############################################################################
RewriteEngine On # Директива включает редиректы.
RewriteBase / # Без директивы (.*) = /$1 будет /var/wwww/site/web/$1 с директивой = /$1

Options +FollowSymLinks # Разрешает переход по символическим ссылкам.

############################################################################
#### Перенаправляем протокол https на http ####
############################################################################
RewriteCond %{HTTPS} on # Проверяем наличие https в URL.
RewriteRule ^.*$ http://%{SERVER_NAME}%{REQUEST_URI} # Перенаправляем протокол на http.

############################################################################
#### Выбор основного зеркала (или с www или без www) ####
############################################################################
# 1. Редирект с www на без www. (раскоментировать директивы пункта 1)
#RewriteCond %{HTTP_HOST} ^www\.(.*) [NC]

# Проверяем, содержит ли домен www (в начале URL).
#RewriteRule ^(.*)$ http://%1/$1 [R=301,L]

# Перенаправляем URL на домен без www.
####
# 2. Редирект без www на www. (раскоментировать директивы пункта 2)
#RewriteCond %{HTTP_HOST} !^www\.(.*) [NC] # Проверяем, не содержит ли домен www (в начале URL).
#RewriteRule ^(.*)$ http://www.%{HTTP_HOST}/$1 [R=301,L] # Перенаправляем URL на домен c www.

############################################################################
#### Убираем повторяющиеся слеши (/) в URL ####
############################################################################
RewriteCond %{THE_REQUEST} //
 # Проверяем, повторяется ли слеш (//) более двух раз.
RewriteRule .* /$0 [R=301,L]
 # Исключаем все лишние слеши.

############################################################################
#### Убираем слеши в конце URL для статических файлов (содержит точку) ####
############################################################################
RewriteCond %{REQUEST_URI} \..+$ 
 # Если файл содержит точку.
RewriteCond %{REQUEST_FILENAME} !-d 
 # И это не директория.
RewriteCond %{REQUEST_FILENAME} -f
 # Является файлом.
RewriteCond %{REQUEST_URI} ^(.+)/$ 
 # И в конце URL есть слеш.
RewriteRule ^(.+)/$ /$1 [R=301,L] 
 # Исключить слеш.

############################################################################
#### Добавляем слеш(/), если его нет, и это не файл. ####
############################################################################
RewriteCond %{REQUEST_URI} !(.*)/$
 # Если слеша в конце нет.
RewriteCond %{REQUEST_FILENAME} !-f
 # Не является файлом.
RewriteCond %{REQUEST_URI} !\..+$
 # В URL нет точки (файл).
RewriteRule ^(.*)$ $1/ [L,R=301]
 # Добавляем слеш в конце.

############################################################################
#### Убираем index.php, если он есть в конце URL ####
############################################################################
RewriteCond %{REQUEST_METHOD} =GET
 # Выявляем GET запрос в URL (не POST).
RewriteCond %{REQUEST_URI} ^(.*)/index\.php$
 # URL cодержит index.php в конце.
RewriteRule ^(.*)$ %1/ [R=301,L]
 # Удалить index.php из URL.

############################################################################
#### Компрессия статического контента для гугл спид тест ####
############################################################################
<IfModule mod_deflate.c>
 # Compress HTML, CSS, JavaScript, Text, XML and fonts
 AddOutputFilterByType DEFLATE application/rss+xml
 AddOutputFilterByType DEFLATE application/vnd.ms-fontobject
 AddOutputFilterByType DEFLATE application/x-font
 AddOutputFilterByType DEFLATE application/x-font-opentype
 AddOutputFilterByType DEFLATE application/x-font-otf
 AddOutputFilterByType DEFLATE application/x-font-truetype
 AddOutputFilterByType DEFLATE application/x-font-ttf
 AddOutputFilterByType DEFLATE application/x-javascript
 AddOutputFilterByType DEFLATE application/xhtml+xml
 AddOutputFilterByType DEFLATE application/xml
 AddOutputFilterByType DEFLATE font/opentype
 AddOutputFilterByType DEFLATE font/otf
 AddOutputFilterByType DEFLATE font/ttf
 AddOutputFilterByType DEFLATE image/svg+xml
 AddOutputFilterByType DEFLATE image/x-icon
 AddOutputFilterByType DEFLATE text/css
 AddOutputFilterByType DEFLATE text/html
 AddOutputFilterByType DEFLATE text/javascript
 AddOutputFilterByType DEFLATE text/plain
 AddOutputFilterByType DEFLATE text/xml
 AddOutputFilterByType DEFLATE image/svg+xml
</IfModule>
<IfModule mod_expires.c>
 ExpiresActive on
 ExpiresByType image/jpeg "access plus 3 day"
 ExpiresByType image/svg "access plus 3 day"
 ExpiresByType image/gif "access plus 3 day"
 ExpiresByType image/png "access plus 3 day"
 ExpiresByType text/javascript "access plus 3 day"
 ExpiresByType text/css "access plus 3 day"
 ExpiresByType application/javascript "access plus 3 day"
</IfModule>
############################################################################
#### Конец общей части, далее следует собственные директивы .htaccess ####
############################################################################

Битрикс как проверить, что письма были отправлены
Частая проблема письма с сайта не доходят и не всегда понятно, проблема в сайте, хостинге, промежуточных сервисах или даже конечном ящике получателя. В данной заметке расскажу как можно проверить, что письма ушли из Битрикса. 
 Отправка писем, попадет в журнал событий Битрикса. Хранятся все события в таблице bevent, посмотреть значения можно через Настройки - Производительность - Таблицы ( /bitrix/admin/perfmon_table.php?lang=ru&table_name=b_event ) 
 Для событий отправки писем нужно смотреть на поле SUCCESS_EXEC Возможные статусы: 
 
 
 SUCCESS_EXEC = Y — сообщение отправлено. 
 
 
 SUCCESS_EXEC = N — не обработано событие (а значит не отправлено) 
 
 
 SUCCESS_EXEC = 0 — не найден шаблон (указан не верный шаблон) 
 
 
 SUCCESS_EXEC = F — надо смотреть логи отправки сервера или хостинга. 
 
 
 Основное на что стоит обратить внимание, что SUCCESS_EXEC = N не значит, что письмо вообще не оправлено, это текущий статус, и если отправка настроена на cron (по расписанию) или на хиты, то нужно подождать перед тем, как проверять статус!

Прикреплять файла к письму (Веб-формы)
$eventManager = \Bitrix\Main\EventManager::getInstance();
 
$eventManager->addEventHandler("main", "OnBeforeEventAdd", array("MailEventHandler", "onBeforeEventAddHandler"));
class MailEventHandler{
 
 static function onBeforeEventAddHandler(&$event, &$lid, &$arFields, &$message_id, &$files){
 // Названия типов почтовых событий и идентификаторы почтовых шаблонов, по которым будет проходить фильтрация при отлавливании события
 $events = array('FORM_FILLING_resume');
 $messageIds = array('37');

 if (in_array($event, $events) && in_array($message_id, $messageIds)){
 // Определяем массив прикрепляемых к письму идентификаторов файлов, если не задан
 if (!is_array($files)){
 $files = [];
 }
 // Перебираем поля письма
 foreach ($arFields as $field){
 // Если находим ссылку на файл, передаем ее дальше
 if ($link = self::getLinkFromField($field)){
 // Если получаем идентификатор файла, сохраняем его в массив идентификаторов файлов письма
 if ($fileID = self::getFileFromLink($link)){
 $files[] = $fileID;
 }
 }
 }
 }
 }
 
 // Метод возвращает ссылку на файл
 private static function getLinkFromField($field){
 preg_match("/(http\:.*form_show_file.*action\=download)/", $field, $out);
 // Если поле соответствует маске пути к файлу, возвращаем путь
 return ($out[1] ?: false);
 }
 // Метод возвращает идентификатор файла
 private static function getFileFromLink($link){
 // Создаем новый объект, в который записываем ссылку
 $uri = new \Bitrix\Main\Web\Uri($link);
 // Разбираем строку URI и создаем массив из параметров запроса
 parse_str($uri->getQuery(), $query);
 // Метод возвращает массив свойств файла по идентификатору результата веб-формы и хэшу
 $arFile = CFormResult::GetFileByHash($query["rid"], $query["hash"]);
 // Возвращаем идентификатор файла
 return $arFile['FILE_ID'];
 }
}

База

Вывод всех элементов раздела Bitrix
$arSelect = Array("ID", "IBLOCK_ID", "NAME", "PREVIEW_PICTURE", "CODE","PROPERTY_*");
$arFilter = Array(
 "IBLOCK_ID" => 6, // id инфоблока
 "ACTIVE" => "Y", // активность
 "SECTION_ID" => 12, // нужная секция
);

$res = CIBlockElement::GetList(Array("SORT" => "ASC"), $arFilter, false, Array(), $arSelect); 
while($ob = $res->GetNextElement()){ 
 $arFields = $ob->GetFields(); 
 $arProps = $ob->GetProperties(); 
}

Вывод разделов и элементов в bitrix:news.list
Часто возникает необходимость вывести разделы инфоблока с элементами на одной странице. Для этой цели подойдет связка catalog.sections + news.list. Или можно обойтись одним bitrix:news.list, немного кастомизировав шаблон компонента. Пойдем вторым путем. 
 Итак. 
 
 
 Размещаем компонент bitrix:news.list на целевой странице. 
 
 
 Копируем шаблон компонента в текущий шаблон сайта. 
 
 
 Создаем в нем файл result_modifier.php с таким содержимым. 
 
 
 // Получаем все активные разделы ИБ
$rsSections = CIBlockSection::GetList(
 Array("SORT" => "ASC"),
 Array(
 "=IBLOCK_ID" => $arParams["IBLOCK_ID"],
 "=ACTIVE" => "Y"
 )
);

// Собираем разделы в массив
while ($arSection = $rsSections->GetNext())
 $arSections[] = $arSection;

// Фильтруем элементы по принадлежности к разделу
// Получаем итоговый массив со структурой: [SECTION] => [ELEMENTS]
foreach ($arSections as $arSection){
 foreach ($arResult["ITEMS"] as $arItem){
 if ($arItem["IBLOCK_SECTION_ID"] == $arSection["ID"])
 $arSection["ELEMENTS"][] = $arItem;
 }
 $arElementGroups[] = $arSection;
}

$arResult["ITEMS"] = $arElementGroups;
 
 В итоге получаем такую структуру: 
 Array
(
 // Разделы
 [0] => Array
 (
 [ID] => 17
 [NAME] => Юридические вопросы
 [CODE] => yuridicheskie-voprosy
 [SECTION_PAGE_URL] => /faq/yuridicheskie-voprosy/
 [ELEMENTS] => Array
 (
 // Элементы
 [0] => Array
 [1] => Array
 [2] => Array
 )
 )
 [1] => Array
 [2] => Array
 ...
)
 
 В template.php выводим так: 
 <?foreach ($arResult["ITEMS"] as $arSection):?>
 <h4><?=$arSection["NAME"]?></h4>
 <?if ($arSection["ELEMENTS"]):?>
 <ul>
 <?foreach ($arSection["ELEMENTS"] as $arItem):?>
 <?
 $this->AddEditAction($arItem['ID'], $arItem['EDIT_LINK'], CIBlock::GetArrayByID($arItem["IBLOCK_ID"], "ELEMENT_EDIT"));
 $this->AddDeleteAction($arItem['ID'], $arItem['DELETE_LINK'], CIBlock::GetArrayByID($arItem["IBLOCK_ID"], "ELEMENT_DELETE"), array("CONFIRM" => GetMessage('CT_BNL_ELEMENT_DELETE_CONFIRM')));
 ?>
 <li id="<?=$this->GetEditAreaId($arItem['ID']);?>">
 <a href="<?=$arItem["DETAIL_PAGE_URL"]?>"><?=$arItem["NAME"]?></a>
 </li>
 <?endforeach?>
 </ul>
 <?endif?>
<?endforeach?>
 
 Не нравится мне имя ключа $arResult["ITEMS"] , напрашивается "SECTIONS", но пока оставлю, как есть. 
 Однако есть вариант лучше, который избавит нас от вложенного foreach. 
 $rsSections = CIBlockSection::GetList(
 Array("SORT" => "ASC"),
 Array(
 "=IBLOCK_ID" => $arParams['IBLOCK_ID'],
 "=ACTIVE" => "Y"
 )
);

// Тут вместо инкрементного индекса, ID раздела
while ($arSection = $rsSections->GetNext())
 $arSections[$arSection['ID']] = $arSection;

// По нему производим неявную фильрацию
foreach($arResult["ITEMS"] as $arItem) {
 $arSections[$arItem['IBLOCK_SECTION_ID']]['ITEMS'][] = $arItem;
}

$arResult["SECTIONS"] = $arSections;
 
 Получаем струтуру вида: 
 Array
( 
 // Разделы
 [18] => Array
 (
 [ID] => 18
 [NAME] => Вопросы по доставка и оплате
 [CODE] => voprosy-po-dostavka-i-oplate
 [SECTION_PAGE_URL] => /faq/voprosy-po-dostavka-i-oplate/
 [IBLOCK_TYPE_ID] => references
 [ITEMS] => Array
 (
 // Элементы
 [0] => Array
 (
 [ID] => 331
 [IBLOCK_SECTION_ID] => 18
 [NAME] => Как изменить номер телефона в личном кабинете?
 [DETAIL_PAGE_URL] => /faq/voprosy-po-dostavka-i-oplate/kak-izmenit-nomer-telefona/
 )
 [1] => Array
 [2] => Array
 
 В template.php аналогичная верстка, лишь переименуем ключи $arResult. 
 <?foreach ($arResult["SECTIONS"] as $arSection):?>
 <h4><?=$arSection["NAME"]?></h4>
 <ul>
 <?foreach ($arSection["ITEMS"] as $arItem):?>
 <li id="<?=$this->GetEditAreaId($arItem['ID']);?>">
 <a href="<?=$arItem["DETAIL_PAGE_URL"]?>"><?=$arItem["NAME"]?></a>
 </li>
 <?endforeach?>
 </ul>
<?endforeach?>

1C-Bitrix: site under construction – изменяем шаблон
Способ изменения стандартной надписи Site under construction в 1C-Bitrix при отключения сайта через панель администрирования. 
 Шаблон “Under construction” находится в следующем файле: 
 /bitrix/modules/main/include/site_closed.php 
 Необходимо скопировать его в 
 /bitrix/php_interface/<language>/ 
 или 
 /bitrix/php_interface/include/

Шпаргалка Bitrix
Шпаргалка Bitrix 
 Шаблон 
 Пролог/подключение языковых файлов (header.php/footer.php) 
 if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true) die();
IncludeTemplateLangFile(__FILE__);
 
 Язык шаблона 
 <html lang="<?=LANGUAGE_ID?>">
 
 Заголовки 
 <title><?$APPLICATION->ShowTitle();?></title>
<h1><?$APPLICATION->ShowTitle(false,false);?></h1>
 
 Мета данные для head 
 <?$APPLICATION->ShowHead();?>
 
 Панель в <body 
 <?$APPLICATION->ShowPanel();?
 
 Подключение CSS и JS 
 <?$APPLICATION->SetAdditionalCSS(SITE_TEMPLATE_PATH.'/css/style.css');?>
<?$APPLICATION->AddHeadScript(SITE_TEMPLATE_PATH.'/js/script.js');?>
 
 Подключение CSS и JS c поддержкой D7 
 use Bitrix\\Main\\Page\\Asset;
Asset::getInstance()->addJs(SITE_TEMPLATE_PATH . "/js/fix.js");
Asset::getInstance()->addCss(SITE_TEMPLATE_PATH . "/styles/fix.css");
Asset::getInstance()->addString("<link href='http://...' rel='stylesheet' type='text/css'>");
 
 Путь до шаблона 
 <?=SITE_TEMPLATE_PATH?>
 
 Включаемая область 
 $APPLICATION->IncludeComponent(
 "bitrix:main.include", 
 "", 
 array(
 "AREA_FILE_SHOW" => "sect", 
 "AREA_FILE_SUFFIX" => "inc", 
 "AREA_FILE_RECURSIVE" => "Y", 
 "EDIT_TEMPLATE" => ""
 ),
 false
);
 
 Включаемая область из файла 
 $APPLICATION->IncludeComponent(
 "bitrix:main.include",
 "",
 array(
 "AREA_FILE_SHOW" => "file",
 "AREA_FILE_SUFFIX" => "inc",
 "EDIT_TEMPLATE" => "",
 "PATH" => "/include/name.php"
 )
);
 
 Проверки URL 
 if ($GLOBALS["APPLICATION"]->GetCurPage() == "/") {} // если в корне

if (CSite::InDir('/about/')) {} // раздел и подразделы

if (strstr($GLOBALS["APPLICATION"]->GetCurPage(), "page")) {} // проверка на совпадение
 
 Свойства разделов/страницы 
 if ($APPLICATION->GetProperty("FULL_WIDTH") == "Y") {}

$APPLICATION->SetPageProperty("keywords", "...");
 
 Фильтр для вывода элементов у которых значение свойства равно определенному значению 
 global $arFilter;

$arFilter = array(
 "IBLOCK_ID" => 9,
 "ACTIVE" => "Y",
 "PROPERTY_NTV_VALUE" => "Да",
);
// в компоненте "FILTER_NAME" => "arFilter",
 
 Для свойств типа "список" 
 $enum_list = CIBlockPropertyEnum::GetList(
 array("SORT" => "ASC", "NAME" => "ASC"), 
 array("IBLOCK_ID" => 2, "CODE" => "PROPNAME", "VALUE" => "да")
); 

$arEnumIsMain = $enum_list->GetNext(); 

global $arrFilter;
$arrFilter = array(
 "PROPERTY" => array("PROPNAME" => $arEnumIsMain["ID"])
);
 
 Пример фильтра для CIBlockElement::GetList по списку 
 CIBlockElement::GetList(
 array(), // arOrder
 array(
 "IBLOCK_ID" => $arResult["IBLOCK_ID"], 
 "ACTIVE" => "Y", 
 "PROPERTY_SHOW_IN_POPULAR_VALUE" => array("Да")
 ), // arFilter
 false, // arGroupBy
 false, // arNavStartParams
 array() // arSelectFields
);
 
 Редактирование елементов 
 $this->AddEditAction(
 $ar_result['ID'], 
 $arItem['EDIT_LINK'], 
 CIBlock::GetArrayByID($arParams['IBLOCK_ID'], "ELEMENT_EDIT")
);
$this->AddDeleteAction(
 $ar_result['ID'], 
 $arItem['DELETE_LINK'], 
 CIBlock::GetArrayByID($arParams['IBLOCK_ID'], "ELEMENT_DELETE"), 
 array("CONFIRM" => GetMessage('CT_BNL_ELEMENT_DELETE_CONFIRM'))
);

<li id="<?=$this->GetEditAreaId($arItem['ID']);?>"></li>
 
 Буферизация 
 Буферизация средствами php 
 ob_start();
// Код компонента
$GLOBALS['NAME'] = ob_get_contents();
ob_end_clean();
// Вывод $GLOBALS['NAME']
 
 Буферизация средствами Bitrix 
 <?
$this->SetViewTarget('NAME');
// Код компонента...
$this->EndViewTarget();
// Вывод $APPLICATION->ShowViewContent("NAME");
?>
 
 Навигация Следующая - Предыдущая статья. 
 Код необходимо разместить в файле result_modifier.php 
 <?
 $arSort = array(
 $arParams["SORT_BY1"] => $arParams["SORT_ORDER1"],
 $arParams["SORT_BY2"] => $arParams["SORT_ORDER2"],
 );
 $arSelect = array("ID", "NAME", "DETAIL_PAGE_URL");
 $arFilter = array (
 "IBLOCK_ID" => $arResult["IBLOCK_ID"],
 // Можно ограничить секцией
 // "SECTION_CODE" => $arParams["SECTION_CODE"], или "SECTION_ID" => $arResult["IBLOCK_SECTION_ID"],
 "ACTIVE" => "Y",
 "CHECK_PERMISSIONS" => "Y",
 );
 // выбирать по 1 соседу с каждой стороны от текущего
 $arNavParams = array(
 "nPageSize" => 1,
 "nElementID" => $arResult["ID"],
 );
 $arItems = array();
 $rsElement = CIBlockElement::GetList($arSort, $arFilter, false, $arNavParams, $arSelect);
 $rsElement->SetUrlTemplates($arParams["DETAIL_URL"]);

 while($obElement = $rsElement->GetNextElement())
 $arItems[] = $obElement->GetFields();
 
 if (count($arItems)==3):
 $arResult["TORIGHT"] = array("NAME" => $arItems[0]["NAME"], "URL" => $arItems[0]["DETAIL_PAGE_URL"]);
 $arResult["TOLEFT"] = array("NAME" => $arItems[2]["NAME"], "URL" => $arItems[2]["DETAIL_PAGE_URL"]);
 elseif (count($arItems)==2):
 if ($arItems[0]["ID"] != $arResult["ID"])
 $arResult["TORIGHT"] = Array("NAME" => $arItems[0]["NAME"], "URL" => $arItems[0]["DETAIL_PAGE_URL"]);
 else
 $arResult["TOLEFT"] = Array("NAME" => $arItems[1]["NAME"], "URL" => $arItems[1]["DETAIL_PAGE_URL"]);
 endif;
 // $arResult["TORIGHT"] и $arResult["TOLEFT"] массивы с информацией о соседних элементах
?>
 
 Вывод в компоненте 
 <?php if (is_array($arResult["TOLEFT"])) { ?>
 <a id="pre_page" href="<?=$arResult["TOLEFT"]["URL"]?>"> < <?=$arResult["TOLEFT"]["NAME"]?></a>
<?php } ?>
<?php if (is_array($arResult["TORIGHT"])) { ?>
 <a id="next_page" href="<?=$arResult["TORIGHT"]["URL"]?>"><?=$arResult["TORIGHT"]["NAME"]?> > </a>
<?php } ?>
 
 Путь к картинке по id 
 <?
$arOnePhoto = CFile::GetFileArray($PHOTO);
// $arOnePhoto['SRC']
?>
 
 Если пoльзoвaтeль имeeт прaвa aдминистрaтoрa 
 <?php if ($USER->Isadmin()) {} ?>
 
 Пoлучeниe кoличeствa тoвaрoв в нaличии 
 <?
$ar_res = CCatalogProduct::GetByID($arelement['ID']); 
// $ar_res['QUANTITY']
?>
 
 Вывод пользовательских свойств раздела 
 Вывод пользовательского свойства раздела типа файл 
 <? 
$db_list = CIBlockSection::GetList(
 array($by => $order), 
 array("IBLOCK_ID" => 8, "ID" => $arSection['ID']), 
 true,
 array("UF_NAME_IMG")
);

while($ar_result = $db_list->GetNext()): 
 foreach($ar_result["UF_NAME_IMG"] as $PHOTO):
 echo CFile::GetPath($PHOTO);
 endforeach; 
endwhile;
?>
 
 
_______________________________________________________________

Свойства элемента по id

<?
$db_props = CIBlockElement::GetProperty(IBLOCK_ID, ELEMENT_ID, "sort", "asc", array());
$PROPS = array();
while($ar_props = $db_props->Fetch())
 $PROPS[$ar_props['CODE']] = $ar_props['VALUE'];
?>
_______________________________________________________________

Замена стандартного выделения слов в поиске

\\www\\bitrix\\modules\\search\\classes\\general\\search.php:317

$str_result = str_replace("%/^%", "</b>", str_replace("%^%","<b>", $str_result));
_______________________________________________________________

Получение элементов инфоблока

<?
$arSelect = Array("ID", "NAME", "PREVIEW_PICTURE");
$arFilter = Array("IBLOCK_ID" => 19, "ACTIVE_DATE" => "Y", "ACTIVE" => "Y");
$res = CIBlockElement::GetList(Array(), $arFilter, false, false, $arSelect);
while($ob = $res->GetNextElement()) {
 $arFields = $ob->GetFields();
 print_r($arFields);
}
?> 
_______________________________________________________________

AJAX подгрузка компонентов

<?
define('STOP_STATISTICS', true);
require_once($_SERVER['DOCUMENT_ROOT'].'/bitrix/modules/main/include/prolog_before.php');
$GLOBALS['APPLICATION']->RestartBuffer();

[ajax code]
?>
_______________________________________________________________

Дополнительные пункты меню

.left.menu_ext.php

<?
if (CModule::IncludeModule("iblock")) {
 global $APPLICATION;
 $aMenuLinksExt = $APPLICATION->IncludeComponent(
 "bitrix:menu.sections",
 "",
 Array(
 "CACHE_TIME" => "3600",
 "CACHE_TYPE" => "A",
 "DEPTH_LEVEL" => "4",
 "DETAIL_PAGE_URL" => "#SECTION_CODE#/#ELEMENT_CODE#",
 "IBLOCK_ID" => "3",
 "IBLOCK_TYPE" => "content",
 "ID" => $_REQUEST["ID"],
 "IS_SEF" => "Y",
 "SECTION_PAGE_URL" => "#SECTION_CODE#/",
 "SECTION_URL" => "",
 "SEF_BASE_URL" => "/services/"
 )
 );
 $aMenuLinks = array_merge($aMenuLinksExt, $aMenuLinks);
}
?>

C элементами

<?
if (CModule::IncludeModule("iblock")) {

 $aMenuLinksNew = Array();
 $IBLOCK_ID = 3;
 $ctlg_sections = CIBlockSection::GetList(
 Array("ID" => "ASC", " ACTIVE" => "Y"),
 Array("IBLOCK_ID" => $IBLOCK_ID),
 true,
 Array('ID', 'NAME', 'CODE', 'DEPTH_LEVEL')
 );

 while ($ar_fields = $ctlg_sections->GetNext()) {

 array_push(
 $aMenuLinksNew, 
 array(
 $ar_fields['NAME'], 
 $ar_fields['CODE']."/", 
 array(), 
 array(
 "FROM_IBLOCK" => "1", 
 "IS_PARENT" => $ar_fields['ELEMENT_CNT'], 
 "DEPTH_LEVEL" => $ar_fields["DEPTH_LEVEL"]
 ), 
 "",
 ) 
 );

 // elements
 $arSelect = array("ID", "NAME", "CODE");
 $arFilter = array(
 "IBLOCK_ID"=> $IBLOCK_ID, 
 "SECTION_ID" => $ar_fields['ID'], 
 "ACTIVE_DATE"=>"Y", 
 "ACTIVE"=>"Y"
 );
 $res = CIBlockElement::GetList(array(), $arFilter, false, array("nPageSize" => 5000), $arSelect);
 while ($ob = $res->GetNextElement()) {
 $arFields = $ob->GetFields();
 array_push(
 $aMenuLinksNew, 
 array(
 $arFields['NAME'], 
 $ar_fields['CODE']."/".$arFields['CODE']."/", 
 array(), 
 array(
 "FROM_IBLOCK"=>"1", 
 "IS_PARENT"=>"", 
 "DEPTH_LEVEL"=>"2"
 ), 
 "",
 )
 );
 }
 
 }

 $aMenuLinks = array_merge($aMenuLinksNew, $aMenuLinks);
}
?>
____________________________________________________________

Image resize

<?
$arFilters = array(
 array(
 "name" => "watermark", 
 "position" => "tr", 
 "size" => "small", 
 "file" => $_SERVER["DOCUMENT_ROOT"]."/waterm.png"
 )
); //если нужен водяной знак

// НЕ пропорционально
$renderImage = CFile::ResizeImageGet(
 $PHOTO, 
 array("width" => 200, "height" => 200), 
 $resizeType = BX_RESIZE_IMAGE_EXACT, 
 $bInitSizes = false, 
 $arFilters
); 

// пропорционально
$renderImage = CFile::ResizeImageGet(
 $PHOTO, 
 array("width" => 1200, "height" => 1000), 
 $resizeType = BX_RESIZE_IMAGE_PROPORTIONAL, 
 $bInitSizes = false, 
 $arFilters
);

// $renderImage['src']
?>
_______________________________________________________________

Пример news.list с вкладками и бесконечной подгрузкой по кнопке

portfolio.php
<?
require_once($_SERVER['DOCUMENT_ROOT'] . "/bitrix/modules/main/include/prolog_before.php");
if (isset($_GET['idtab'])) $idtab = $_GET['idtab']; // id активного раздела (для фильтра)
?>

<?$APPLICATION->IncludeComponent(
 "bitrix:news.list",
 "portfolio",
 Array(
 "ACTIVE_DATE_FORMAT" => "d.m.Y",
 "ADD_SECTIONS_CHAIN" => "N",
 "AJAX_MODE" => "N",
 "AJAX_OPTION_ADDITIONAL" => "",
 "AJAX_OPTION_HISTORY" => "N",
 "AJAX_OPTION_JUMP" => "N",
 "AJAX_OPTION_STYLE" => "Y",
 "CACHE_FILTER" => "N",
 "CACHE_GROUPS" => "Y",
 "CACHE_TIME" => "36000000",
 "CACHE_TYPE" => "A",
 "CHECK_DATES" => "Y",
 "COMPONENT_TEMPLATE" => "portfolio",
 "DETAIL_URL" => "",
 "DISPLAY_BOTTOM_PAGER" => "Y", // для генерации PAGER_ 
 "DISPLAY_DATE" => "Y",
 "DISPLAY_NAME" => "Y",
 "DISPLAY_PICTURE" => "Y",
 "DISPLAY_PREVIEW_TEXT" => "Y",
 "DISPLAY_TOP_PAGER" => "N",
 "FIELD_CODE" => array(0=>"",1=>"",),
 "FILTER_NAME" => "",
 "HIDE_LINK_WHEN_NO_DETAIL" => "N",
 "IBLOCK_ID" => "8",
 "IBLOCK_TYPE" => "design",
 "INCLUDE_IBLOCK_INTO_CHAIN" => "N",
 "INCLUDE_SUBSECTIONS" => "Y",
 "MESSAGE_404" => "",
 "NEWS_COUNT" => "6",
 "PAGER_BASE_LINK_ENABLE" => "N",
 "PAGER_DESC_NUMBERING" => "N",
 "PAGER_DESC_NUMBERING_CACHE_TIME" => "36000",
 "PAGER_SHOW_ALL" => "N",
 "PAGER_SHOW_ALWAYS" => "N",
 "PAGER_TEMPLATE" => ".default",
 "PAGER_TITLE" => "Новости",
 "PARENT_SECTION" => $idtab, // фильтр по конкретному разделу
 "PARENT_SECTION_CODE" => "",
 "PREVIEW_TRUNCATE_LEN" => "",
 "PROPERTY_CODE" => array(0=>"",1=>"",),
 "SET_BROWSER_TITLE" => "N",
 "SET_LAST_MODIFIED" => "N",
 "SET_META_DESCRIPTION" => "N",
 "SET_META_KEYWORDS" => "N",
 "SET_STATUS_404" => "N",
 "SET_TITLE" => "N",
 "SHOW_404" => "N",
 "SORT_BY1" => "ACTIVE_FROM",
 "SORT_BY2" => "SORT",
 "SORT_ORDER1" => "DESC",
 "SORT_ORDER2" => "ASC"
 )
);?>

template.php

<?
foreach($arResult["ITEMS"] as $arItem):
 $this->AddEditAction($arItem['ID'], $arItem['EDIT_LINK'], CIBlock::GetArrayByID($arItem["IBLOCK_ID"], "ELEMENT_EDIT"));
 $this->AddDeleteAction($arItem['ID'], $arItem['DELETE_LINK'], CIBlock::GetArrayByID($arItem["IBLOCK_ID"], "ELEMENT_DELETE"), array("CONFIRM" => GetMessage('CT_BNL_ELEMENT_DELETE_CONFIRM')));
 ?>
 <div id="<?=$this->GetEditAreaId($arItem['ID']);?>"><?=$arItem["NAME"]?></div>
<?
endforeach;
?>

index.php с компонентом

<?
CModule::IncludeModule("iblock");
$newsCounter = CIBlockElement::GetList(array(), array("IBLOCK_ID" => 8, "ACTIVE" => "Y"), array());
?>
<div class="ptabs ptabs_active" data-id="" data-count="<?=$newsCounter?>">Все</div>
<?
$ptabs = CIBlockSection::GetList(array($by=>$order), array('IBLOCK_ID' => 8, 'GLOBAL_ACTIVE' => 'Y'), true);
while ($ar_result = $ptabs->GetNext()) {
 $newsCounter = CIBlockElement::GetList(
 array(), array("IBLOCK_ID" => 8, "ACTIVE" => "Y", "SECTION_ID"=>$ar_result['ID']), array()
 );
 ?>
 <div class="ptabs" data-id="<?=$ar_result['ID']?>" data-count="<?=$newsCounter?>">
 <?=$ar_result['NAME']?> (id:<?=$ar_result['ID']?>)
 </div>
 <?
}
?>

<div>
 <div class="potfolio__list"><?$APPLICATION->IncludeFile("/portfolio.php");?></div> 
 <a href="#" class="show-more">Показать еще</a>
</div>

script.js

<script>
$(document).ready(function(){
 function checkCount(cnt){
 if (currentPage * 6 >= cnt) {
 $('.show-more').hide();
 } else {
 $('.show-more').show();
 }
 }
 var currentPage = 1;
 var path = '/portfolio.php?ajax=Y';
 var count = $('.ptabs_active').data('count');
 checkCount(count);
 $('.ptabs').on('click', function() {
 $('.preloader').fadeIn(0);
 $('.ptabs').removeClass('ptabs_active');
 $(this).addClass('ptabs_active');
 var idtab = $(this).data('id');
 $.get(path, {idtab: idtab}, function(data) {
 $('.potfolio__list').html(data);
 count = $('.ptabs_active').data('count');
 currentPage = 1;
 checkCount(count);
 setTimeout(function() {
 $('.preloader').fadeOut(100);
 }, 500);
 });
 });

 $('.show-more').click(function(e) {
 $('.preloader').fadeIn(0);
 var idtab = $('.ptabs_active').data('id');
 $.get(path, {PAGEN_1: ++currentPage, idtab:idtab}, function(data){
 $('.potfolio__list').append(data);
 checkCount(count);
 setTimeout(function(){
 $('.preloader').fadeOut(100);
 }, 500);
 });
 e.preventDefault();
 });
}
</script>

Если нет возможности узнать общее кол-во (например умный фильтр со scu) проще скрывать по условию:

<?
if ($arResult["NAV_RESULT"]->nEndPage > 1 && $arResult["NAV_RESULT"]->NavPageNomer < $arResult["NAV_RESULT"]->nEndPage):
?>
Показать еще
<?endif;?>
_______________________________________________________________

Получить поля SEO для элемента

<?
CModule::IncludeModule("iblock");
$ipropValues = new \\Bitrix\\Iblock\\InheritedProperty\\ElementValues(
 $arCurElem["IBLOCK_ID"], // ID инфоблока
 $arCurElem["ID"] // ID элемента
);
$arElMetaProp = $ipropValues->getValues();
echo '<pre>'; print_r ($arElMetaProp); echo '</pre>';
?>

Поля SEO для раздела

<?
CModule::IncludeModule("iblock");
 
$rsSection = CIBlockSection::GetList(
 array(),
 array(
 "IBLOCK_ID"=>$arParams['IBLOCK_ID'],
 "ACTIVE"=>"Y",
 "=CODE"=>$arParams["SECTION_CODE"]
 ),
 false
);
 
if($arSection = $rsSection->GetNext()){
 
 $ipropValues = new \\Bitrix\\Iblock\\InheritedProperty\\SectionValues(
 $arSection["IBLOCK_ID"],
 $arSection["ID"]
 );
 $arSection["IPROPERTY_VALUES"] = $ipropValues->getValues();
 echo "<pre>"; print_r($arSection); echo '</pre>';
}
?>
_______________________________________________________________

Получение всего списка highload блоков

<?
use Bitrix\\Highloadblock\\HighloadBlockTable as HLBT;
$MY_HL_BLOCK_ID = 3;
CModule::IncludeModule('highloadblock');
function GetEntityDataClass($HlBlockId) {
 if (empty($HlBlockId) || $HlBlockId < 1) return false;
 $hlblock = HLBT::getById($HlBlockId)->fetch(); 
 $entity = HLBT::compileEntity($hlblock);
 $entity_data_class = $entity->getDataClass();
 return $entity_data_class;
}
$entity_data_class = GetEntityDataClass($MY_HL_BLOCK_ID);
$rsData = $entity_data_class::getList(array(
 'select' => array('*')
));
while ($el = $rsData->fetch()) {
 print_r($el);
}
?>

или

<?
if (CModule::IncludeModule('highloadblock')) {
 $Date = date(CDatabase::DateFormatToPHP(FORMAT_DATETIME));
 $arHLBlock = Bitrix\\Highloadblock\\HighloadBlockTable::getById(3)->fetch();
 $obEntity = Bitrix\\Highloadblock\\HighloadBlockTable::compileEntity($arHLBlock);
 $strEntityDataClass = $obEntity->getDataClass();
 $resData = $strEntityDataClass::getList(array(
 'select' => array('*'),
 ));
 while ($arItem = $resData->Fetch()) {
 echo "<pre>"; print_r($arItem); echo "</pre>";
 }
}
?>
_______________________________________________________________

Добавление номера страницы в title

каталог/section.php
<?
 CModule::IncludeModule("iblock");
 $arSection = array();
 if ($arResult["VARIABLES"]["SECTION_ID"]>0) {
 $arFilter = array('IBLOCK_ID'=>$arParams["IBLOCK_ID"], 'GLOBAL_ACTIVE'=>'Y', "ID" => $arResult["VARIABLES"]["SECTION_ID"]);
 } elseif(strlen(trim($arResult["VARIABLES"]["SECTION_CODE"]))>0) {
 $arFilter = array('IBLOCK_ID'=>$arParams["IBLOCK_ID"], 'GLOBAL_ACTIVE'=>'Y', "=CODE" => $arResult["VARIABLES"]["SECTION_CODE"]);
 }
 $db_list = CIBlockSection::GetList(array(), $arFilter, true, array("ID", "NAME", "IBLOCK_ID", "DEPTH_LEVEL", "IBLOCK_SECTION_ID", "CODE"));

 while($section = $db_list->GetNext())
 $arSection = $section;

 $arSelect = array("ID");

 if ($arParams["LIST_BROWSER_TITLE"]) $arSelect = array_merge($arSelect, (array)$arParams["LIST_BROWSER_TITLE"]);
 if ($arParams["LIST_META_KEYWORDS"]) $arSelect = array_merge($arSelect, (array)$arParams["LIST_META_KEYWORDS"]);
 if ($arParams["LIST_META_DESCRIPTION"]) $arSelect = array_merge($arSelect, (array)$arParams["LIST_META_DESCRIPTION"]);

 $arSectionFull = CIBlockSection::GetList(
 array(), 
 array("ID" => $arSection["ID"], "IBLOCK_ID"=> $arSection["IBLOCK_ID"]), 
 false, 
 $arSelect, 
 false
 )->GetNext();

 if ($_GET["PAGEN_1"]) $page = GetMessage('PAGE').$_GET["PAGEN_1"];

 if ($arParams["LIST_BROWSER_TITLE"] && $arSectionFull[$arParams["LIST_BROWSER_TITLE"]]) $APPLICATION->SetPageProperty("title", $arSectionFull[$arParams["LIST_BROWSER_TITLE"]].$page);

 // new title
 $ipropValues = new \\Bitrix\\Iblock\\InheritedProperty\\SectionValues(
 $arSection["IBLOCK_ID"],
 $arSection["ID"]
 );
 
 $arSection["IPROPERTY_VALUES"] = $ipropValues->getValues();
 $APPLICATION->SetPageProperty("title", $arSection["IPROPERTY_VALUES"]["SECTION_META_TITLE"].$page);
?>

Детальная

<?
if(CModule::IncludeModule("iblock")){
 $ipropValues = new \\Bitrix\\Iblock\\InheritedProperty\\ElementValues(
 $arParams['IBLOCK_ID'],
 $ElementID
 );
 
 $arElMetaProp = $ipropValues->getValues();

 $title = $arElMetaProp["ELEMENT_META_TITLE"] ? $arElMetaProp["ELEMENT_META_TITLE"] : $APPLICATION->GetTitle();
 $description = $arElMetaProp["ELEMENT_META_DESCRIPTION"] ? $arElMetaProp["ELEMENT_META_DESCRIPTION"] : $APPLICATION->GetProperty("description");

 if($_GET["PAGEN_2"]){
 $APPLICATION->SetPageProperty('title', $title.". Страница ".$_GET["PAGEN_2"].".");
 $APPLICATION->SetPageProperty('description', $description.". Страница ".$_GET["PAGEN_2"].".");
 }
}
?>
_______________________________________________________________

HTTPS

dbconn.php
$_SERVER["HTTPS"] = "On";
_______________________________________________________________

CAPTCHA

template.php

<?
$code = $APPLICATION->CaptchaGetCode();
?>
<img src="/bitrix/tools/captcha.php?captcha_code=<?=$code?>">
<input id="captcha_word" name="captcha_word" type="text" placeholder="Введите слово на картинке">
<input name="captcha_code" value="<?=$code?>" type="hidden">

Проверка

<?
if (!$APPLICATION->CaptchaCheckCode($_POST["captcha_word"], $_POST["captcha_code"])) {
 // Неправильное значение
} else {
 // Правильное значение
}
?>

Пример обновления

<div class="captcha__update">обновить картинку</div>
<script>
$('.captcha__update').click(function(){
 $.getJSON('<?=$path?>/reload_captcha.php', function(data) {
 $('.captcha__img').attr('src','/bitrix/tools/captcha.php?captcha_sid='+data);
 $('.captcha__validate').val(data);
 });
});
</script>

reload_captcha.php
<?
echo json_encode($APPLICATION->CaptchaGetCode());
?>
_______________________________________________________________

Вывод переменных до их определения

Добавляем ссылку в h1 в шаблоне компонента header.php:
<?$APPLICATION->ShowViewContent('news');?><!-- content -->

Добавляем в шаблон компонента:
<?$this->SetViewTarget('news');?>
 <!-- content -->
<?$this->EndViewTarget();?>
_______________________________________________________________

Генерация url с заменой параметров и сохранением старых

<?=$APPLICATION->GetCurPageParam ('sort=price&method=asc', array('sort', 'method'))?>
_______________________________________________________________

Добавление полей к шаблону письма

<?
AddEventHandler("sale", "OnOrderNewSendEmail", "bxModifySaleMails");

function bxModifySaleMails($orderID, &$eventName, &$arFields)
{
 $arOrder = CSaleOrder::GetByID($orderID);

 $order_props = CSaleOrderPropsValue::GetOrderProps($orderID);

 $city_name = ""; 
 $address = "";

 while ($arProps = $order_props->Fetch()){

 if ($arProps["CODE"] == "PHONE") $phone = htmlspecialchars($arProps["VALUE"]);

 if ($arProps["CODE"] == "INDEX") $index = $arProps["VALUE"]; 
 if ($arProps["CODE"] == "ADDRESS") $address = $arProps["VALUE"];

 if ($arProps["CODE"] == "LOCATION") {
 $arLocs = CSaleLocation::GetByID($arProps["VALUE"]);
 $country_name = $arLocs["COUNTRY_NAME_ORIG"];
 $city_name = $arLocs["CITY_NAME_ORIG"];
 }

 /* юр лицо */
 if ($arProps["CODE"] == "COMPANY") $company = $arProps["VALUE"]; 
 if ($arProps["CODE"] == "COMPANY_ADR") $company_adr = $arProps["VALUE"];
 if ($arProps["CODE"] == "INN") $inn = $arProps["VALUE"];
 if ($arProps["CODE"] == "KPP") $kpp = $arProps["VALUE"];
 if ($arProps["CODE"] == "CONTACT_PERSON") $contact_person = $arProps["VALUE"];
 if ($arProps["CODE"] == "FAX") $fax = $arProps["VALUE"];
 }

 // служба доставки
 $arDeliv = CSaleDelivery::GetByID($arOrder["DELIVERY_ID"]);
 if ($arDeliv) $delivery_name = $arDeliv["NAME"];

 // получаем название платежной системы 
 $arPaySystem = CSalePaySystem::GetByID($arOrder["PAY_SYSTEM_ID"]);
 if ($arPaySystem) $pay_system_name = $arPaySystem["NAME"];

 // добавляем новые поля в массив результатов
 $arFields["ORDER_DESCRIPTION"] = $arOrder["USER_DESCRIPTION"] ? $arOrder["USER_DESCRIPTION"] : "-";
 $arFields["PHONE"] = $phone ? $phone : "-";
 $arFields["DELIVERY_NAME"] = $delivery_name ? $delivery_name : "-";
 $arFields["PAY_SYSTEM_NAME"] = $pay_system_name ? $pay_system_name : "-";
 $arFields["FULL_ADDRESS"] = $city_name." ".$address;

 $arFields["COMPANY"] = $company ? $company : "-";
 $arFields["COMPANY_ADR"] = $company_adr ? $company_adr : "-";
 $arFields["INN"] = $inn ? $inn : "-";
 $arFields["KPP"] = $kpp ? $kpp : "-";
 $arFields["CONTACT_PERSON"] = $contact_person ? $contact_person : "-";
 $arFields["FAX"] = $fax ? $fax : "-";

}
?>
_______________________________________________________________

Размещаем некэшируемую область в кэшируемом компоненте

result_modifier.php

<?if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true)die();?>
<?$this->__component->SetResultCacheKeys(array("CACHED_TPL"));?>

component_epilog.php

<?if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true)die();?>
<?
echo preg_replace_callback(
 "/#VOTE_ID_([\\d]+)#/is".BX_UTF_PCRE_MODIFIER,
 create_function('$matches', 
 'ob_start();
 /*тут код который не хотим кэшировать*/
 $retrunStr = @ob_get_contents();
 ob_get_clean();
 return $retrunStr;'
 ),
 $arResult["CACHED_TPL"]
);
?>

(в некэшируемом коде вместо обычного $APPLICATION пишем $GLOBALS["APPLICATION"], для видимости объекта внутри временной функции)

template.php

В начало
<?ob_start();?>
В конец
<?
$this->__component->arResult["CACHED_TPL"] = @ob_get_contents();
ob_get_clean();
?>

добавляем маркер
<? echo "#VOTE_ID_1#"; ?>
(регулярка #VOTE_ID_([\\d]+)# для примера, удобно использовать $matches[1] для ID и т.п.)
_______________________________________________________________

AJAX сравнение

header.php

<script>
 var SITE_DIR = '<?=SITE_DIR?>';
 var CATALOG_COMPARE_LIST = new Object();
 CATALOG_COMPARE_LIST.defaultText = "Сравнить";
 CATALOG_COMPARE_LIST.activeText = "В сравнении";
</script>
<?// сравнение
foreach ($_SESSION["CATALOG_COMPARE_LIST"][2]["ITEMS"] as $value) { 
 ?>
 <script>CATALOG_COMPARE_LIST[<?=$value["ID"]?>] = true;</script> 
 <?
}
?>

template.php

В начало
<?ob_start();?>
В конец
<?
$this->__component->arResult["CACHED_TPL"] = @ob_get_contents();
ob_get_clean();
?>
Маркер
<? echo "#COMPARE_FAV_ID_".$arItem['ID']."#"; ?>

component_epilog.php 

<?
echo preg_replace_callback(
 "/#COMPARE_FAV_ID_([\\d]+)#/is".BX_UTF_PCRE_MODIFIER,
 create_function('$matches', 
 'ob_start();
 ?>
 <div class="btn-c">
 <a href="#" class="add-compare ctrl-radio <?if(!empty($_SESSION["CATALOG_COMPARE_LIST"][2]["ITEMS"][$matches[1]])):?> ctrl-radio_checked<?endif?>" data-id="<?=$matches[1]?>" >
 <i class="ctrl-radio__ico"></i>
 <span class="add-compare__ttl">
 <?if (!empty($_SESSION["CATALOG_COMPARE_LIST"][2]["ITEMS"][$matches[1]])):?>
 В сравнении
 <?else:?>
 Сравнить
 <?endif?>
 </span>
 </a>
 </div>
 <?
 $returnStr = @ob_get_contents();
 ob_get_clean();
 return $returnStr;'
 ),
$arResult["CACHED_TPL"]);
?>

result_modifier.php

<?if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true)die();?>
<?$this->__component->SetResultCacheKeys(array("CACHED_TPL"));?>

script.js 

<script>
 // compare
 $('body').on('click', '.add-compare', function(e){
 e.preventDefault();

 var compareButton = $(this),
 product_id = compareButton.data('id');

 if (CATALOG_COMPARE_LIST[product_id]) {
 compareButton.removeClass('ctrl-radio_checked').find('.add-compare__ttl').text(CATALOG_COMPARE_LIST.defaultText);
 $.ajax({
 url: SITE_DIR + 'catalog/?action=DELETE_FROM_COMPARE_LIST&id=' + product_id,
 type: 'post',
 success: function (data) {
 $('.bx_catalog-compare-list').replaceWith(data);
 }
 });
 delete CATALOG_COMPARE_LIST[product_id];
 } else {
 compareButton.addClass('ctrl-radio_checked').find('.add-compare__ttl').text(CATALOG_COMPARE_LIST.activeText);
 $.ajax({
 url: SITE_DIR + 'catalog/?action=ADD_TO_COMPARE_LIST&id=' + product_id,
 type: 'post',
 success: function (data) {
 $('.bx_catalog-compare-list').replaceWith(data);
 }
 });
 CATALOG_COMPARE_LIST[product_id] = true;
 }
 });

 $('body').on('click', '.bx_catalog_compare_form [data-id]', function() {
 var delId = $(this).data('id');
 delete CATALOG_COMPARE_LIST[delId];
 $('.add-compare[data-id='+delId+']').removeClass('ctrl-radio_checked').find('.add-compare__ttl').text(CATALOG_COMPARE_LIST.defaultText);
 });
</script>

sections.php

<?
if ($_REQUEST["action"]=="ADD_TO_COMPARE_LIST" || $_REQUEST["action"]=="DELETE_FROM_COMPARE_LIST") {
 $APPLICATION->RestartBuffer();
 if ($arParams["USE_COMPARE"]=="Y") {
 $APPLICATION->IncludeComponent(
 "bitrix:catalog.compare.list",
 "",
 array(
 "IBLOCK_TYPE" => $arParams["IBLOCK_TYPE"],
 "IBLOCK_ID" => $arParams["IBLOCK_ID"],
 "NAME" => $arParams["COMPARE_NAME"],
 "DETAIL_URL" => $arResult["FOLDER"].$arResult["URL_TEMPLATES"]["element"],
 "COMPARE_URL" => $arResult["FOLDER"].$arResult["URL_TEMPLATES"]["compare"],

 ),
 $component
 );
 }
 die();
}
?>
_______________________________________________________________

AJAX избранное

header.php

<script>
 var SITE_DIR = '<?=SITE_DIR?>';
 var DELAY_LIST = new Object();
</script>

template.php

В начало
<?ob_start();?>
В конец
<?
$this->__component->arResult["CACHED_TPL"] = @ob_get_contents();
ob_get_clean();
?>
Маркер
<? echo "#COMPARE_FAV_ID_".$arItem['ID']."#"; ?>

component_epilog.php

<?
echo preg_replace_callback(
 "/#COMPARE_FAV_ID_([\\d]+)#/is".BX_UTF_PCRE_MODIFIER,
 create_function('$matches', 'ob_start();
 ?>
 <? global $favourites; ?>
 <a href="#" class="b-popular-tiles__fav btn-fav add-delay<?
 if (in_array($matches[1], $favourites)):
 ?> btn-fav_active js-check_checked<?
 endif;
 ?>" data-id="<?=$matches[1]?>">
 <i class="icon png-icons btn-fav__ico"></i>
 <span class="add-delay__ttl">
 <?if (in_array($matches[1], $favourites)):?>
 В избранном
 <?else:?>
 В избранное
 <?endif?>
 </span>
 </a>
 <?
 $returnStr = @ob_get_contents();
 ob_get_clean();
 return $returnStr;'),
$arResult["CACHED_TPL"]);
?>

result_modifier.php

<?if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true)die();?>
<?$this->__component->SetResultCacheKeys(array("CACHED_TPL"));?>

script.js

<script>

 $('body').on('click', '.add-delay', function(e){
 e.preventDefault();

 var delayButton = $(this),
 product_id = delayButton.data('id'),
 productPrice = parseFloat(delayButton.parents('.product-item').find('.cur-price').text().replace(/ /g,''));

 if (DELAY_LIST[product_id]) {
 delayButton.removeClass('btn-fav_active js-check_checked').find('.add-delay__ttl').html('В избранное');
 $.post(SITE_DIR + 'ajax/addDelay.php?action=DELAY_DELETE&id=' + product_id);
 delete DELAY_LIST[product_id];
 } else {
 delayButton.addClass('btn-fav_active js-check_checked').find('.add-delay__ttl').html('В избранном');
 $.post(SITE_DIR + 'ajax/addDelay.php?action=DELAY_ADD&id=' + product_id + '&PRICE=' + productPrice);
 DELAY_LIST[product_id] = true;
 }

 $('#head-favourite__info').html(Object.keys(DELAY_LIST).length);
 });

</script>

ajax/addDelay.php

<? 
require_once($_SERVER["DOCUMENT_ROOT"] . "/bitrix/modules/main/include/prolog_before.php");

if (CModule::IncludeModule("sale") && CModule::IncludeModule("catalog") && CModule::IncludeModule("iblock")) {

 $productID = htmlspecialchars($_REQUEST["id"]);
 $productPrice = htmlspecialchars($_REQUEST["PRICE"]);

 if ($_REQUEST['action'] == 'DELAY_ADD') {
 $res = CIBlockElement::GetList(Array(), array("ID" => $productID), false, Array(), array("NAME"));
 if ($ob = $res->Fetch())
 $name = $ob['NAME'];

 // $ar_res = CPrice::GetBasePrice($productID);

 $arFields = array(
 "PRODUCT_ID" => $productID,
 "PRICE" => $productPrice,
 "CURRENCY" => 'RUB',
 // "PRICE" => $ar_res["PRICE"], 
 // "CURRENCY" => $ar_res["CURRENCY"],
 "QUANTITY" => 1,
 "LID" => LANG,
 "DELAY" => "Y",
 "NAME" => $name,
 );

 CSaleBasket::Add($arFields);
 }

 if ($_REQUEST['action'] == 'DELAY_DELETE') {
 $arFilter = array(
 "FUSER_ID" => CSaleBasket::GetBasketUserID(),
 "LID" => SITE_ID,
 "ORDER_ID" => "NULL",
 "DELAY" => "Y",
 "PRODUCT_ID" => $productID,
 );

 $dbBasketItems = CSaleBasket::GetList(array(), $arFilter, false, false, array("ID"));
 if ($arItems = $dbBasketItems->Fetch()) {
 CSaleBasket::Delete($arItems['ID']);
 }
 }

 $cntDelay = array();
 $dbBasketItems = CSaleBasket::GetList(array(), array("FUSER_ID" => CSaleBasket::GetBasketUserID(), "LID" => SITE_ID, "ORDER_ID" => "NULL", "DELAY" => "Y"), false, false, array("ID"));
 while ($arItems = $dbBasketItems->Fetch()) {
 $cntDelay[] = $arItems;
 }

 echo count($cntDelay);

}
?>
_______________________________________________________________

Добавление доп свойств к заказу

catalog.element script.js
<script>
function getServices(){
 var services = 'получаем свойства';
 return services;
}

window.JCCatalogElement.prototype.SendToBasket = function()
{
 if (!this.canBuy)
 return;

 this.InitBasketUrl();
 this.FillBasketProps();

 /* доп свойства */
 this.basketParams.addServices = getServices();

 BX.ajax.loadJSON(
 this.basketUrl,
 this.basketParams,
 BX.proxy(this.BasketResult, this)
 );

};
</script>

init.php

<?
AddEventHandler("sale", "OnOrderNewSendEmail", "bxModifySaleMails");
function bxModifySaleMails($orderID, &$eventName, &$arFields)
{

 $additional_information = '';

 $cntBasketItems = CSaleBasket::GetList(
 array(
 "NAME" => "ASC",
 "ID" => "ASC"
 ),
 array(
 "ORDER_ID" => $orderID
 ), 
 false,
 false,
 array()
 );

 $itemIds = array();
 $itemNames = array();

 while ($arItems = $cntBasketItems->Fetch()){
 $itemIds[] = $arItems["ID"];
 $itemNames[$arItems["ID"]] = $arItems["NAME"];
 }
 
 if(!empty($itemIds)) $additional_information .= "Дополнительные услуги:<br>";

 $db_res = CSaleBasket::GetPropsList(
 array(),
 array("ORDER_ID" => $orderID, "BASKET_ID"=>$itemIds,"CODE"=>"ST_ADD_SERV")
 );

 while ($ar_res = $db_res->Fetch()) {

 $additional_information .= $itemNames[$ar_res["BASKET_ID"]]." : ".$ar_res["VALUE"]."<br>";

 }

 $arFields["ADDITIONAL_INFORMATION"] = $additional_information;

 $arOrder = CSaleOrder::GetByID($orderID);
 $order_props = CSaleOrderPropsValue::GetOrderProps($orderID);
 
 $full_address = "";

 while ($arProps = $order_props->Fetch()){
 if ($arProps["CODE"] == "COMPANY") $company = htmlspecialchars($arProps["VALUE"]);

 if ($arProps["CODE"] == "EMAIL") $email = htmlspecialchars($arProps["VALUE"]);

 if ($arProps["CODE"] == "PHONE") $phone = htmlspecialchars($arProps["VALUE"]);

 if ($arProps["CODE"] == "LOCATION") {
 $arLocs = CSaleLocation::GetByID($arProps["VALUE"]);
 if($arLocs["COUNTRY_NAME_ORIG"]) $full_address .= $arLocs["COUNTRY_NAME_ORIG"];
 if($arLocs["REGION_NAME_ORIG"]) $full_address .= ", ".$arLocs["REGION_NAME_ORIG"];
 //if($arLocs["CITY_NAME_ORIG"]) $full_address .= ", ".$arLocs["CITY_NAME_ORIG"];

 $parameters = array();
 $parameters['filter']['=CODE'] = $arLocs["CODE"];
 $parameters['filter']['NAME.LANGUAGE_ID'] = "ru";
 $parameters['limit'] = 1;
 $parameters['select'] = array('LNAME' => 'NAME.NAME');
 $arVal = Bitrix\\Sale\\Location\\LocationTable::getList( $parameters )->fetch();
 if($arVal[ 'LNAME' ]) $full_address .= ", ".$arVal[ 'LNAME' ];
 }

 if ($arProps["CODE"] == "ADDRESS") $address = $arProps["VALUE"];

 if ($arProps["CODE"] == "REQUISITES") {
 $requisites = "";
 if (!empty($arProps["VALUE"])) {
 $files = explode(", ",$arProps["VALUE"]);
 foreach ($files as $file) {
 $requisites .= "<a href='".SITE_SERVER_NAME.CFile::GetPath($file)."'>Скачать</a><br>";
 }
 }
 }
 }

 // тип плательщика
 $db_ptype = CSalePersonType::GetList(Array("SORT" => "ASC"), Array("LID"=>SITE_ID));
 while ($ptype = $db_ptype->Fetch())
 if($ptype["ID"]==$arOrder["PERSON_TYPE_ID"]) $personType = $ptype["NAME"];

 // название службы доставки
 $arDeliv = CSaleDelivery::GetByID($arOrder["DELIVERY_ID"]);
 if ($arDeliv) $delivery_name = $arDeliv["NAME"];

 // название платежной системы 
 $arPaySystem = CSalePaySystem::GetByID($arOrder["PAY_SYSTEM_ID"]);
 if ($arPaySystem) $pay_system_name = $arPaySystem["NAME"];

 // добавляем новые поля в массив результатов
 $arFields["ORDER_DESCRIPTION"] = "Комментарий: ".$arOrder["USER_DESCRIPTION"]."<br>";
 $arFields["ORDER_P_TYPE"] = "Тип плательщика: ".$personType."<br>";
 $arFields["ORDER_PHONE"] = "Телефон: ".$phone."<br>";
 $arFields["ORDER_EMAIL"] = "E-mail: ".$email."<br>";
 $arFields["DELIVERY_NAME"] = "Доставка: ".$delivery_name."<br>";
 $arFields["PAY_SYSTEM_NAME"] = "Оплата: ".$pay_system_name."<br>";
 $arFields["ADDRESS"] = "Адрес доставки: ".$address."<br>";
 $arFields["FULL_ADDRESS"] = "Местоположение: ".$full_address."<br>";
 $arFields["COMPANY"] = "Компания: ".$company."<br>";
 $arFields["REQUISITES"] = "Реквизиты: ".$requisites."<br>";
}
?>

в старых версиях создаем новый компонент
/bitrix/components/site-hit/catalog.element/component.php

<?
if ($successfulAdd) {
 if ($_REQUEST["addServices"]) {
 $product_properties[] = array(
 "NAME" => "Дополнительные услуги",
 "CODE" => "ST_ADD_SERV",
 "VALUE" => $_REQUEST["addServices"],
 "SORT" => "1000"
 );
 }
 if (!Add2BasketByProductID($productID, $QUANTITY, $arRewriteFields, $product_properties)) {
 if ($ex = $APPLICATION->GetException())
 $strError = $ex->GetString();
 else
 $strError = GetMessage("CATALOG_ERROR2BASKET");
 $successfulAdd = false;
 }
}
?>

в новых версиях создаем новый компонент и наследуем от /bitrix/modules/iblock/lib/component/base.php

class CatalogElementComponent extends Element

<?
 protected function addProductToBasket($productId, $action)
 {
 /** @global \\CMain $APPLICATION */
 global $APPLICATION;

 $successfulAdd = true;
 $errorMsg = '';

 $quantity = 0;
 $productProperties = array();
 $iblockId = (int)\\CIBlockElement::GetIBlockByID($productId);

 if ($iblockId > 0)
 {
 $productCatalogInfo = \\CCatalogSku::GetInfoByIBlock($iblockId);
 if (!empty($productCatalogInfo) && $productCatalogInfo['CATALOG_TYPE'] == \\CCatalogSku::TYPE_PRODUCT)
 {
 $productCatalogInfo = false;
 }
 if (!empty($productCatalogInfo))
 {
 if ($this->arParams['ADD_PROPERTIES_TO_BASKET'] === 'Y')
 {
 $productIblockId = ($productCatalogInfo['CATALOG_TYPE'] == \\CCatalogSku::TYPE_CATALOG
 ? $productCatalogInfo['IBLOCK_ID']
 : $productCatalogInfo['PRODUCT_IBLOCK_ID']
 );
 $iblockParams = $this->storage['IBLOCK_PARAMS'][$productIblockId];
 if ($productCatalogInfo['CATALOG_TYPE'] !== \\CCatalogSku::TYPE_OFFERS)
 {
 if (!empty($iblockParams['CART_PROPERTIES']))
 {
 $productPropsVar = $this->request->get($this->arParams['PRODUCT_PROPS_VARIABLE']);
 if (is_array($productPropsVar))
 {
 $productProperties = \\CIBlockPriceTools::CheckProductProperties(
 $productIblockId,
 $productId,
 $iblockParams['CART_PROPERTIES'],
 $productPropsVar,
 $this->arParams['PARTIAL_PRODUCT_PROPERTIES'] === 'Y'
 );
 if (!is_array($productProperties))
 {
 $errorMsg = Loc::getMessage('CATALOG_PARTIAL_BASKET_PROPERTIES_ERROR');
 $successfulAdd = false;
 }
 }
 else
 {
 $errorMsg = Loc::getMessage('CATALOG_EMPTY_BASKET_PROPERTIES_ERROR');
 $successfulAdd = false;
 }
 }
 }
 else
 {
 $skuAddProps = $this->request->get('basket_props') ?: '';
 if (!empty($iblockParams['OFFERS_CART_PROPERTIES']) || !empty($skuAddProps))
 {
 $productProperties = \\CIBlockPriceTools::GetOfferProperties(
 $productId,
 $productIblockId,
 $iblockParams['OFFERS_CART_PROPERTIES'],
 $skuAddProps
 );
 }
 }
 }
 }
 else
 {
 $errorMsg = Loc::getMessage('CATALOG_PRODUCT_NOT_FOUND');
 $successfulAdd = false;
 }

 if ($this->arParams['USE_PRODUCT_QUANTITY'])
 {
 $quantity = (float)$this->request->get($this->arParams['PRODUCT_QUANTITY_VARIABLE']);
 }

 if ($quantity <= 0)
 {
 $ratioIterator = \\CCatalogMeasureRatio::getList(
 array(),
 array('PRODUCT_ID' => $productId),
 false,
 false,
 array('PRODUCT_ID', 'RATIO')
 );
 if ($ratio = $ratioIterator->Fetch())
 {
 $intRatio = (int)$ratio['RATIO'];
 $floatRatio = (float)$ratio['RATIO'];
 $quantity = $floatRatio > $intRatio ? $floatRatio : $intRatio;
 }
 }

 if ($quantity <= 0)
 {
 $quantity = 1;
 }
 }
 else
 {
 $errorMsg = Loc::getMessage('CATALOG_PRODUCT_NOT_FOUND');
 $successfulAdd = false;
 }

 $rewriteFields = $this->getRewriteFields($action);

 if ($successfulAdd)
 {
 /* */
 if($_REQUEST["optionsprice"]){
 $productProperties[] = array(
 "NAME" => "Сумма дополнителных опций (за ед.товара)",
 "CODE" => "PICKED_OPTIONS_PRICE",
 "VALUE" => $_REQUEST["optionsprice"]." руб.",
 "SORT" => "1000"
 );
 }
 if($_REQUEST["edge"] && $_REQUEST["edgeprice"]){
 $productProperties[] = array(
 "NAME" => "Обработка края",
 "CODE" => "PICKED_EDGE",
 "VALUE" => $_REQUEST["edge"],
 "SORT" => "1100"
 );
 }
 if($_REQUEST["edges"] && $_REQUEST["edgesprice"]){
 $productProperties[] = array(
 "NAME" => "Отстрочка края",
 "CODE" => "PICKED_EDGES",
 "VALUE" => $_REQUEST["edges"],
 "SORT" => "1200"
 );
 }
 if($_REQUEST["bracing"] && $_REQUEST["bracingprice"]){
 $productProperties[] = array(
 "NAME" => "Крепления",
 "CODE" => "PICKED_BRACING",
 "VALUE" => $_REQUEST["bracing"],
 "SORT" => "1300"
 );
 }
 if($_REQUEST["logo"] && $_REQUEST["logoprice"]){
 $productProperties[] = array(
 "NAME" => "Логотип",
 "CODE" => "PICKED_LOGO",
 "VALUE" => $_REQUEST["logo"],
 "SORT" => "1400"
 );
 }
 if($_REQUEST["extra"] && $_REQUEST["extraprice"]){
 $productProperties[] = array(
 "NAME" => "Дополнительно",
 "CODE" => "PICKED_EXTRA",
 "VALUE" => $_REQUEST["extra"],
 "SORT" => "1500"
 );
 }
 /* */

 if (!Add2BasketByProductID($productId, $quantity, $rewriteFields, $productProperties))
 {
 if ($ex = $APPLICATION->GetException())
 {
 $errorMsg = $ex->GetString();
 }
 else
 {
 $errorMsg = Loc::getMessage('CATALOG_ERROR2BASKET');
 }

 $successfulAdd = false;
 }
 }

 return array($successfulAdd, $errorMsg);
 }
?>
_______________________________________________________________

Добавление наценки в корзине (пример с добавлением суммы из выбранных свойств товара)

<?
\\Bitrix\\Main\\EventManager::getInstance()->addEventHandler( 
 'sale', 
 'OnBeforeSaleBasketItemSetField', 
 'changePrice' 
);

function changePrice(\\Bitrix\\Main\\Event $event) 
{ 
 $name = $event->getParameter('NAME'); 
 $value = $event->getParameter('VALUE'); 
 $item = $event->getParameter('ENTITY');

 if ($name === 'PRICE') { 
 $basketPropertyCollection = \\Bitrix\\Sale\\BasketPropertiesCollection::load($item);
 $basketId = $basketPropertyCollection->getBasketId();
 $db_res = CSaleBasket::GetPropsList(
 array(
 "SORT" => "ASC",
 "NAME" => "ASC"
 ),
 array("BASKET_ID" => $basketId)
 );
 while ($ar_res = $db_res->Fetch()) {
 if ($ar_res["CODE"] == "PICKED_OPTIONS_PRICE") $value += floatval($ar_res["VALUE"]);
 }
 $event->addResult( 
 new \\Bitrix\\Main\\EventResult( 
 \\Bitrix\\Main\\EventResult::SUCCESS, array('VALUE' => $value) 
 ) 
 ); 
 }
}
?>
_______________________________________________________________

PHP 7

1) Меняем версию на хостинге
2) Меняем mod_php5.c в .htaccess

3) /bitrix/php_interface/dbconn.php

define("BX_USE_MYSQLI", true);
4) /bitrix/.settings.php 
className: 'className' => '\\\\Bitrix\\\\Main\\\\DB\\\\MysqliConnection',
...
'handled_errors_types' => 4437,
'exception_errors_types' => 4437,
5) на сервере отключить вывод E_DEPRECATED

_______________________________________________________________

Логи

dbconn.php

define("LOG_FILENAME", $_SERVER["DOCUMENT_ROOT"]."/log.txt");

AddMessage2Log("Сообщение");
_______________________________________________________________

Список сработавших почтовых событий

(Настройки → Инструменты → SQL-запрос)

select * from b_event 
 where event_name like '%form%' 
 order by date_insert desc

Выставить права на папки и файлы Битрикс SSH
// Переходим в нужную директорию
cd ~/www
// Установка прав для папок
find . -type d -exec chmod 775 {} \;
// Установка прав для файлов
find . -type f -exec chmod 664 {} \;

// Если необходимо изменить владельца группы 
find . -type d -exec chown bitrix:bitrix {} \;
find . -type f -exec chown bitrix:bitrix {} \;

Добавляем пользовательское поле TEXT/HTML в 1С-Битрикс
До сих пор в Битриксе нет пользовательского свойства с HTML кодом (визуальным редактором). Устраняем это досадное недоразумение. 
 На просторах интернета быстро нашлось решение, правда сильно устаревшее, немного пришлось допилить напильником, и теперь всё работает. 
 Данный код необходимо вставить в init.php вашего сайта на Битриксе. Решение поддерживает PHP8. 
 //выводим пользовательское HTML поле в свойствах разделов
AddEventHandler('main', 'OnUserTypeBuildList', array('CUserTypeSectionsHtmlField', 'GetUserTypeDescription'), 5000);

class CUserTypeSectionsHtmlField {

 public static function GetUserTypeDescription() {
 return array(
 // уникальный идентификатор
 'USER_TYPE_ID' => 'sections_html_field',
 // имя класса, методы которого формируют поведение типа
 'CLASS_NAME' => 'CUserTypeSectionsHtmlField',
 // название для показа в списке типов пользовательских свойств
 'DESCRIPTION' => 'HTML/text',
 // базовый тип на котором будут основаны операции фильтра
 'BASE_TYPE' => 'string',
 );
 }

 public static function GetDBColumnType($arUserField) {
 switch (strtolower($GLOBALS['DB']->type)) {
 case 'mysql':
 return 'text';
 break;
 }
 }

 public static function GetSettingsHTML($arUserField = false, $arHtmlControl, $bVarsFromForm) {
 $result = '';

 return $result;
 }

 public static function CheckFields($arUserField, $value) {
 $aMsg = array();
 return $aMsg;
 }

 public static function GetEditFormHTML($arUserField, $arHtmlControl) {
 if ($arUserField["ENTITY_VALUE_ID"] < 1 && strlen($arUserField["SETTINGS"]["DEFAULT_VALUE"]) > 0)
 $arHtmlControl["VALUE"] = htmlspecialchars($arUserField["SETTINGS"]["DEFAULT_VALUE"]);
 ob_start();
 CFileMan::AddHTMLEditorFrame($arHtmlControl["NAME"], $arHtmlControl["VALUE"], "html", "html", 200, "N", 0, "", "", "s1");
 $b = ob_get_clean();
 return $b;
 }

 public static function GetEditFormHTMLMulty($arUserField, $arHtmlControl) {
 $html = 'Поле не может быть множественным!';
 return $html;
 }

 public static function GetFilterHTML($arUserField, $arHtmlControl) {
 $sVal = intval($arHtmlControl['VALUE']);
 $sVal = $sVal > 0 ? $sVal : '';

 return CUserTypeSectionsHtmlField::GetEditFormHTML($arUserField, $arHtmlControl);
 }

 public static function GetAdminListViewHTML($arUserField, $arHtmlControl) {
 return '';
 }

 public static function GetAdminListViewHTMLMulty($arUserField, $arHtmlControl) {
 return '';
 }

 public static function GetAdminListEditHTML($arUserField, $arHtmlControl) {
 return '';
 }

 public static function GetAdminListEditHTMLMulty($arUserField, $arHtmlControl) {
 return '';
 }

 public static function onsearchIndex($arUserField) {
 return '';
 }

 public static function OnBeforeSave($arUserField, $value) {
 return $value;
 }
}
 
 Теперь в пользовательских типах у вас появится Text/HTML