Задача: на странице товара необходимо реализовать функцию автоматического изменения URL при выборе определенной товарной позиции без перезагрузки страницы. При этом, если ссылка скопирована и передана другому пользователю, должен осуществляться автоматический выбор соответствующей товарной позиции при переходе по ссылке.
Подмена url с помощью javascript, без перезагрузки страницы
Для начала необходимо открыть файл script.js шаблона детального просмотра элемента и найти участок, который отвечает за переключение SKU. Обычно это строка selectOfferProp: function() на, примерно, 1792-ой строке.
Полный код модифицированной функции ниже, с комментариями-отбивками ("//start CUSTOM" и "// end CUSTOM"):
selectOfferProp: function () {
var i = 0,
strTreeValue = '',
arTreeItem = [],
rowItems = null,
target = BX.proxy_context,
smallCardItem;
if (target && target.hasAttribute('data-treevalue')) {
if (BX.hasClass(target, 'selected'))
return;
if (typeof document.activeElement === 'object') {
document.activeElement.blur();
}
// start CUSTOM
var skuId = this.offers[this.offerNum]['ID'];
// end CUSTOM
strTreeValue = target.getAttribute('data-treevalue');
arTreeItem = strTreeValue.split('_');
this.searchOfferPropIndex(arTreeItem[0], arTreeItem[1]);
rowItems = BX.findChildren(target.parentNode, {
tagName: 'li'
}, false);
if (rowItems && rowItems.length) {
for (i = 0; i < rowItems.length; i++) {
BX.removeClass(rowItems[i], 'selected');
}
// start CUSTOM
var currentUrl = window.location.href;
var newUrl = currentUrl.replace(skuId + '/', '');
window.history.replaceState(null, null, newUrl);
// end CUSTOM
}
BX.addClass(target, 'selected');
// start CUSTOM
var skuId = this.offers[this.offerNum]['ID'];
var newUrl = window.location.pathname + skuId + '/';
window.history.pushState('', '', newUrl);
// end CUSTOM
if (this.smallCardNodes.panel) {
smallCardItem = this.smallCardNodes.panel.querySelector('[data-treevalue="' + strTreeValue + '"]');
if (smallCardItem) {
rowItems = this.smallCardNodes.panel.querySelectorAll('[data-sku-line="' + smallCardItem.getAttribute('data-sku-line') + '"]');
for (i = 0; i < rowItems.length; i++) {
rowItems[i].style.display = 'none';
}
smallCardItem.style.display = '';
}
}
if (
this.isFacebookConversionCustomizeProductEventEnabled &&
BX.Type.isArrayFilled(this.offers) &&
BX.Type.isObject(this.offers[this.offerNum])
) {
BX.ajax.runAction(
'sale.facebookconversion.customizeProduct', {
data: {
offerId: this.offers[this.offerNum]['ID']
}
}
);
}
}
},
- Создаем переменную skuId, в которой хранится ID выбранного торгового предложения.
- С помощью метода window.history.replaceState очищаем URL от ранее вставленного ID предложения.
- С помощью метода window.history.pushState добавляем в URL ID выбранного предложения с учетом ЧПУ.
Теперь, при переключении предложений, в URL будет добавляться ID элемента торгового предложения с учетом ЧПУ. Если в URL уже есть ID предложения, оно будет удалено и добавится выбранное предложение.
Все будет происходить без перезагрузки страницы, и пользователь, при желании, сможет скопировать адрес, чтобы поделиться прямой ссылкой на предложение.
Прямая ссылка на торговое предложение
Если пользователь скопирует сгенерированную ссылку и поделится ей с другом, друг попадет на страницу с ошибкой 404, так как для системы таких URL не существует.
Чтобы обработать этот переход и направить пользователя в карточку товара, нужно установить вот такие параметры обработки ошибки 404, в настройках комплексного компонента каталога.
В директории каталога создаем файл 404.php со следующим содержимым:
include_once($_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/urlrewrite.php');
$currentPath = GetPagePath();
$arUrl = explode('/', $currentPath);
// Находим инфоблок предложений
$dbIBlock = CIBlock::GetList(
false,
array(
"TYPE" => "offers",
"SITE_ID" => SITE_ID,
)
);
if ($arIBlock = $dbIBlock->GetNext()) {
$offersIblocId = $arIBlock['ID'];
}
// Проходим по предложениям в посках ID из url
$dbOffers = CIBlockElement::GetList(
false,
array(
'IBLOCK_ID' => $offersIblocId
),
false,
false,
array('ID')
);
while ($arOffers = $dbOffers->Fetch()) {
if (in_array($arOffers['ID'], $arUrl)) {
$removePath = $arOffers['ID'] . '/';
$urlWithoutOfferId = str_replace($removePath, '', $currentPath);
LocalRedirect($urlWithoutOfferId . '?TARGET_OFFER=' . $arOffers['ID']); // отправляем в товар
exit;
}
}
CHTTP::SetStatus("404 Not Found");
@define("ERROR_404", "Y");
define("HIDE_SIDEBAR", true);
require($_SERVER["DOCUMENT_ROOT"] . "/bitrix/header.php");
$APPLICATION->SetTitle("Страница не найдена");
// !!!!! Тут ваша красивая 404 ошибка каталога
require($_SERVER["DOCUMENT_ROOT"] . "/bitrix/footer.php");
- Получаем текущий URL с помощью $_SERVER['REQUEST_URI'] и разбиваем его на массив с помощью функции explode().
- Далее, с помощью CIBlock::GetList() получаем ID инфоблока с предложениями. Можно просто указать его в CIBlockElement::GetList().
- С помощью CIBlockElement::GetList() определяем, есть ли в URL ID предложения.
- Если совпадение найдено, мы вырезаем ID предложения из URL и перенаправляем пользователя на страницу товара (без учета предложения), но с GET-параметром TARGET_OFFER, в котором указан ID предложения.
- Если это несуществующий ID предложения или какая-то неправильная строка в URL, условие не сработает и отдастся обычная 404 ошибка.
Выбираем торговое предложение зная его ID
Теперь, когда пользователь перешел по ссылке на товар с GET параметром, в котором хранится ID торгового предложения, нужно это обработать и открыть ему ссылку с выбранным предложением.
В файл component_epilog.php, в шаблоне catalog.element добавляем:
if (!empty($_REQUEST['TARGET_OFFER'])) {
$offerNum = array_search($_REQUEST['TARGET_OFFER'], $templateData['OFFER_IDS']);
if (!empty($offerNum))
{?>
<script>
BX.ready(function(){
if (!!window.)
{
window.<?=$templateData['JS_OBJ']?>.setOffer(<?=$offerNum?>);
}
const url = window.location.href.replace(/(.*\/.*\/.*\/.*)\?TARGET_OFFER=(.*)/, '$1$2/');
const title = document.title;
window.history.replaceState({path: url}, title, url);
});
</script>
<?
}
}
- Проверили, не является ли запрос с TARGET_OFFER пустым.
- С помощью array_search нашли ключ, в котором хранится ID предложения из GET параметра.
- Установили выбор на предложении из GET параметра с помощью window.setOffer.
- Используя window.history.replaceState, перезаписали URL, чтобы вместо GET параметра был ЧПУ вариант ссылки.
Заметка написана без учета SEO. Для поисковиков не существуют страницы для каждого предложения.
У заметки есть продолжение: Уникальная СЕО информация для каждого торгового предложения
Видео: Как установить свой URL для торговых предложений (SKU) в Битрикс
Более наглядно и с учетом нюансов описанных выше, можно посмотреть в видео. Полная версия на моем BOOSTY канале, подписка всего 23 рубля в месяц
$OFFER_ID = filter_input(INPUT_GET, 'OFFER_ID', FILTER_SANITIZE_NUMBER_INT); - что бы исключить SQL инъекции и сделать работу более безопасной.