Плагин добавляет на страницу товара быструю AJAX-форму бронирования, временно закрепляет товар за покупателем, отправляет уведомления, позволяет управлять заявками и предоставляет персональную страницу статуса заказа.
Назначение плагина
GRIT AJAX Reservation - универсальная система бронирования товаров JoomShopping без стандартной корзины и многоэтапного оформления заказа.
Плагин подходит для любых товаров, которые необходимо временно закрепить за покупателем до подтверждения заказа или получения оплаты.
Его можно использовать для:
- товаров в единственном экземпляре;
- товаров с ограниченным остатком;
- изделий ручной работы;
- мебели и предметов интерьера;
- оборудования и техники;
- лимитированных серий;
- предварительных заказов;
- коллекционных товаров;
- подарков и сувениров;
- приёма заявок с ручным выставлением счёта;
- продаж без подключённого эквайринга;
- первичного тестирования спроса.
Плагин также можно использовать для услуг, если услуги оформлены в JoomShopping как товары.
Основные возможности
Быстрая форма
Покупатель оформляет бронь в модальном окне без перехода в корзину.
Временный резерв
Товар автоматически блокируется на установленное в настройках время.
Защита от дублей
Сервер не позволяет создать две активные брони одного товара.
Почтовые уведомления
Продавец получает заявку, а покупатель - подтверждение и ссылку на статус.
Панель заявок
Администратор управляет статусами, резервами и отправлениями.
Остатки магазина
После оплаты плагин может автоматически снять товар с продажи.
- AJAX-отправка формы без перезагрузки страницы.
- Повторная серверная проверка остатка перед созданием заявки.
- Уникальный номер каждой заявки.
- Автоматическое завершение просроченного резерва.
- Продление срока после отправки счёта.
- Отправка уведомления продавцу.
- Опциональное письмо покупателю.
- Персональная страница статуса заказа.
- Сброс активной брони.
- Удаление тестовых и ненужных заявок.
- Добавление трек-номера.
- Добавление ссылки на отслеживание.
- Копирование трек-номера одним нажатием.
- Опциональное обнуление остатка после оплаты.
- Передача целей в Яндекс.Метрику.
- Отображение всех дат по московскому времени.
- Журналирование важных операций.
Системные требования
- Joomla 6.x.
- Компонент JoomShopping.
- PHP 8.1 или новее.
- MySQL или MariaDB.
- Работающая отправка почты Joomla.
- Возможность создать переопределение шаблона JoomShopping.
Fancybox не является обязательным. Если библиотека Fancybox доступна на сайте, плагин использует её. При отсутствии Fancybox открывается встроенное модальное окно.
Установка
Скачайте установочный архив по кнопке в начале страницы.
Откройте административную панель Joomla и перейдите в раздел Система - Установка - Расширения.
Загрузите файл plg_grit_ajaxreservation.zip.
Откройте список плагинов, найдите GRIT AJAX Reservation и включите его.
Заполните основные настройки, настройте почту Joomla и сохраните параметры.
Выполните интеграцию в переопределённый шаблон страницы товара JoomShopping.
Во время установки автоматически создаётся таблица:
#__grit_ajaxreservations
Интеграция в шаблон JoomShopping
Одной установки плагина недостаточно. Необходимо заменить стандартную кнопку корзины на вызов формы бронирования и подключить разметку модального окна в шаблоне страницы товара.
Почему нужно использовать переопределение шаблона
Не следует изменять файлы непосредственно внутри каталога компонента JoomShopping. Такие изменения могут быть удалены при обновлении компонента.
Правильное решение - создать переопределение представления товара в активном шаблоне Joomla.
Обычно переопределение находится в каталоге:
/templates/ВАШ_ШАБЛОН/html/com_jshopping/product/
Точное имя PHP-файла зависит от установленной версии JoomShopping и используемого шаблона магазина.
Создание переопределения через Joomla
- Откройте Система - Шаблоны сайта.
- Выберите активный шаблон.
- Откройте раздел создания переопределений.
- Найдите компонент
com_jshopping. - Создайте переопределение представления страницы товара.
- Все последующие изменения выполняйте только в созданной копии.
Название пунктов административной панели может немного отличаться в зависимости от используемого шаблона и версии Joomla.
Файлы интеграции
После установки примеры находятся в каталоге:
/plugins/ajax/grit_ajaxreservation/integration/product-character-trigger.php
Код кнопки, открывающей форму бронирования.
/plugins/ajax/grit_ajaxreservation/integration/product-character-modal.php
Код модального окна с формой.
/plugins/ajax/grit_ajaxreservation/integration/INSTALLATION-RU.txt
Краткая инструкция по интеграции.
Примеры из каталога integration подготовлены для пользовательского шаблона product-character.php. В другом шаблоне названия переменных товара, цены и иконок могут отличаться.
Шаг 1. Найдите стандартную кнопку корзины
В шаблоне страницы товара найдите кнопку, которая добавляет товар в корзину. Обычно она находится внутри блока кнопок и содержит обработчик отправки формы JoomShopping.
Пример стандартной кнопки:
<button
type="submit"
class="btn btn-success button btn-buy"
onclick="jQuery('#to').val('cart');"
>
В корзину
</button>
Удалите только эту кнопку. Остальные элементы блока - кнопку вопроса, информацию о доставке и другие ссылки - можно оставить.
Шаг 2. Добавьте кнопку бронирования
Вместо удалённой кнопки вставьте вызов layout-файла плагина:
<?php
print \Joomla\CMS\Layout\LayoutHelper::render(
'trigger',
[
'productId' => (int) $product->product_id,
'productName' => (string) $productName,
'productEan' => (string) $product->getEan(),
'priceText' => trim(
strip_tags(
Helper::formatprice($product->getPriceCalculate())
. (string) $product->_tmp_var_price_ext
)
),
'priceValue' => (float) $product->getPriceCalculate(),
'buttonIcon' => $productCharacterIcon('cart'),
'buttonLabel' => 'Забронировать товар',
'buttonClass' => 'btn btn-success button btn-buy',
],
JPATH_PLUGINS . '/ajax/grit_ajaxreservation/layouts'
);
?>
Значение buttonLabel можно изменить:
Забронировать товарОформить броньЗабронироватьОставить заявку
Передаваемые параметры
| Параметр | Назначение |
|---|---|
productId |
ID товара JoomShopping. |
productName |
Название товара. |
productEan |
Артикул или EAN товара. |
priceText |
Отформатированная цена для отображения. |
priceValue |
Числовое значение цены. |
buttonIcon |
Иконка кнопки. Параметр можно передать пустой строкой. |
buttonLabel |
Текст кнопки. |
buttonClass |
CSS-классы кнопки. |
Если в вашем шаблоне нет функции $productCharacterIcon(), передайте:
'buttonIcon' => '',
Шаг 3. Подключите модальную форму
Найдите закрывающий тег основной формы товара:
</form>
Сразу после него вставьте:
<?php if ($isAvailable && !$hideBuy) { ?>
<?php
print \Joomla\CMS\Layout\LayoutHelper::render(
'modal',
[
'productId' => (int) $product->product_id,
'productName' => (string) $productName,
'productEan' => (string) $product->getEan(),
'priceText' => trim(
strip_tags(
Helper::formatprice($product->getPriceCalculate())
. (string) $product->_tmp_var_price_ext
)
),
'priceValue' => (float) $product->getPriceCalculate(),
],
JPATH_PLUGINS . '/ajax/grit_ajaxreservation/layouts'
);
?>
<?php } ?>
Не вставляйте модальное окно внутрь формы JoomShopping.
HTML не допускает вложенные формы. Браузер может автоматически перестроить разметку, из-за чего отправка данных перестанет работать или начнёт передавать неправильные поля.
Правильная структура шаблона
<form class="jshop productfull" method="post">
Основные данные товара
<div class="product-buttons">
Кнопка GRIT AJAX Reservation
</div>
Скрытые поля JoomShopping
</form>
Модальное окно GRIT AJAX Reservation
Другие блоки страницы товара
Проверка доступности
В пользовательском шаблоне можно определять доступность по стандартному остатку JoomShopping:
<?php
$isAvailable = (float) $product->getQty() > 0;
?>
Когда product_quantity становится равным нулю, кнопку бронирования следует скрыть и вывести сообщение о недоступности товара.
Пример:
<?php if ($isAvailable) { ?>
Кнопка бронирования
<?php } else { ?>
<div class="product-unavailable">
<strong>Товар больше недоступен</strong>
<span>Оформить новую бронь нельзя</span>
</div>
<?php } ?>
Настройки плагина
| Параметр | Описание |
|---|---|
| Email получателя уведомлений | Адрес продавца или администратора, на который приходит новая заявка. |
| Срок первичного резерва | Количество минут, на которое товар блокируется после создания заявки. |
| Срок после отправки счёта | Новый срок резерва после статуса «Счёт отправлен». |
| Отправлять письмо покупателю | При значении «Да» покупатель получает подтверждение и ссылку на статус. |
| Обнулять остаток после оплаты | При значении «Да» плагин записывает нулевой остаток в JoomShopping. |
| Ссылка на политику | Относительный адрес страницы без домена. |
| Лимит с одного IP | Максимальное количество заявок с одного IP-адреса за час. |
| Лимит на email | Максимальное количество заявок на один email за сутки. |
| Минимальное время формы | Защита от автоматической моментальной отправки формы ботом. |
| ID счётчика Метрики | Числовой идентификатор счётчика Яндекс.Метрики. |
| Цель открытия формы | Идентификатор JavaScript-цели открытия формы. |
| Цель успешной брони | Идентификатор цели успешного создания заявки. |
Ссылка на политику конфиденциальности
Указывайте относительный путь:
/privacy-policy
или:
/politika-konfidentsialnosti
Полный адрес с доменом указывать не нужно.
Как проходит бронирование
- Покупатель открывает карточку товара.
- Плагин проверяет остаток и активную бронь.
- Покупатель нажимает кнопку бронирования.
- Открывается модальная форма.
- Покупатель вводит имя, фамилию, телефон и email.
- Выбирает способ доставки и указывает ПВЗ.
- Сервер повторно проверяет товар.
- Создаётся заявка с уникальным номером.
- Товар временно блокируется.
- Продавцу отправляется уведомление.
- При включённой настройке покупатель получает письмо.
- Продавец отправляет счёт или платёжную ссылку.
- После оплаты заявка переводится в соответствующий статус.
Данные формы
- Имя.
- Фамилия.
- Телефон.
- Email.
- Способ доставки.
- Адрес, код или ссылка на ПВЗ.
- Комментарий.
- Согласие на обработку персональных данных.
Способы доставки
- ПВЗ Wildberries.
- ПВЗ Яндекс Маркета.
- ПВЗ Ozon.
- ПВЗ СДЭК.
Панель управления бронированиями
После установки в административном меню Joomla появляется пункт управления бронированиями.
Панель также доступна по адресу:
/administrator/index.php?option=com_ajax&plugin=gritAjaxreservation&format=raw&action=panel
В панели можно:
- просматривать все заявки;
- искать заявки;
- фильтровать их по статусу;
- просматривать контакты покупателя;
- просматривать данные доставки;
- изменять статус;
- указывать трек-номер;
- указывать ссылку отслеживания;
- сбрасывать активный резерв;
- удалять заявку;
- открывать страницу статуса покупателя;
- переходить к настройкам плагина.
Статусы заявок
| Статус | Назначение |
|---|---|
| Ожидает счёта | Заявка создана, ссылка на оплату ещё не отправлена. |
| Счёт отправлен | Покупателю передана ссылка или реквизиты для оплаты. |
| Оплачен | Продавец подтвердил поступление денег. |
| Готовится к отправке | Заказ упаковывается. |
| Отправлен | Заказ передан службе доставки. Требуется трек-номер. |
| Завершён | Работа с заказом завершена. |
| Отменён | Бронь отменена администратором. |
| Истёк | Срок активного резерва закончился. |
Сброс брони
Сброс переводит активную заявку в статус «Отменён» и снова разрешает бронирование товара.
Запись остаётся в истории.
Удаление заявки
Удаление полностью стирает запись. Действие выполняется после подтверждения и не может быть отменено.
Работа с остатками JoomShopping
Источником фактической доступности является стандартная таблица товаров JoomShopping:
#__jshopping_products
Используемый столбец:
product_quantity
Логика:
product_quantity > 0- товар доступен.product_quantity = 0- товар недоступен.
При включённой опции «Обнулять остаток после оплаты» плагин выполняет:
UPDATE `#__jshopping_products`
SET `product_quantity` = 0
WHERE `product_id` = ID_ТОВАРА;
После этого карточка товара получает новый статус непосредственно из базы. JavaScript используется только для обновления интерфейса, но не является источником сведений об остатке.
Почтовые уведомления
Плагин использует стандартный почтовый транспорт Joomla.
Перед запуском проверьте тестовое письмо:
Система - Общие настройки - Сервер - Почта
Письмо продавцу
Содержит:
- номер заявки;
- название товара;
- стоимость;
- артикул;
- имя и фамилию покупателя;
- телефон;
- email;
- способ доставки;
- данные ПВЗ;
- комментарий;
- срок резерва;
- ссылку на товар;
- ссылку на административную панель.
Email покупателя устанавливается как Reply-To.
Письмо покупателю
При включённой опции письмо начинается с обращения:
Здравствуйте, Имя Фамилия!
Также письмо содержит:
- название товара;
- номер заявки;
- стоимость;
- доставку и ПВЗ;
- срок резерва;
- дальнейшие инструкции;
- персональную ссылку на статус.
На локальном Open Server Panel для проверки писем можно использовать Mailpit. В этом случае письма сохраняются локально и не отправляются на реальные почтовые адреса.
Страница статуса и отслеживание отправления
Каждая заявка получает случайный публичный токен и персональную ссылку.
Покупатель может увидеть:
- номер заявки;
- название товара;
- стоимость;
- текущий статус;
- способ доставки;
- выбранный пункт выдачи;
- срок резерва;
- дату последнего обновления;
- трек-номер;
- ссылку на отслеживание.
Телефон и email на публичной странице не выводятся.
После указания трек-номера рядом появляется кнопка «Копировать». После нажатия над кнопкой выводится уведомление «Номер скопирован».
Передача целей в Яндекс.Метрику
Поддерживаются две цели:
reservation_form_open- открытие формы;reservation_success- успешное бронирование.
Названия можно изменить в настройках.
Для успешной заявки передаются параметры:
product_id;product_name;reservation_code;order_price;currency: RUB.
В Яндекс.Метрике необходимо создать цели типа «JavaScript-событие» с теми же идентификаторами.
Безопасность
Публичная форма
- CSRF-токен Joomla.
- Серверная проверка HTTP-метода.
- Проверка допустимого AJAX-действия.
- Очистка и валидация полей.
- Honeypot против спам-ботов.
- Минимальное время заполнения.
- Лимит заявок по IP.
- Лимит заявок по email.
- Повторная проверка товара перед записью.
- Транзакция базы данных.
- Защита от двойного бронирования.
Административные операции
- Доступ только авторизованному администратору.
- Проверка ACL Joomla.
- Проверка права
core.manageдляcom_plugins. - CSRF-токен для изменения данных.
- Изменения выполняются через POST.
- Транзакции при критических операциях.
- Запись действий в журнал.
Проверка после установки
- Установите тестовому товару количество больше нуля.
- Откройте карточку товара в приватном окне браузера.
- Нажмите кнопку бронирования.
- Заполните и отправьте форму.
- Проверьте письмо продавцу.
- При включённой настройке проверьте письмо покупателю.
- Обновите страницу товара и убедитесь, что отображается активная бронь.
- Откройте административную панель заявок.
- Переведите заявку в статус «Счёт отправлен».
- Проверьте новый срок резерва.
- Добавьте трек-номер и ссылку отслеживания.
- Откройте персональную страницу покупателя.
- Проверьте копирование трек-номера.
- Переведите заявку в статус «Оплачен».
- При включённой опции проверьте значение
product_quantity. - Убедитесь, что товар больше нельзя забронировать.
Журнал плагина
Диагностические записи сохраняются в:
/administrator/logs/plg_grit_ajaxreservation.php
Журнал содержит:
- создание брони;
- фактический срок резерва;
- результат отправки писем;
- ошибки почты;
- состояние переключателей;
- изменение остатка товара;
- сброс брони;
- удаление заявки;
- изменение статусов.
Ограничения текущей версии
- Плагин не принимает оплату самостоятельно.
- Счёт или платёжная ссылка отправляются продавцом вручную.
- Плагин не формирует чек.
- Нет прямого подключения к приложению «Мой налог».
- Не рассчитывается стоимость доставки.
- ПВЗ не загружаются автоматически с карты.
- Адрес, код или ссылка на ПВЗ вводятся вручную.
- Получение оплаты подтверждается администратором.
Обновление и удаление
Обновление
Новый ZIP-архив устанавливается поверх предыдущей версии через стандартный установщик Joomla.
Предварительно удалять плагин не нужно.
Удаление
Таблица заявок намеренно не удаляется автоматически вместе с плагином, чтобы не потерять историю бронирований.
Для полного ручного удаления используется таблица:
#__grit_ajaxreservations