Вход / Регистрация 0
г. Красноярск
Дубровинского 110, оф. 503

Памятка разработчику

пользовательское поле типа "цвет"

В init.php вставляем следующий код:


// расширим свой класс от числового типа
class UserDataColor extends CUserTypeInteger
{
 
 // инициализация пользовательского свойства для главного модуля
 function GetUserTypeDescription()
 {
 return array(
 "USER_TYPE_ID" => "color",
 "CLASS_NAME" => "UserDataColor",
 "DESCRIPTION" => "Цвет",
 "BASE_TYPE" => "int",
 );
 }
 
 // инициализация пользовательского свойства для инфоблока
 function GetIBlockPropertyDescription()
 {
 return array(
 "PROPERTY_TYPE" => "S",
 "USER_TYPE" => "color",
      "DESCRIPTION" => "Цвет",
      'GetPropertyFieldHtml' => array('UserDataColor', 'GetPropertyFieldHtml'),
      'GetAdminListViewHTML' => array('UserDataColor', 'GetAdminListViewHTML')
     );
 }
 
 // представление свойства
 function getViewHTML($name, $value)
 {
 return '<div style="display: block; width: 16px; height: 16px; background-color: #'.str_pad(dechex($value), 6, '0', STR_PAD_LEFT).';"> </div>';
 }
 
 // редактирование свойства
 function getEditHTML($name, $value, $is_ajax = false)
 {
 $uid = 'x'.uniqid();
 $dom_id = $uid;
 $colorHex = str_pad(dechex($value), 6, '0', STR_PAD_LEFT);
 $colorRGB = array();
 $colorRGB[0] = hexdec(substr($colorHex, -6, 2));
 $colorRGB[1] = hexdec(substr($colorHex, -4, 2));
 $colorRGB[2] = hexdec(substr($colorHex, -2, 2));
 $init = $is_ajax ? 'init();' : '$(init);';
return '
 <input type="hidden" id="'.$dom_id.'" name="'.$name.'" value="'.$value.'">
 <link rel="stylesheet" type="text/css" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/base/jquery-ui.css">
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
 <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.21/jquery-ui.min.js"></script>
 <style>
 #red'.$uid.', #green'.$uid.', #blue'.$uid.' {float: left; clear: left; width: 300px; margin: 15px;}
 #swatch'.$uid.' {width: 120px; height: 100px; margin-top: 18px; margin-left: 350px; background-image: none;}
 #red'.$uid.' .ui-slider-range, #red'.$uid.' .ui-slider-handle { background: #ef2929; }
 #green'.$uid.' .ui-slider-range, #green'.$uid.' .ui-slider-handle { background: #8ae234; }
 #blue'.$uid.' .ui-slider-range, #blue'.$uid.' .ui-slider-handle { background: #729fcf; }
 </style>
 <div>
 <div id="red'.$uid.'"></div>
 <div id="green'.$uid.'"></div>
 <div id="blue'.$uid.'"></div>
 <div id="swatch'.$uid.'" class="ui-widget-content ui-corner-all"></div>
 </div>
 <script>
 (function(){
 function hexFromRGB(r, g, b) {
 var hex = [
 r.toString( 16 ),
 g.toString( 16 ),
 b.toString( 16 )
 ];
 $.each( hex, function( nr, val ) {
 if ( val.length === 1 ) {
 hex[ nr ] = "0" + val;
 }
 });
 return hex.join( "" ).toUpperCase();
 }
 function refreshSwatch() {
 var red = $( "#red'.$uid.'" ).slider( "value" ),
 green = $( "#green'.$uid.'" ).slider( "value" ),
 blue = $( "#blue'.$uid.'" ).slider( "value" ),
 hex = hexFromRGB( red, green, blue );
 $( "#'.$dom_id.'" ).val(red*256*256+green*256+blue);
 $( "#swatch'.$uid.'" ).css( "background-color", "#" + hex );
 }
 var init = function() {
 $( "#red'.$uid.', #green'.$uid.', #blue'.$uid.'" ).slider({
 orientation: "horizontal",
 range: "min",
 max: 255,
 value: 0,
 slide: refreshSwatch,
 change: refreshSwatch
 });
 $( "#red'.$uid.'" ).slider( "value", '.$colorRGB[0].' );
 $( "#green'.$uid.'" ).slider( "value", '.$colorRGB[1].' );
 $( "#blue'.$uid.'" ).slider( "value", '.$colorRGB[2].' );
 };
 '.$init.'
 })();
 </script>
 ';
 }
 
 // редактирование свойства в форме (главный модуль)
 function GetEditFormHTML($arUserField, $arHtmlControl)
 {
 return self::getEditHTML($arHtmlControl['NAME'], $arHtmlControl['VALUE'], false);
 }
 
 // редактирование свойства в списке (главный модуль)
 function GetAdminListEditHTML($arUserField, $arHtmlControl)
 {
 return self::getViewHTML($arHtmlControl['NAME'], $arHtmlControl['VALUE'], true);
 }
 
 // представление свойства в списке (главный модуль, инфоблок)
function GetAdminListViewHTML($arProperty, $value)
 {
return self::getViewHTML('dddd', $value['VALUE']);
 }
 
 // редактирование свойства в форме и списке (инфоблок)
 function GetPropertyFieldHtml($arProperty, $value, $strHTMLControlName)
 {
 return $strHTMLControlName['MODE'] == 'FORM_FILL'
 ? self::getEditHTML($strHTMLControlName['VALUE'], $value['VALUE'], false)
 : self::getViewHTML($strHTMLControlName['VALUE'], $value['VALUE'])
 ;
 }
 
}
// добавляем тип для инфоблока
AddEventHandler("iblock", "OnIBlockPropertyBuildList", array("UserDataColor", "GetIBlockPropertyDescription"));
// добавляем тип для главного модуля
AddEventHandler("main", "OnUserTypeBuildList", array("UserDataColor", "GetUserTypeDescription"));

На странице "/bitrix/admin/userfield_admin.php?lang=ru" появится новое поле типа "цвет".
Спасибо https://bad-code.ru/sozdanie-novogo-tipa-ili-kastomizatsiya-polzovatelskogo-polya-v-1s-bitrix/

Настройка git на серверах хостинга timeweb-а

Сначала необходимо создать RSA-ключи для обмена, так как гит не умеет обмениваться паролями.
Эта операция делается один раз, далее можно заводить сколько угодно репозиториев и пользоваться одним ключом для всех.

Открываем документацию таймвеб (http://timeweb.com/ru/community/articles/kak-nastroit-ssh-klyuchi-i-kodovuyu-frazu-dlya-servera-1) и делаем всё как там написано, четвёртый шаг выполнять необязательно.
После этого выполните команду

git config receive.denyCurrentBranch ignore

Следующий шаг - открываем статью по настройке гит: (https://github.com/eveness/git-and-timeweb) и пошагово выполяем все действия из этой статьи.

На всякий случай:

Так как на тарифах виртуального хостинга Timeweb нет возможности добавить иной SSH-доступ, кроме основного, то работа в пределах такого тарифа возможна только под одним юзером.
Для начала необходимо включить SSH-доступ, для чего требуется привязка телефона с подтверждением SMS-кодом.
Заходим на сервер, где <user> соответственно логин, а <server> хост, который можно узнать в панели управления:
ssh <user>@<server>.timeweb.ru
Заходим в папку проекта, для примера my-site, и инициализируем там репозиторий:
cd my-site
git init
Добавляем в конфиг свою почту и имя пользователя (если до этого не было):
git config --global user.name "John Doe"
git config --global user.email johndoe@example.com
Посмотреть настройки можно командой:
git config --list
Добавляем какой-нибудь файл, например .gitignore, коммитим:
git add .
git commit -m "init"
Создаем в корне папку git и переходим в нее:
cd ~
mkdir git
cd git
Тут инициализируем bare-репозиторий:
git clone --bare ../my-site my-site.git
Возвращаемся в папку проекта и добавляем туда:
cd ~/my-site
git remote add shared ../git/my-site.git
Добавляем хук post-update в bare-репозиторий:
cd ~/git/my-site.git/hooks
С содержимым:
#!/bin/sh
cd /home/u/user/my-site || exit
unset GIT_DIR
git pull shared master
exec git-update-server-info
Где /u/user/ - это первая буква логина и сам логин. Даем права на запуск:
chmod +x post-update
Добавляем хук post-commit в репозиторий проекта:
cd ~/my-site/.git/hooks
С содержимым:
#!/bin/sh
git push shared
Даем права на запуск:
chmod +x post-commit
Возвращаемся в папку проекта:
cd ~/my-site
И пушимся:
git push --set-upstream shared master
Локально добавлеям удаленный репозиторий и обновляемся:
git remote add origin ssh://<user>@<server>.timeweb.ru/home/<u>/<user>/git/my-site.git
git pull origin master
Примечание:
в случае работы с IDE JetBrains PhpStorm/WebStorm достаточно:
а) в стартовом окне выбрать Checkout from Version Control -> Git
б) в произвольном открытом проекте в верхнем меню выбрать VCS -> Checkout from Version Control -> Git
и в поле Git Repository URL ввести:
ssh://<user>@<server>.timeweb.ru/home/<u>/<user>/git/my-site.git
После запуска проекта пулить сразу уже не требуется.
Работаем как и с обычным репозиторием. Конец, успех.
Единственное что:
команду

git remote add origin ssh://<user>@<server>.timeweb.ru/home/<u>/<user>/git/my-site.git

выполнить не получилось, вместо неё надо выполнить

git clone ssh://<user>@<server>.timeweb.ru/home/<u>/<user>/git/my-site.git
Не забудьте указать локально конфиг:
git config --global user.name "John Doe"
git config --global user.email johndoe@example.com
Со своими данными.

Если хуки правим/создаём в редакторе под windows - то формат конца строки должен быть LF
В notepad++: Правка-Формат конца строк-Преобразовать в UNIX формат (LF) (Edit -> EOL Conversion -> Unix (LF))

Таблица пользователей в связке с инфоблоком

 \Bitrix\Main\Loader::IncludeModule('iblock');         
         $result = \Bitrix\Main\UserTable::getList(array(
            'select' => array(
               'ID','NAME', 'SECOND_NAME', 'LAST_NAME',
               'PERSONAL_COUNTRY', 'PERSONAL_STATE', 'PERSONAL_CITY', 'PERSONAL_STREET', 'PERSONAL_PHOTO',
               'UF_COMPANY_ID', 'UF_SUBCOMPANY_ID', 'KO.NAME', 'KP.NAME'
               
               
               ),
            'filter' => array('ID'=>$user_id),
            'limit' => 1,
            'runtime'=>array(
               'KO' => array(
                  'data_type' => '\Bitrix\Iblock\ElementTable',
                  'reference' => array('=this.UF_COMPANY_ID' => 'ref.ID'),
                  'join_type' => 'LEFT'
               ),
               'KP' => array(
                  'data_type' => '\Bitrix\Iblock\ElementTable',
                  'reference' => array('=this.UF_SUBCOMPANY_ID' => 'ref.ID'),
                  'join_type' => 'LEFT'
               )
            )

Комплексный компонент с уровнем вложенности 5

Заготовка комплексного компонента с уровнем вложенности 5.
typecatalog.zip (8.71 КБ)

Кастомизация умного фильтра

1. Копируем штатный шаблон нужного нам формата (горизонтальный, вертикальный), переименовываем.
2. Запускаем компонент с новым шаблоном, открываем страницу и смотрим html-код. Нас интересует структура блока с каким-либо свойством, копируем его. После открываем шаблон, и в любом месте добавляем свой блок с произвольным html содержимым. Получиться примерно следующее:

<div class="bx_filter_parameters_box custom_block active">
   <span class="bx_filter_container_modef"></span>
   <div class="bx_filter_parameters_box_title" data-role="prop_angle" onclick="smartFilter.hideFilterProps(this)">Произвольный раздел</div>
      <div class="bx_filter_block" data-role="bx_filter_block">
         <div class="bx_filter_parameters_box_container">
            <div class="bx-filter-parameters-box-container-block">
                     ...Здесь произвольное содержимое...
            </div>
         </div>
         <div class="clb"></div>
      </div>
</div>
Теперь у нас есть блок который органично вписывается в структуру родного шаблона. Заполняем его по своему усмотрению, можно, например, вставить туда список разделов. Обработку, естественно, пишем сами, главное не забыть чтоб на каждое изменение элементов формы в вашем блоке срабатывала конструкция вида:
smartFilter.click($(this)[0]);
Всё, теперь у вас при изменении  значений должна всплывать подсказка сколько элементов выбрано.
3. Все значения вснесённые вами в блок придут в виде request-a в компонент, чтобы туда не лезть, обработайте эти параметры на странице перед вызовом компонента умного фильтра и внесите в фильтр который будет использован этим компонентом. Внесённые вами изменения будут подхвачены и дополнены свойствами умного фильтра.
4. В шаблоне компонента замените параметр action формы с
$arResult['ACTION_FORM']
на явный путь до страницы
/filter_path/
то же самое делаем в скрипте:
BX.ajax.loadJSON(
       this.ajaxURL,
меняем на
BX.ajax.loadJSON(
            '/filter_path/',
5. Опять идём в шаблон: в самом начале формы находим код


<?foreach($arResult["HIDDEN"] as $arItem){?>
      <input type="hidden" name="<?echo $arItem["CONTROL_NAME"]?>" id="<?echo $arItem["CONTROL_ID"]?>" value="<?echo $arItem["HTML_VALUE"]?>" />
   <?}
и меняем его на
<?foreach($arResult["HIDDEN"] as $arItem){
            if(
               strpos($arItem["CONTROL_NAME"], 'custom_prop1')===false
               && strpos($arItem["CONTROL_NAME"], 'custom_prop2')===false
               && strpos($arItem["CONTROL_NAME"], 'custom_prop3')===false
               && strpos($arItem["CONTROL_NAME"], 'custom_prop4')===false
            ){?>
               <input type="hidden" name="<?echo $arItem["CONTROL_NAME"]?>" id="<?echo $arItem["CONTROL_ID"]?>" value="<?echo $arItem["HTML_VALUE"]?>" />
            <?}
         }
Дело в том что шаблон пытается запихать в скрытые поля все пришедшие в форму посторонние данные, соответственно, на странице фильтрации в форме вы получите задублированные поля в виде скрытого и внешнего, соответственно при попытке отключить какой-либо свой параметр он всё равно уйдёт в отбор, так как есть скрытое поле-двойник с тем же именем.

На это всё, ваш фильтр будет учитывать любые ваши доработки и корректно их отображать.

Подключение произвольного языкового файла

https://bxapi.ru/src/?module_id=main&name=__IncludeLang - подключение произвольного языкового файла

Отличная статья по работе с изображениями

Отличная статья по работе с изображениями:
http://www.sesmikcms.ru/pages/read/igraem-s-izobrazheniem-v-php/

Колоризатор в настройках компонента

Вывести кастомное поле с выбором цветового решения в настройках компонента.

Файл ".parameters.php":


 $arComponentParameters = array(
   "PARAMETERS" => array(
      "COLOR_SCHEME" => Array(
         "NAME" => GetMessage("SW24_BUYNOW_COLOR_SCHEME"),
         "PARENT" => "BASE",
         "TYPE"=>"CUSTOM",
         "JS_FILE" => '/bitrix/components/skyweb24/mycomponent/settings.js',
         'JS_DATA' => 'silver',
         'JS_EVENT' => 'sw24ColorSettingsEdit',
         "DEFAULT" => "silver",
         "ADDITIONAL_VALUES"=>"N"
      )
   )
);
?>
<style>
.color_block a{
   display:inline-block;
   box-sizing:border-box;
   height:30px;
   width:25%;
   border-width:2px;
   border-style:solid;
   margin-top: -3px;
}
</style>
Файл "settings.js":

function sw24ColorSettingsEdit(arParams){
   console.log(arParams);
   var colorArr={
      'turquoise':'rgb(26, 188, 156)',
      'green-sea':'rgb(22, 160, 133)',
      'emerland':'rgb(46, 204, 113)',
      'nephritis':'rgb(39, 174, 96)',
      'peter-river':'rgb(52, 152, 219)',
      'belize-hole':'rgb(41, 128, 185)',
      'amethyst':'rgb(166, 107, 190)',
      'wisteria':'rgb(142, 68, 173)',
      'wet-asphalt':'rgb(52, 73, 94)',
      'midnight-blue':'rgb(44, 62, 80)',
      'sun-flower':'rgb(241, 196, 15)',
      'orange':'rgb(243, 156, 18)',
      'carrot':'rgb(230, 126, 34)',
      'pumpkin':'rgb(211, 84, 0)',
      'alizarin':'rgb(231, 76, 60)',
      'pomegranate':'rgb(192, 57, 43)',
      'clouds':'rgb(236, 240, 241)',
      'silver':'rgb(189, 195, 199)',
      'concrete':'rgb(149, 165, 166)',
      'asbestos':'rgb(127, 140, 141)'
   };
   var colorBlock='<div class="color_block">';
   for(key in colorArr){
      var bColor=(arParams.oInput.value==key)?'red':colorArr[key];
      colorBlock+='<a href="javascript:void(0);" title="'+key+'" style="background-color:'+colorArr[key]+'; border-color:'+bColor+'"></a>';
   }
   colorBlock+='</div>';
   
   var linkBlock=arParams.oCont.appendChild(BX.create('div', {html: colorBlock}));
   var links=BX.findChild(linkBlock, {"tag" : "a"}, true, true);
   for(var i=0; i<links.length; i++){
      links[i].onclick=function(){
         console.log(this.title)
         arParams.oInput.value=this.title;
         for(var i=0; i<links.length; i++){
            links[i].style.borderColor=links[i].style.backgroundColor;
         }
         this.style.borderColor='red';
      }
   }
   
}
 

Картинка заданной пропорции

Бывает необходимо создать картинку заданных пропорций (например квадратную), а на входе картинки самых немыслимых пропорций.
У битрикса нет такого механизма:  CFile::ResizeImageFile предлагает либо обрезку до заданных пропорций - либо масштабирование.

Решение: в init.php помещаем следующую функцию:


function image_resize_square($src, $dst){
    if(!list($w, $h) = getimagesize($src)) return "Unsupported picture type!";
  
    $type = strtolower(substr(strrchr($src, "." ),1));
    if($type == 'jpeg') $type = 'jpg';
        switch($type){
        case 'bmp': $img = imagecreatefromwbmp($src); break;
        case 'gif': $img = imagecreatefromgif($src); break;
        case 'jpg': $img = imagecreatefromjpeg($src); break;
        case 'png': $img = imagecreatefrompng($src); break;
   default : return "Unsupported picture type!";
    }
                      
    $x = $y = 0;
    if($w < $h) {
   $x = $h/2 - $w/2;
   $new = imagecreatetruecolor($h, $h);
    } else {
       $y = $w/2 - $h/2;
   $new = imagecreatetruecolor($w, $w);       
    }

    $color = imagecolorallocate($new, 255, 255, 255);
    imagefill($new, 0, 0, $color);    
                                                                                                    
    imagecopyresampled($new, $img, $x, $y, 0, 0, $w, $h, $w, $h);
    
    switch($type){
        case 'bmp': imagewbmp($new, $dst); break;
   case 'gif': imagegif($new, $dst); break;
        case 'jpg': imagejpeg($new, $dst); break;
   case 'png': imagepng($new, $dst); break;
    }
    return true;
}



а в шаблоне компонента такой код:



$proportionArr=Array("width" => 220, "height" => 220);
         $renderImage=CFile::ResizeImageGet($cId, $proportionArr, BX_RESIZE_IMAGE_PROPORTIONAL, true);
         
         if($renderImage['height']!=$renderImage['width'] ){
            image_resize_square($_SERVER['DOCUMENT_ROOT'].$renderImage['src'], $_SERVER['DOCUMENT_ROOT'].$renderImage['src'] );
         }



Всё, при первом ресайзе штатными средставми получаем пропорциональную картинку, а дальше, если пропорции не подходят (в нашем случае если картинка не квадратная) - применяем высокотехнологичный костыль из PHP.

Решение взял отсюда, Большое спасибо Вдовину Алексею.

Очистка старых корзин

У посещаемых магазинов на битриксе часто накапливаются старые корзины, если посмотреть в БД - то часто видно что таблица "b_sale_fuser" имеет неприличный размер в несколько миллионов записей.
Решение: настроить крон по очистке.

<?
//for crontab
//$_SERVER["DOCUMENT_ROOT"] = realpath(dirname(__FILE__)."/../..");
//$DOCUMENT_ROOT = $_SERVER["DOCUMENT_ROOT"];

define("NO_KEEP_STATISTIC", true);
define("NOT_CHECK_PERMISSIONS",true);
define('CHK_EVENT', true);

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

CModule::IncludeModule("sale");
global $DB;

$cLimit= 10000;
$strSql = "SELECT ID FROM b_sale_fuser WHERE TO_DAYS(DATE_UPDATE)<(TO_DAYS(NOW())-30) LIMIT ".$cLimit;
$db_res = $DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__);
while ($ar_res = $db_res->Fetch()){
   CSaleBasket::DeleteAll($ar_res["ID"], false);
   CSaleUser::Delete($ar_res["ID"]);
}
echo 'end!';
?>
Необходимо положить такой скрипт куда-нибудь на сервер, настроить переменную $_SERVER["DOCUMENT_ROOT"], задать частоту вызова и переменную $cLimit (в зависимости от нагрузки магазина).

Примерный алгоритм настройки поисковых индексов для разных сайтов

Данный пример делает отдельный индекс для англоязычного сайта из общего для всех сайтов инфоблока, заменяя название и описание на текст из отдельных полей для англоязычного сайта:

function BeforeIndexHandler($arFields){
   if($arFields["MODULE_ID"] == "iblock"){
      if($arFields["PARAM2"]==4 && $arFields['SITE_ID'][1]=='s2'){
         CModule::IncludeModule("search");
         CModule::IncludeModule("iblock");
         //AddMessage2Log($arFields);
         $arFields['SITE_ID']=array('s1');
         
         $res = CIBlockElement::GetList(Array(), array('IBLOCK_ID'=>$arFields["PARAM2"], 'ID'=>$arFields["ITEM_ID"]), false, array("nPageSize"=>1), Array('IBLOCK_ID', 'ID', 'PROPERTY_NAME_ENG', 'PROPERTY_PREVIEW_TEXT_ENG', 'IBLOCK_CODE'));
         if($ob = $res->GetNext()){
            CSearch::Index(
               $ob['IBLOCK_ID'],
               $ob['ID'],
               Array(
                  "DATE_CHANGE"=>$arFields["LAST_MODIFIED"],
                  "TITLE"=>$ob['~PROPERTY_NAME_ENG_VALUE'],
                  "SITE_ID"=>array('s2'),
                  "PARAM1"=>$arFields["PARAM1"],
                  "PARAM2"=>$arFields["PARAM2"],
                  "PERMISSIONS"=>$arFields["PERMISSIONS"],
                  "URL"=>'/eng/'.$ob['IBLOCK_CODE'].'/'.$ob['ID'].'/',
                  "BODY"=>$ob['~PROPERTY_PREVIEW_TEXT_ENG_VALUE']['TEXT'],
                  "TAGS"=>$arFields["TAGS"],
               ),
               false
            );
         }
      }
   }
   return $arFields;
}
 

Свои стили в новом редакторе битрикс:

Свои стили в новом редакторе битрикс:
http://dev.1c-bitrix.ru/community/forums/forum6/topic64039/

Скрипт скрытия popup окна на jquery

function hidePopup(popupObj, arrObj, triggerClass, e){
   if(popupObj.hasClass(triggerClass)){
      
   var clickEl=$(e.target),
      hideFlag=false,
      currentNode=e.target;
      
      while(!hideFlag){
         if(currentNode.nodeName=='BODY'){hideFlag=true; break;}
         else{
            for(var i=0; i<arrObj.length; i++){
               
               if(currentNode==arrObj[i][0]){
                  return;
               }
            }
            currentNode=$(currentNode).parent()[0];
         }
      }
      if(hideFlag){
         popupObj.removeClass(triggerClass);
      }
   }
}
 

Компоненты и отложенные функции в битрикс

Рассмотрим работу отложенных функций в Битрикс на примере переноса компонента из одного места шаблона в другое.

Описанный ниже метод основан на технологии буферизации. Буферизация позволяет нам манипулировать данными, которые формируют нам php скрипты на странице (например, HTML код). Проще говоря, происходит следующее: перед тем как сервер отдаст нам сформированный html код по нашему запросу, мы с помощью определённых методов можем изменить расположение этого кода заданным образом, переместив его выше или ниже места вывода.
Этим удобно пользоваться, когда нет возможности изменить дизайн сайта подкорректировав верстку и расположение вызова компонентов напрямую. Часто это случается при использовании комплексных компонентов, которые вместе с выводом определённого контента выводят дополнительные включающие в себя компоненты.

Приведу распространенный пример использования.
Комплексный компонент битрикс каталог bitrix:catalog выводит умный фильтр над списком товаров. Многим хочется изменить такой дизайн переместив умный фильтр в привычное пользователю левое меню (к примеру). При этом компонент фильтра должен сохранить свою логику работы.
Делаем это следующим образом:
заключаем компонент умного фильтра в

 <?$this->SetViewTarget("left_sidebar");?> код компонента <?$this->EndViewTarget();?> 


а в нужном месте вывода шаблона - это может быть как выше, так и ниже места вывода фильтра, вставляем:


 <div class="left sidebar"> <?$APPLICATION->ShowViewContent("left_sidebar");?> // здесь будет выведен код умного фильтра </div> 


Способ взят отсюда.

bitrix:search.page не декодирует русский текст

Если у вас в шаблоне есть компонент "bitrix:search.title", и параметр "PAGE" у вас выглядит так:
"PAGE" => "#SITE_DIR#search/index.php",
То при переходе на страницу поиска в случае наличия кириллицы в вашей поисковой фразе вы получите сообщение что ничего не найдено и недекодированый текст в поле поиска.
Решается такая проблема исправлением вышеупомянутого параметра следующим образом:
"PAGE" => "#SITE_DIR#search/", 
То есть в конце значения должен стоять слеш.
Неочевидное решение было найдено здесь.

Позиционирование выпадающего списка для компонента bitrix:search.title

Если вы разместили компонент bitrix:search.title в блок с position:fixed, то выпадающий список компонента неправильно позиционируется.
Всё дело в том что компонент использует метод BX.pos, который может неправильно определять позицию фиксированного элемента:

Примечание: Может некорректно работать для элементов с фиксированной позицией (position: fixed) или для их дочерних элементов.
(Документация).

Теперь рецепт: выносим компонент в своё пространство имён, идём по адресу "http://ваш сайт/bitrix/components/bitrix/ bitrix:search.title"
и копируем оттуда файл script.js в наш шаблон. Внутри скрипта находиться функция JCTitleSearch.
Переименовываем эту функцию (например в JCTitleSearchForHeader), далее открываем файл template.php и заменяем
BX.ready(function(){
      new JCTitleSearch({
 
на
BX.ready(function(){
      new JCTitleSearchForHeader({
теперь идём в сам скрипт и ищём такой код:
this.adjustResultNode = function()
   {
      var pos;
      var fixedParent = BX.findParent(_this.CONTAINER, BX.is_fixed);
      if(!!fixedParent)
      {
         _this.RESULT.style.position = 'fixed';
         _this.RESULT.style.zIndex = BX.style(fixedParent, 'z-index') + 2;
         pos = BX.pos(_this.CONTAINER, true);
      }
 
меняем его на:
this.adjustResultNode = function()
   {
      var pos;
      var fixedParent = BX.findParent(_this.CONTAINER, BX.is_fixed);
      if(!!fixedParent)
      {
         _this.RESULT.style.position = 'fixed';
         _this.RESULT.style.zIndex = BX.style(fixedParent, 'z-index') + 2;
         //pos = BX.pos(_this.CONTAINER, true);
         pos = _this.CONTAINER.getBoundingClientRect();
      }
 
Всё, теперь выпадающий список работает корректно.