Ответы пользователя по тегу 1С-Битрикс
  • Почему не перенаправляет на detail.php комплексный компонент news?

    @PetrPo
    Ранее настраивал комплексный компонент, представляю что делать

    Нет, не представляешь. Почитав документацию можно было бы не задавать здесь глупые вопросы.

    Скрин 1, где SITE_DIR?
    URL страницы информационного блока: #SITE_DIR#/9-modyley/
    URL страницы детального просмотра: #SITE_DIR#/9-modyley/#ELEMENT_CODE#/

    Скрин 2, 3 ЧПУ компонента не так настраивается
    Каталог ЧПУ (относительно корня сайта): /9-modyley/
    Страница детального просмотра: #ELEMENT_CODE#/
    Ответ написан
    Комментировать
  • Как удалить товар из корзины?

    @PetrPo
    Mikhail K, Так вот продолжение.
    Вот это $item2Delete = $obBasket->getItemById($itemId) получение товара в корзине по Id записи, а не по id товара

    Если ты используешь мой код из предыдущего вопроса, то все сработает
    Bitrix\Main\Loader::includeModule('sale');
    
    $siteId = 's1';
    $fUserId = \Bitrix\Sale\FUser::getId();
    $productId = 139;
    $productByBasketItem = null;
    $bProductInBasket = false;
    
    $basket = \Bitrix\Sale\Basket::loadItemsForFUser($fUserId, $siteId);
    $basketItems = $basket->getBasketItems();
    
    if($basketItems) {
      foreach($basketItems as $basketItem) {
        if($basketItem->getField('PRODUCT_ID') == $productId) {
          $productByBasketItem = $basketItem;
          $bProductInBasket = true;
          break;
        }
      }
    }
    
    if($productByBasketItem) {
    	$productByBasketItem->delete();
    	$basket->save();
    }

    Проверки на success сам добавь
    Ответ написан
    3 комментария
  • Как сделать все товары в наличии?

    @PetrPo
    Примерно так, можно лучше запрос сделать, но на раз сойдет - этот код установит значение по умолчанию
    \Bitrix\Main\Loader::includeModule('iblock');
    \Bitrix\Main\Loader::includeModule('catalog');
    
    $iblocksId = [2, 3];
    
    $iterator = \Bitrix\Iblock\ElementTable::getList([
    	'select' => ['IBLOCK_ID', 'ID'],
    	'filter' => ['IBLOCK_ID' => $iblocksId, '!PRODUCT.CAN_BUY_ZERO' => 'D', '!PRODUCT.TYPE' => \Bitrix\Catalog\ProductTable::TYPE_SKU],
    	'runtime' => [
    		'PRODUCT' => [
    			'data_type' => '\Bitrix\Catalog\ProductTable',
    			'reference' => ['=this.ID' => 'ref.ID']
    		]
    	]
    ]);
    
    $elements = [];
    while($row = $iterator->fetch()) {
    	$elements[] = $row;
    }
    
    foreach($elements as $element) {
    	CCatalogProduct::Update($element['ID'], ['CAN_BUY_ZERO' => 'D']);	
    }
    
    echo 'Количество = '.count($elements);


    $iblocksId - id-шники инфоблоков Каталог и Торговые предложения, если торговых предложений нет, укажи только ид каталога

    Потом в ответах там скрин человек скинул, выставь настройки по умолчанию
    В компоненте каталога должен быть указан PRICE_CODE
    Ответ написан
    Комментировать
  • Существует ли товар в корзине Bitrix?

    @PetrPo
    Ждал красивого решения от битрикса? )) А вот и хрен. Чтобы получить твой \Bitrix\Sale\BasketItem $obItem придется передать все его $properties в 3-ий параметр getExistsItem, типа
    $obItem = $obBasket->getExistsItem('catalog', $productId, [
    	0 => ['CODE' => 'PROP1', 'VALUE' => 'electron'],
    	//......
    ]);

    вообще не понятно зачем этот метод public, если им хрен воспользуешься, надо знать все свойства товара в корзине, у меня это выглядело так
    $obItem = $obBasket->getExistsItem('catalog', $productId, [
    	0 => ['CODE' => 'ARTNUMBER', 'VALUE' => '235-81-03'],
    	1 => ['CODE' => 'COLOR_REF', 'VALUE' => 'Черный'],
    	2 => ['CODE' => 'SIZES_CLOTHES', 'VALUE' => 'XS'],
    	3 => ['CODE' => 'CATALOG.XML_ID', 'VALUE' => 'clothes_offers_s1'],
    	4 => ['CODE' => 'PRODUCT.XML_ID', 'VALUE' => '332#337'],
    ]);


    Вообщем решение конечно будет не таким красивым, как просто методом воспользоваться, но если метод getExistsItem посмотреть, там тоже самое делается, только еще кое-что
    \Bitrix\Main\Loader::includeModule('sale');
    
    $siteId = 's1';
    $fUserId = \Bitrix\Sale\FUser::getId();
    $productId = 139;
    $productByBasketItem = null;
    $bProductInBasket = false;
    
    $basket = \Bitrix\Sale\Basket::loadItemsForFUser($fUserId, $siteId);
    $basketItems = $basket->getBasketItems();
    
    if($basketItems) {
    	foreach($basketItems as $basketItem) {
    		if($basketItem->getField('PRODUCT_ID') == $productId) {
    			$productByBasketItem = $basketItem;
    			$bProductInBasket = true;
    			break;
    		}
    	}
    }
    
    var_dump($bProductInBasket);
    var_dump($productByBasketItem);

    В примере написал булево $bProductInBasket и записал сам объект \Bitrix\Sale\BasketItem в $productByBasketItem, там сам по ситуации выбирай как надо
    Ответ написан
    6 комментариев
  • Почему в Bitrix smart.filter начинает игнорировать PREFILTER_NAME, если выбираются фильтры, относящиеся к торговым предложениям?

    @PetrPo
    В catalog.section используется класс Bitrix\Iblock\Component\ElementList и вот в нем для гетлиста мерджится массив глобального фильтра и массив с внутренним фильтром array_merge($globalFilter, $filterFields) и вот в $filterFields тоже есть ключ =ID и при мердже он затирает твой =ID

    То есть в $prefilterCustom перед ID надо убрать =
    $prefilterCustom = array(
      "ID" => $arElements,
    );
    Ответ написан
    Комментировать
  • Как создать правило работы с корзиной через API?

    @PetrPo
    UPD заменил пример на нормальный

    Используй CSaleDiscount::Add($arFields)
    spoiler

    \Bitrix\Main\Loader::includeModule('sale');
    
    $arFields = [
        'LID' => 's1',
        'NAME' => 'Тест ядра33',
        'ACTIVE_FROM' => '',
        'ACTIVE_TO' => '',
        'ACTIVE' => 'Y',
        'SORT' => 100,
        'PRIORITY' => 1,
        'LAST_DISCOUNT' => 'Y',
        'LAST_LEVEL_DISCOUNT' => 'N',
        'XML_ID' => '',
        'CONDITIONS' => [
    		'CLASS_ID' => 'CondGroup',
    		'DATA' => [
    			'All' => 'AND',
    			'True' => 'True',
    		],
    		'CHILDREN' => [
    			0 => [
    				'CLASS_ID' => 'CondBsktProductGroup',
    				'DATA' => [
    					'Found' => 'Found',
    					'All' => 'AND',
    				],
    				'CHILDREN' => [
    					'0' => [
    						'CLASS_ID' => 'CondBsktFldProduct',
    						'DATA' => [
    							'logic' => 'Equal',
    							'value' => '92',
    						]
    					]
    				]
    			]
    		]
    	],
        'ACTIONS' => [
    		'CLASS_ID' => 'CondGroup',
    		'DATA' => [
    			'All' => 'AND',
    		],
    		'CHILDREN' => [
    			0 => [
    				'CLASS_ID' => 'ActSaleBsktGrp',
    				'DATA' => [
    					'Type' => 'Discount',
    					'Value' => 10,
    					'Unit' => 'Perc',
    					'Max' => 0,
    					'All' => 'AND',
    					'True' => 'True',
    				],
    				'CHILDREN' => []
    			]
    		]
    	],
        'USER_GROUPS' => [1]
    ];
    
    CSaleDiscount::Add($arFields);

    Ответ написан
  • Как правильно выводить UF-свойство в Битриксе?

    @PetrPo
    Проблема в том, что документацию надо внимательно читать, написано же, что этот метод
    Возвращается объект CIBlockResult. Пользовательские поля не возвращаются.

    Используй GetList.
    Обрати внимание
    для вывода пользовательских свойств обязательно должен быть передан IBLOCK_ID и в arSelect код необходимых свойств UF_XXX. Если необходимо вывести все пользовательские свойства, то в arSelect необходимо передать UF_*.
    Ответ написан
  • Можете подсказать метод АПИ для того что бы заполнить свойство заказа "тип перечисление"?

    @PetrPo
    ссылка
    ORDER_PROPS_ID, NAME и VALUE - обязательные поля

    Написано что метод нестатический, по исходникам тоже вижу что он не статический, а пример в доках статический.
    Правильно должно быть так:
    $ob = new CSaleOrderPropsVariant;
    $ob->Add($arFields);
    Ответ написан
  • Как остаться на той же странице после авторизации?

    @PetrPo
    ну типа ты же сам переход делаешь. замени window.location.href = '/personal/';
    на window.location = window.location;
    Ответ написан
    Комментировать
  • Есть ли в api битрикса ресайз фотографии под высоту и ширину?

    @PetrPo
    Первый вариант
    Делай CFile::ResizeImageGet BX_RESIZE_IMAGE_PROPORTIONAL_ALT и выставляй ширину большую, типа 10000, а высоту = 520, тогда всегда будет действовать ограничение по высоте 520
    $imageId = 1;
    
    $arImage = CFile::ResizeImageGet($imageId, array("width" => 10000, "height" => 520), BX_RESIZE_IMAGE_PROPORTIONAL_ALT, false);


    второй вариант
    могу предложить так это css
    .owl-item>div>div>a{
        position: relative;
        padding-top: 80%;
        display: block;}
    
    .owl-item>div>div>a>img{
        position: absolute;
        left: 0;
        top: 0;
        width: 100%;
        height: 100%;
        object-fit: cover}

    только от знака > избавься потом, класс какой-нибудь на ссылку повесь. И вот с этим padding-top: 80% можешь поиграть - меньше/больше поделать
    Ответ написан
    Комментировать
  • Вывод картинки со связанного свойства в битриксе?

    @PetrPo
    redesupar, держи норм код для catalog.section

    1. В result_modifier.php в конце добавь
    if($arResult['ITEMS']) {
    	$currentElement = current($arResult['ITEMS']);
    	
    	$bPropertyBrandDisplay = isset($currentElement['DISPLAY_PROPERTIES']['BRAND']) ? true : false;
    	$bPropertyBrandLink = $bPropertyBrandDisplay && $currentElement['DISPLAY_PROPERTIES']['BRAND']['LINK_IBLOCK_ID'] ? true : false;
    	
    	$brandsIblockId = $bPropertyBrandLink ? $currentElement['DISPLAY_PROPERTIES']['BRAND']['LINK_IBLOCK_ID'] : 0;
    
    	$brandsId = $brands = [];
    
    	if($bPropertyBrandDisplay && $bPropertyBrandLink) {
    		foreach($arResult['ITEMS'] as $arItem) {
    			$brandId = (int)$arItem['DISPLAY_PROPERTIES']['BRAND']['VALUE'];
    			if($brandId) {
    				$brandsId[] = $brandId;
    			}
    		}
    
    		if($brandsId) {
    			$brandsId = array_unique($brandsId);
    			$bShowBrandPicture = isset($arParams['SHOW_BRAND_PICTURE']) && $arParams['SHOW_BRAND_PICTURE'] == 'Y' ? true : false;
    
    			$order = ['ID' => 'ASC'];
    			$filter = ['IBLOCK_ID' => $brandsIblockId, 'ID' => $brandsId]; // Если надо добавляешь в фильтр активность элементов 'ACTIVE' => 'Y', 'GLOBAL_ACTIVE' => 'Y', 'ACTIVE_DATE' => 'Y'
    			$select = ['IBLOCK_ID', 'ID', 'NAME', 'DETAIL_PAGE_URL'];
    			if($bShowBrandPicture) {
    				$select = array_merge($select, ['PREVIEW_PICTURE', 'DETAIL_PICTURE']);
    			}
    			
    			$result = CIBlockElement::GetList($order, $filter, false, false, $select);
    			while($row = $result->GetNext()) {
    				$row['PICTURE'] = [];
    				
    				if($bShowBrandPicture) {
    					$pictureResize = ['width' => 120, 'height' => 40];
    					$pictureId = $row['PREVIEW_PICTURE'] ? $row['PREVIEW_PICTURE'] : $row['DETAIL_PICTURE'];
    					
    					if($pictureId) {
    						$row['PICTURE'] = CFile::ResizeImageGet($pictureId, $pictureResize, BX_RESIZE_IMAGE_PROPORTIONAL_ALT, true);
    						$row['PICTURE']['ALT'] = $row['NAME'];
    						$row['PICTURE']['TITLE'] = $row['NAME'];
    						
    						if($row['DETAIL_PICTURE']) {
    							$iProperty = new \Bitrix\Iblock\InheritedProperty\ElementValues($row['IBLOCK_ID'], $row['ID']);
    							$iPropertyValues = $iProperty->getValues();
    							
    							if($iPropertyValues['ELEMENT_DETAIL_PICTURE_FILE_TITLE'])
    							   $row['PICTURE']['TITLE'] = $iPropertyValues['ELEMENT_DETAIL_PICTURE_FILE_TITLE'];
    						   
    							if($iPropertyValues['ELEMENT_DETAIL_PICTURE_FILE_ALT'])
    							   $row['PICTURE']['ALT'] = $iPropertyValues['ELEMENT_DETAIL_PICTURE_FILE_ALT'];
    						}
    					}
    				}
    				
    				$brands[$row['ID']] = $row;
    			}
    		}
    	}
    	
    	if($brands) {
    		foreach($arResult['ITEMS'] as &$arItem) {
    			$brandId = (int)$arItem['DISPLAY_PROPERTIES']['BRAND']['VALUE'];
    			if($brandId) {
    				$arItem['BRAND_ITEM'] = $brands[$brandId];
    			}
    		}
    		
    		unset($arItem, $brands, $brandsId, $currentElement);
    	}
    }


    2. В template.php, внутри цикла по элементам
    <?if($arItem['BRAND_ITEM']):?>
    	<div class="brand">
    		<meta itemprop="brand" content="<?=$arItem['BRAND_ITEM']['NAME']?>" />
    		<?if($arItem['BRAND_ITEM']['PICTURE']):?>
    			<a class="brand_picture" href="<?=$arItem['BRAND_ITEM']['DETAIL_PAGE_URL']?>">
    				<img src="<?=$arItem['BRAND_ITEM']['PICTURE']['src'];?>" alt="<?=$arItem['BRAND_ITEM']['PICTURE']['ALT']?>" title="<?=$arItem['BRAND_ITEM']['PICTURE']['TITLE'];?>" />
    			</a>
    		<?else:?>
    			<b class="block_title"><?=GetMessage('BRAND');?>:</b>
    			<a href="<?=$arItem['BRAND_ITEM']['DETAIL_PAGE_URL']?>"><?=$arItem['BRAND_ITEM']['NAME']?></a>
    		<?endif;?>
    	</div>
    <?endif;?>


    UPD
    3. В шаблоне компонента catalog в файле section.php где вызывается catalog.section добавь
    "SHOW_BRAND_PICTURE" => $arParams["SHOW_BRAND_PICTURE"],
    Ответ написан
    2 комментария
  • Как сделать отбор элементов инфоблока по дате больше определенной?

    @PetrPo
    // чтобы получить дату в формате сайта (в битриксе)
    $date = date('Y-m-d');
    $timestamp = MakeTimeStamp($date, 'YYYY-MM-DD');
    $convertDateTime = ConvertTimeStamp($timestamp);
    
    $arFilter = Array("IBLOCK_ID"=>16, "PROPERTY_ID_VK" => false, "ACTIVE" => "Y", ">=DATE_ACTIVE_FROM" => $convertDateTime);
    Ответ написан
    Комментировать
  • Как снять одно значение множественного свойства в BITRIX по апи?

    @PetrPo
    Как задача звучит тривиально...

    Реальность:
    \Bitrix\Main\Loader::includeModule('iblock');
    
    $propertyValuesIdByXmlId = $elementPropertyValuesById = [];
    
    $iblockId = 17;
    $elementId = 176;
    $propertyCode = 'HIT';
    $deletePropertyValuesXmlId = ['NEW'];
    
    $iterator = \Bitrix\Iblock\PropertyEnumerationTable::getList([
    	'select' => ['*'],
    	'filter' => ['PROPERTY.IBLOCK_ID' => $iblockId, 'PROPERTY.CODE' => $propertyCode]
    ]);
    while($row = $iterator->fetch()) {
    	$propertyValuesIdByXmlId[$row['XML_ID']] = $row['ID'];
    }
    
    $dbRes = CIBlockElement::GetList([], ['IBLOCK_ID' => $iblockId, 'ID' => $elementId], false, false, ['IBLOCK_ID', 'ID', 'PROPERTY_'.$propertyCode]);
    while($arRes = $dbRes->Fetch()) {
    	$value = $arRes['PROPERTY_'.$propertyCode.'_VALUE'];
    	$valueId = $arRes['PROPERTY_'.$propertyCode.'_ENUM_ID'];
    	$elementPropertyValuesById[$valueId] = $value;
    }
    
    if($elementPropertyValuesById) {
    	foreach($deletePropertyValuesXmlId as $xmlId) {
    		$deletePropertyValueId = $propertyValuesIdByXmlId[$xmlId];
    		
    		if(isset($elementPropertyValuesById[$deletePropertyValueId])) {
    			unset($elementPropertyValuesById[$deletePropertyValueId]);
    		}
    	}
    
      CIBlockElement::SetPropertyValuesEx($elementId, $iblockId, [$propertyCode => array_keys($elementPropertyValuesById)]);
    }


    P.S. все подписано конечно, но если что-то непонятно, спрашивай

    UPD
    перенес CIBlockElement::SetPropertyValuesEx выше в условие
    Ответ написан
  • Как на странице товара убрать категории и подкатегории из УРЛ?

    @PetrPo
    в компоненте не правильно указан параметр детальная информация, product/#ELEMENT_CODE#/
    Ответ написан
    Комментировать
  • Как модифицировать умный фильтр?

    @PetrPo
    Вот читаю, вроде и вопрос нормальный и движешься ты в правильном направлении, и понимаешь, что надо script.js править. А в конце, посоветуйте как поправить javascript не правя javascript. Да, никак!

    У тебя javascriptофобия? )

    1. Открываешь template.php, ищешь где там вызывается new BX.Iblock.SmartFilter, над этим вызовом параметры
    $arJsParams = array(
    	"leftSlider" => 'left_slider_'.$key,
    	// .............
    
    	// добавляешь свой параметр, например step (значение = шаг)
    	"step" => 100
    );


    2. Открываешь script.js ищешь BX.Iblock.SmartFilter = (function() там внутри
    var SmartFilter = function(arParams)
    {
    	if (typeof arParams === 'object')
    	{
    		this.leftSlider = BX(arParams.leftSlider);
    		// ...........
    		
    		// где-нибудь здесь добавляешь
    		this.step = arParams.step || 1;
    	}
    };


    3. Ищешь функцию
    SmartFilter.prototype.recountMinPrice = function()
    {
    	var newMinPrice = (this.priceDiff*this.leftPercent)/100;
    	newMinPrice = (this.minPrice + newMinPrice).toFixed(this.precision);
    	
    	// добавляешь эту строку
    	newMinPrice = Math.round(newMinPrice/this.step) * this.step;
    
    	if (newMinPrice != this.minPrice)
    		this.minInput.value = newMinPrice;
    	else
    		this.minInput.value = "";
    	/** @global JCSmartFilter smartFilter */
    	smartFilter.keyup(this.minInput);
    };


    4. Ищешь функцию
    SmartFilter.prototype.recountMaxPrice = function()
    {
    	var newMaxPrice = (this.priceDiff*this.rightPercent)/100;
    	newMaxPrice = (this.maxPrice - newMaxPrice).toFixed(this.precision);
    	
    	// добавляешь эту строку
    	newMaxPrice = Math.round(newMaxPrice/this.step) * this.step;
    
    	if (newMaxPrice != this.maxPrice)
    		this.maxInput.value = newMaxPrice;
    	else
    		this.maxInput.value = "";
    	/** @global JCSmartFilter smartFilter */
    	smartFilter.keyup(this.maxInput);
    };


    P.S. в template.php есть два вызова new BX.Iblock.SmartFilter - первый = цены, второй = остальные ползунки
    Ответ написан
    Комментировать
  • Почему неработает "group" в Bitrix\Sale\PropertyValueCollection::getList?

    @PetrPo
    $inn = Bitrix\Sale\PropertyValueCollection::getList([
    	'order' => [],
    	'select' => ['VALUE', 'COUNT'],
    	'filter' => [
    		'!ORDER_ID' => false,
    		'=CODE' => 'INN'
    	],
    	'runtime' => [
    		new \Bitrix\Main\Entity\ExpressionField('COUNT', 'COUNT(*)')
    	]
    ])->fetchAll();
    Ответ написан
    Комментировать
  • Как сделать своё свойство в торговом предложении карточки товара?

    @PetrPo
    в файле result_modifier.php своего шаблона компонента catalog.element после метода
    $arParams = $component->applyTemplateModifications();


    добавить
    if($arResult['OFFERS']) {
    	$colorPropertyCode = 'COLOR_REF';
    	
    	foreach($arResult['OFFERS'] as $key => $offer) {
    		$colors = $arResult['SKU_PROPS'][$colorPropertyCode]['VALUES'];
    		$offerColorXmlId = $offer['PROPERTIES'][$colorPropertyCode]['VALUE'];
    		$offerColorImage = [];
    		
    		foreach($colors as $color) {
    			if($color['XML_ID'] == $offerColorXmlId) {
    				if(is_array($color['PICT']) && $color['PICT']['SRC']) {
    					$offerColorImage = $color['PICT'];
    				}
    				break;
    			}
    		}
    
    		if($offerColorImage) {
    			++$arResult['OFFERS'][$key]['MORE_PHOTO_COUNT'];
    			array_unshift($arResult['OFFERS'][$key]['MORE_PHOTO'], $offerColorImage);
    			
    			++$arResult['JS_OFFERS'][$key]['SLIDER_COUNT'];
    			array_unshift($arResult['JS_OFFERS'][$key]['SLIDER'], $offerColorImage);
    		}
    	}
    }


    Только вот эту строку измени $colorPropertyCode = 'COLOR_REF'; COLOR_REF - символьный код свойства цвет инфоблока торговых предложений
    Ответ написан
    1 комментарий
  • Можно ли изменить стоимость доставки?

    @PetrPo
    Тебе надо менять не стоимость доставки, а стоимость отгрузки. Как-то так:
    $eventManager = \Bitrix\Main\EventManager::getInstance();
    $eventManager->addEventHandler('sale', 'OnSaleOrderBeforeSaved', ['OrderEvents', 'onBeforeOrderSaveHandler']);
    
    class OrderEvents {
    	public static function onBeforeOrderSaveHandler(\Bitrix\Main\Event $event) {
    		$order = $event->getParameter('ENTITY');
    		$shipmentCollection = $order->getShipmentCollection();
    		
    		foreach($shipmentCollection as $shipment) {
    			if(!$shipment->isSystem())
    				$shipment->setBasePriceDelivery(0, false);
    		}
    	}
    }


    UPD
    Насчет if(!$shipment->isSystem()) я не уверен, взял с компонента sale.order.ajax. Помню, что там типа две отгрузки создаются - одна системная, а вот зачем не помню.
    Ответ написан
  • Битрикс загибается?

    @PetrPo
    Не вижу особой разницы между тем чтобы написать модуль или написать тоже самое просто в отдельной папке. Создаешь папку со своим namespace в папке php_interface, там файл include.php с autoload-ом классов и подключаешь в init.php свой include.php Сейчас это тебе сэкономит время (не писать и не тестить установку и другие мелочи), а уж если получится реально переиспользуемой крутой код, потратишь немного времени, чтобы завернуть это в модуль.

    P.S. Написание модуля никак не исправит твое желание писать говнокод)
    Ответ написан
    Комментировать
  • Как перезаписать правило ЧПУ для собственнего компонента Битрикс при сохранении настроек?

    @PetrPo
    У тебя комплексный компонент, он все правильно переписывает urlrewrite. Когда включаешь SEF_MODE у тебя есть доп. параметр SEF_URL_TEMPLATES, вот он и будет твоими правилами, которые ты хочешь вот так записать #^/somedir/([^/]+)/([^/]+)?/?(.*)$#
    Сохрани свой компонент через визуальный редактор, потом вручную (пока что) замени в индексном файле
    "SEF_URL_TEMPLATES" => array(
    	"element" => "#CODE#/",
    	"articles" => "#CODE#/articles/",
    	"articles2" => "#CODE#/articles2/",
    	"articles3" => "#CODE#/articles3/",
    ),

    Теперь по запросу /somedir/#CODE#/articles/ у тебя будет подключаться страница articles.php (остальные соответственно - /somedir/#CODE#/articles2/ будет articles2.php ), которую тебе надо создать в шаблоне комплексного компонента. в $arResult['VARIABLES']['CODE'] у тебя будет код твоего элемента, можешь доставать нужные связи - тут уже как считаешь правильным, хоть тут запросы делай, хоть на уровень комплексного компонента это выноси, я бы для таких связей написал еще простой компонент.

    Ну и остается сделать, чтобы твои SEF_URL_TEMPLATES можно было через визуальный редактор редактировать, в любом комплексном компоненте в файле .parameters.php можешь посмотреть (ориентир, все что с SEF_MODE связано)

    Примерчик на основе компонента news:
    5f3a8ffb3d32e894639962.jpeg
    стандартный битриксовый eshop, раздел новости, компонент news, все работает как надо

    Правки в файле .parameters.php компонента, раздел SEF_MODE
    // ...............
    "SEF_MODE" => Array(
    	"element" => array(
    		"NAME" => GetMessage("T_IBLOCK_SEF_PAGE_NEWS_DETAIL"),
    		"DEFAULT" => "#CODE#/",
    		"VARIABLES" => array("CODE"),
    	),
    	"articles" => array(
    		"NAME" => "Страница связанных articles",
    		"DEFAULT" => "search/",
    		"VARIABLES" => array(),
    	),
    
    	"articles2" => array(
    		"NAME" => "Страница связанных articles2",
    		"DEFAULT" => "search/",
    		"VARIABLES" => array(),
    	),
    
    	"articles3" => array(
    		"NAME" => "Страница связанных articles3",
    		"DEFAULT" => "search/",
    		"VARIABLES" => array(),
    	),
    
    ),
    // ................
    
    в конце по вкусу можно добавить, что-то типа
    if($arCurrentValues["SEF_MODE"]=="Y")
    {
    	$arComponentParameters["PARAMETERS"]["VARIABLE_ALIASES"] = array();
    	$arComponentParameters["PARAMETERS"]["VARIABLE_ALIASES"]["CODE"] = array(
    		"NAME" => GetMessage("CP_BC_VARIABLE_ALIASES_ELEMENT_ID"),
    		"TEMPLATE" => "#CODE#",
    	);
    }


    В файле component.php можно добавить
    $arDefaultUrlTemplates404 = array(
    	"news" => "",
    	"element" => "#CODE#/",
    );
    Ответ написан
    Комментировать