Загружает каталог
Запрашивает все товары указанной категории Tilda. Каталог нужен, чтобы определить названия товаров и позиции с обычной скидкой.
Практическое руководство к скрипту, который считает подарочные позиции в корзине Tilda, применяет скидку, показывает бейджи и передаёт сведения о промоакции в заказ.
В базовой конфигурации покупатель кладёт три разрешённых товара в корзину, а самая дешёвая единица получает скидку 100%. Скрипт работает и с одинаковыми товарами: сравнивает каждую единицу, а не только строки корзины.
Запрашивает все товары указанной категории Tilda. Каталог нужен, чтобы определить названия товаров и позиции с обычной скидкой.
MutationObserver замечает открытие корзины и запускает пересчёт каждые 250 мс только пока она открыта.
Добавляет пояснение в корзину, перечёркивает полностью бесплатные позиции и заполняет скрытое поле заказа.
Найдите ID категории «Все товары» или нужного каталога и замените демонстрационное число в ALL_CATEGORY_ID.
Настройте массив DEALS: сколько единиц нужно взять и сколько из них оплатить.
Разместите исходный фрагмент HTML/JS в пользовательском HTML-блоке или в коде страницы Tilda. Опубликуйте страницу.
t706. Перед публикацией откройте корзину на опубликованной странице и проверьте тестовый заказ.Все параметры находятся в самом начале блока <script>. Меняйте только значения справа от знака =.
const ENABLED_DEFAULT = true; // включить акцию const DEBUG = true; // журнал в консоли браузера const POLL_MS = 250; // частота пересчёта, мс const ALL_CATEGORY_ID = String(window.id_all_category_p || '434145928791'); const ALLOW_SALE_ITEMS_DEFAULT = false; const FREEBIE_DISCOUNT_PERCENT_DEFAULT = 100; const SALE_FREEBIE_POLICY = 'minusOne'; const USE_ALLOWED_LIST_DEFAULT = false; const FREEBIE_ALLOWED_UIDS = [ // 579586095852, ];
| Параметр | Назначение | Что поставить |
|---|---|---|
ALL_CATEGORY_ID | Категория, из которой подгружается каталог. | Реальный ID категории Tilda. |
FREEBIE_DISCOUNT_PERCENT_DEFAULT | Резервная величина скидки. | 100 для подарка, 50 для скидки 50%. |
USE_ALLOWED_LIST_DEFAULT | Ограничивает акцию конкретными товарами. | true, если используется список UID. |
FREEBIE_ALLOWED_UIDS | UID товаров или вариаций, доступных для акции. | Числа через запятую; при пустом списке и true акция не сработает. |
ALLOW_SALE_ITEMS_DEFAULT | Разрешает выдавать скидку на уже уценённые товары. | Обычно false. |
DEBUG | Выводит диагностические сообщения с префиксом [CFREE]. | true при проверке, затем false. |
Массив DEALS определяет, сколько единиц покупатель должен взять (buy) и сколько оплатить (pay).
// Базовый вариант: 3 товара, один из них бесплатно; только один раз const DEALS = [{ buy: 3, pay: 2, repeat: false, percent: 100 }]; // Повторяемая акция: при 6 товарах — два подарка const DEALS = [{ buy: 3, pay: 2, repeat: true, percent: 100 }]; // Один подарок при 4 товарах и скидка 50% при 6 товарах const DEALS = [ { buy: 4, pay: 3, repeat: false, percent: 100 }, { buy: 6, pay: 5, repeat: false, percent: 50 } ]; // Только 4 = 3: exclusive исключает остальные правила const DEALS = [{ buy: 4, pay: 3, repeat: false, exclusive: true, percent: 100 }];
| Поле | Смысл |
|---|---|
buy | Количество единиц, необходимое для применения правила. |
pay | Количество оплачиваемых единиц. Разница buy − pay получит скидку. |
repeat | true повторяет правило на каждой кратности; false применяет его максимум раз. |
percent | Процент скидки для награждённой единицы. |
exclusive | true оставляет только это правило, игнорируя все остальные. |
После загрузки страницы доступен объект window.CFREE. Команды удобно выполнять в DevTools → Console во время тестирования.
CFREE.enable() / disable()Включить или выключить акцию. При выключении скидка и метки удаляются.
CFREE.recalcNow()Немедленно выполнить пересчёт, не дожидаясь следующего цикла.
CFREE.useAllowedList()Разрешить акцию только для UID из FREEBIE_ALLOWED_UIDS.
CFREE.useAllProducts()Снять фильтр и применять акцию ко всем товарам.
CFREE.setFreebieDiscountPercent(50)Временно установить резервную скидку в процентах.
CFREE.allowSaleItems()Разрешить выбирать уже уценённые позиции как подарочные.
Добавьте в корзину две позиции: скидки быть не должно. Добавьте третью: самая дешёвая должна стать подарком.
Если repeat: true, при шести товарах должно появиться два подарка. При false — один.
Примените промокод: скидка акции должна исчезнуть. Удалите его: скидка должна вернуться.
| Ситуация | Что проверить |
|---|---|
| Акция не включается | Корзина открыта, каталог загрузился, товары имеют положительное количество; при фильтре списка UID добавлены верные UID. |
| Неверно определяется товар со скидкой | Скрипт считает товар уценённым, если в каталоге указан priceold. Проверьте именно это поле у товара или вариации. |
| В корзине уже есть sale-товар | При ALLOW_SALE_ITEMS_DEFAULT: false стратегия minusOne уменьшает учитываемое количество на одну единицу; block блокирует выдачу полностью. |
| Что передаётся в заказ | Поле textarea[name="all_sales"] получает список подарков, процент и итоговую скидку; оно скрыто стилем в начале исходного кода. |
| Нужно увидеть причину | Оставьте DEBUG: true и откройте консоль браузера: сообщения [CFREE] покажут товары, правила и выбранные единицы. |
Инструкция построена строго по вашему коду. Скрипт загружает каталог, следит за открытием корзины, выбирает самые дешёвые единицы и применяет к ним скидку — с учётом промокода и товаров с обычной скидкой.
Используйте переданный исходный блок целиком: в нём есть и CSS для бейджей/скрытого поля, и JavaScript. Внутри кода меняются только параметры в разделе «НАСТРОЙКИ» и массив DEALS.
Скопируйте весь исходный фрагмент, начиная со <style> и заканчивая </script>. Не удаляйте служебные функции. Ниже показана только структура блока, а не готовый код для вставки.
<style>
.cfree-badge { /* бейдж подарка */ }
.cfree-strike { /* зачёркнутая цена */ }
.t-input-group_ta[data-field-name="all_sales"] { display:none!important; }
</style>
<script>
document.addEventListener('DOMContentLoaded', function () {
(function () {
// настройки и логика акции
})();
});
</script>ALL_CATEGORY_ID.all_sales.targets, категорий товаров, CSV-вариаций или отключение проверок Tilda. Не добавляйте в неё шаги и параметры из старой инструкции — такого API в этом коде нет.all_salesОткройте настройки корзины и раздел с полями. Нажмите «Добавить поле для ввода», выберите «Поле для ввода в несколько строк», установите количество строк 10 и задайте имя переменной all_sales. Сохраните настройки корзины.
updateSalesTextarea() записывает сюда подарочные товары, размер скидки и её общий итог. В начале исходного кода это поле скрыто правилом .t-input-group_ta[data-field-name="all_sales"], поэтому покупатель его не увидит.После настройки ID категории скопируйте весь исходный блок. В Tilda откройте «Настройки сайта → Ещё → Редактировать код» и вставьте его в код проекта. Вставляется блок целиком — и <style>, и <script>. Такой способ подходит скрипту: он сам ждёт событие DOMContentLoaded, прежде чем обратиться к корзине и каталогу.
cfree-* и скрипт нужны вместе. Сохраните изменения и нажмите «Опубликовать все страницы».Каталог загружается запросом Tilda API. ID нужен для поиска названий товаров и определения позиции с уже заданной старой ценой.
В начале скрипта найдите ALL_CATEGORY_ID и поставьте ID нужной категории. Обычно используется служебная категория «Все товары». Если на странице уже объявлена переменная window.id_all_category_p, скрипт возьмёт её значение автоматически.
const ALL_CATEGORY_ID = String( window.id_all_category_p || '434145928791' );
DEBUG = true после открытия корзины не должно быть сообщения Catalog: ошибка загрузки в консоли браузера.Правило описывается так: buy — сколько единиц нужно взять, pay — сколько из них оплачивается. Разница получает скидку. Базовый вариант в вашем коде — один подарок при трёх товарах.
// 3 = 2: один подарок, правило не повторяется
const DEALS = [{ buy: 3, pay: 2, repeat: false, percent: 100 }];
// 3 = 2: повторяется на каждой кратности
const DEALS = [{ buy: 3, pay: 2, repeat: true, percent: 100 }];
// 4 = 3: скидка 50% на самую дешёвую единицу
const DEALS = [{ buy: 4, pay: 3, repeat: false, percent: 50 }];exclusive: true — необязательный флаг. Если он стоит у правила, код игнорирует все остальные правила из массива и оставляет только первое такое правило.
По умолчанию USE_ALLOWED_LIST_DEFAULT = false, и акция применяется ко всем товарам. Чтобы ограничить её, включите фильтр и перечислите UID товара или UID его вариации в FREEBIE_ALLOWED_UIDS.
const USE_ALLOWED_LIST_DEFAULT = true; const FREEBIE_ALLOWED_UIDS = [ 579586095852, 640781596522 ];
true и пустом массиве ни один товар не участвует в акции. В этой реализации список — только UID; настройка по категориям отсутствует.Товар считается уже уценённым, если у него или его вариации в каталоге есть priceold. При ALLOW_SALE_ITEMS_DEFAULT = false такой товар не может стать подарком. Дополнительно политика minusOne уменьшает количество, участвующее в расчёте, на одну единицу; block полностью блокирует выдачу подарка.
const ALLOW_SALE_ITEMS_DEFAULT = false; const SALE_FREEBIE_POLICY = 'minusOne'; // или 'block'
Если в tcart.promocode есть успешный статус, сумма или процент скидки, скрипт снимает только собственную скидку акции, метки и запись в all_sales. Он не останавливается: после удаления промокода пересчёт автоматически вернёт акцию.
Пересчёт работает, когда корзина открыта. Скрипт распознаёт стандартные состояния корзины Tilda: боковую панель, окно и страницу корзины.
Добавьте две единицы — скидки нет. Добавьте третью — самая дешёвая разрешённая единица получает скидку.
При repeat: true шесть единиц дают два подарка. При false — только один.
Примените промокод: акция исчезает. Удалите промокод: скидка снова появляется.
DEBUG = true. Сообщения с префиксом [CFREE] покажут состав корзины, рассчитанные правила, выбранные позиции и причины, по которым скидка не выдана.Эти иллюстрации из переданной инструкции помогают найти нужные настройки без лишних поисков.




Значения ниже соответствуют именно переданному JavaScript. Остальные функции менять не требуется.
| Параметр | Значение по умолчанию | Реальное действие |
|---|---|---|
ENABLED_DEFAULT | true | Стартовое состояние акции. Если false, пересчёт не делает ничего до команды CFREE.enable(). |
DEBUG | true | Включает сообщения [CFREE] в консоли. На расчёт не влияет. |
POLL_MS | 250 | Интервал пересчёта в миллисекундах, пока корзина открыта. |
ALL_CATEGORY_ID | демо-ID | ID категории для загрузки каталога партиями по 500 товаров. |
FREEBIE_DISCOUNT_PERCENT_DEFAULT | 100 | Резервный процент, если у конкретного правила DEALS не указан percent. |
ALLOW_SALE_ITEMS_DEFAULT | false | Разрешает или запрещает отдавать товар со старой ценой priceold в качестве подарка. |
SALE_FREEBIE_POLICY | 'minusOne' | При наличии sale-товара: уменьшает учёт на одну единицу или полностью блокирует акцию при 'block'. |
USE_ALLOWED_LIST_DEFAULT | false | Включает фильтр по FREEBIE_ALLOWED_UIDS. |
После DOMContentLoaded код загружает каталог методом loadCatalog(). Он рекурсивно получает все страницы API, пока Tilda возвращает nextslice. MutationObserver следит за классами t706__body_cartsidebarshowed, t706__body_cartwinshowed и t706__body_cartpageshowed. При открытии запускается интервал, при закрытии он останавливается и бейджи очищаются.
safeRecalc() сначала проверяет, включена ли акция, существует ли window.tcart и является ли tcart.products массивом. Затем проверяет промокод. Только после этого вызывает applyCheapestFree(); ошибки внутри него не останавливают работу страницы, а пишутся в консоль при включённом DEBUG.
Строки корзины с нулевым количеством отбрасываются. Если каталог не загружен или после UID-фильтра не осталось товаров, собственная скидка снимается. Количество каждой строки разворачивается в отдельные единицы: товар с количеством 3 становится тремя кандидатами с одинаковой ценой.
Правила сначала очищаются функцией sanitizeDeals(): остаются только правила, где buy > pay. calcFreebieAwards() создаёт список процентов скидки. Кандидаты сортируются по цене, затем по UID и индексу строки; первые N единиц получают скидку. Поэтому при равной цене выбор стабилен.
liftOwnDiscount() вычитает предыдущую скидку скрипта из общей, сохраняет чужие скидки, пересчитывает tcart.prodamount_discountsum, prodamount_withdiscount и amount с доставкой. Затем код вызывает стандартный tcart__reDrawTotal(), добавляет бейджи и обновляет запасной вывод итогов.
Функция updateSalesTextarea() ищет textarea[name="all_sales"]. В него записываются название товара, количество, скидка по каждой позиции и общий итог. Стиль в начале кода скрывает это поле на странице.
Эти команды уже создаёт ваш код. Они полезны для проверки без редактирования исходника.
| Команда | Действие |
|---|---|
CFREE.enable() | Включает акцию и запускает немедленный пересчёт. |
CFREE.disable() | Снимает собственную скидку, бейджи, итоговую строку и очищает all_sales. |
CFREE.recalcNow() | Выполняет один безопасный пересчёт прямо сейчас. |
CFREE.useAllowedList() / CFREE.useAllProducts() | Включает UID-фильтр или возвращает участие всех товаров. |
CFREE.setAllowedFilter(true|false) | То же переключение фильтра с аргументом. |
CFREE.allowSaleItems() / CFREE.disallowSaleItems() | Меняет в памяти страницы отношение к товарам с priceold. |
CFREE.setFreebieDiscountPercent(50) | Задаёт резервный процент 0–100 с ограничением значения. |
CFREE.getAllowedFilterState(), getSaleItemsState(), getFreebieDiscountPercent() | Возвращают текущие значения настроек. |
CFREE.clearDebugLogCache() | Очищает кэш повторяющихся отладочных сообщений. |
Команды меняют переменные в текущей вкладке. После обновления страницы снова применяются значения из исходного блока: ENABLED_DEFAULT, USE_ALLOWED_LIST_DEFAULT, ALLOW_SALE_ITEMS_DEFAULT и другие.
Меняйте только ID категории, массив DEALS, фильтр UID и параметры скидок. Остальная часть кода отвечает за загрузку каталога, перерасчёт сумм и интерфейс корзины.
Настройки и примеры ниже соответствуют переданному коду акции «самый дешёвый товар в подарок».
Создайте поле для информации об акции в заказе.
all_sales.updateSalesTextarea() записывает сюда подарки, размер скидки и итог. CSS в предоставленном блоке скрывает поле от покупателя.
Этот ID необходим коду, чтобы загрузить каталог товаров.
data-storepart-uid. Его число — ID категории.const ALL_CATEGORY_ID = String(window.id_all_category_p || 'ВАШ_ID_КАТЕГОРИИ_ВСЕ');
ALL_CATEGORY_ID. Переменная window.id_all_category_p используется только как резервное значение.
В массиве DEALS укажите, сколько товаров нужно взять и сколько оплатить.
buy — количество единиц в акции, pay — количество оплачиваемых, percent — скидка на самые дешёвые единицы.
const DEALS = [{ buy: 3, pay: 2, repeat: false, percent: 100 }];repeat: true, если при 6 товарах должно быть 2 подарка. Для скидки 50% замените percent: 100 на percent: 50.
По умолчанию акция действует на все товары. Этот шаг нужен только для ограниченного списка.
const USE_ALLOWED_LIST_DEFAULT = true; const FREEBIE_ALLOWED_UIDS = [579586095852, 640781596522];
FREEBIE_ALLOWED_UIDS, а не my_name_tovar1 из старой инструкции. UID товара и вариации поддерживаются. Пустой список при включённом фильтре отключает акцию.
Вставляется весь предоставленный блок со стилями и JavaScript.
<style> до </script>.
Для диагностики оставьте DEBUG = true: сообщения [CFREE] в консоли покажут расчёт и причину, если скидка не выдана.