---
title: "Разработка форм обратной связи для магазинов на Joomla - WebTolk"
description: "Статья о тонкостях разработки форм обратной связи для интернет магазинов на Joomla. Описанный способ подходит для построения форм не только для интернет магазин"
url: "https://web-tolk.ru/blog/razrabotka-form-obratnoj-svyazi-dlya-magazinov-na-joomla"
date: "2021-09-14T05:51:40+00:00"
language: "ru-RU"
---

# Разработка форм обратной связи для магазинов на Joomla

 Автор: Сергей Толкачев Создано: 14 сентября 2021 Обновлено: 30 января 2026 Просмотров: 8617    ![](https://web-tolk.ru/blog/images/blog/razrabotka-form-obratnoj-svyazi-dlya-magazinov-na-joomla-3/splash-1280x720.jpg)

Ещё одна статья-туториал, [опубликованная сначала на habr.com](https://habr.com/ru/post/576444/), о создании форм обратной связи на Joomla 3. В статье описывается подход к созданию форм, работающий как для Joomla 3, так и для Joomla 4 и последующих версий.

## Преамбула

В современном интернет-магазине должно быть немало форм обратной связи. Интернет-маркетологи стараются предупредить все возможные ситуации и порой создают формы обратной связи чуть ли ни на каждый потенциальный интент пользователя.

Оставив за скобками традиционные "заказать звонок", "подписаться на новости" привожу примеры форм интернет-магазина/каталога, которые мне доводилось встречать на практике при работе с Joomla 3:

- категория (листинг) товаров - "купить в 1 клик"
- категория (листинг) товаров - "запрос цены" (если у товара не указана цена)
- категория (листинг) товаров - "задать вопрос"
- карточка товара - "купить в 1 клик"
- карточка товара - "запрос цены" (если у товара не указана цена)
- карточка товара - "задать вопрос"
- карточка товара - "получить скидку" или "нашли дешевле?"
- карточка товара - "сделать индивидуальный заказ"
- карточка товара - "заказать оптом"

…и т.д. и т.п. Чудный мир фантазий интернет-маркетолога (безусловно опирающийся на данные аналитики, мониторинг конкурентов и рынка в целом, профессиональное чутьё и опыт) предлагает самые разные варианты ответа на вопрос: "как достать клиента?"

## Задача

Создать N-е количество форм обратной связи для интернет-магазина на базе Joomla. Формы должны быть красивыми и информативными, не вызывать неточного толкования у посетителя в том, что он делает. В форму выводим информацию о товаре и интент пользователя.

В форме должен меняться заголовок ("Задать вопрос", "узнать цену" и т.д.), картинка товара, его цена, название и артикул.

## К каким проблемам это приводит?

Мы постоянно слышим о том, что что-то можно сделать "легко и быстро", однако забываем о том, что для этого нужны знания и опыт. Везде.

В Joomla формы обратной связи - это модули, зачастую с огромным количеством настроек (Shack Forms, например). Или же компонент + модуль (RS Forms и другие).

 ![shack forms pro demo](https://web-tolk.ru/blog/images/blog/razrabotka-form-obratnoj-svyazi-dlya-magazinov-na-joomla-3/shack-forms-pro-demo.jpg)Демо настроек модуля Shack Forms Pro для Joomla 3

Чаще всего один модуль имеет только одну настройку темы письма (ручками указываем "задать вопрос", "купить оптом"). В итоге получается, что мы на каждый интент пользователя создаем отдельный модуль. Сверяемся со списком форм выше и получаем 9 однотипных модулей только для каталога товаров. Значит мы получаем много мусора в коде страницы и все вытекающие отсюда минусы.

Иной раз СЕО-специалисты (ничего личного) делают зоопарк форм обратной связи не модулями Joomla, а сторонним конструктором форм - DSForms, например. А тут на основной почте сайта поменяли пароль.... И человек меняет в 9 формах пароль. Это рутина, этим вообще некогда заниматься и в 2-3 формах остается старый пароль. Через несколько дней (хорошо если!) звонит разгневанный клиент: "У нас просели заявки!" Мы начинаем смотреть логи, отправлять тестовые заявки, искать почему так произошло, ведь разработчику никто не сказал, что меняли пароль...

## Форма обратной связи для Joomla своими руками

Ну, почти своими. Описываемый ниже подход подойдет для любых форм обратной связи. И отдельный акцент мы делаем на формах, в которых нужно указать информацию о товаре.

![](https://web-tolk.ru/blog/images/blog/razrabotka-form-obratnoj-svyazi-dlya-magazinov-na-joomla-3/screen-1280x720.jpg)

### Замена модулей обратной связи на плагин-обработчик

Плагин [Radical Form](https://hika.su/rasshireniya/radical-form) - плагин-обработчик формы обратной связи. На странице документации плагина описаны причины появления такого решения и в целом я соглашаюсь с доводами.

Если кратко, то обычно каждое стороннее расширение тянет за собой js-скрипты, css, которые далеко не всегда вписываются в контекст сайта. В итоге всё равно приходится делать свой макет вывода. А если автор стороннего модуля решил сделать решения в духе No code (то есть максимум настроек внешнего вида в админке), то для разработчика работа с таким решением может превратиться в ад.

С Radical Form становится возможным следующий подход в работе:

1. вы делаете свой HTML формы (вообще любой!),
2. кнопке "отправить" назначается класс `rf-button-send`
3. код формы размещаете в модуле типа "HTML-код" везде, где это необходимо.

И оно работает. Именно это решение мы разовьём в тексте ниже. Так же рекомендую ознакомиться с документацией по Radical Form для лучшего понимания общей картины.

### Несколько форм в одной

Чаще всего формы показываются в модальных (всплывающих) окнах. Я в основном работаю с сайтами в стеке Bootstrap, поэтому примеры HTML будут приведены для него. Однако, в контексте данной статьи не имеет значение CSS-фреймворк.

По сути все перечисленные выше формы - это одна форма, в которой нужно менять только заголовок модального окна и тему письма, а код формы может быть одним и тем же. Для этого нам потребуется раздел [Varying modal content из документации Bootstrap 4.6](https://getbootstrap.com/docs/4.6/components/modal/#varying-modal-content), для [Bootstrap 5.3](https://getbootstrap.com/docs/5.3/components/modal/#varying-modal-content).

Обратите внимание, что для Bootstrap 5+ имена data-атрибутов поменялись с `data-toggle`, на `data-bs-toggle`, `data-target` на `data-bs-target` и так далее.

```
<!-- data-form-title - здесь указываем заголовок модального окна и тему письма -->
<button class="btn btn-primary" type="button" data-toggle="modal" data-target="#exampleModal2" data-form-title="Обратный звонок">Обратный звонок</button>
<button class="btn btn-primary" type="button" data-toggle="modal" data-target="#exampleModal2" data-form-title="Заказать консультацию">Заказать консультацию</button>
<button class="btn btn-primary" type="button" data-toggle="modal" data-target="#exampleModal2" data-form-title="Запрос скидки">Запрос скидки</button>

<div id="exampleModal2" class="modal fade" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
            <h5 id="exampleModalLabel" class="modal-title">Здесь будет заголовок из атрибута data-form-title кнопки</h5>
            <button class="close" type="button" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">×</span> </button></div>
            <div class="modal-body">
                <form>
                    <div class="form-group mb-4">
                        <label for="phone3">Ваш телефон *</label>
                        <input id="phone3" class="form-control required" name="PHONE" required="" type="tel" placeholder="+79999999999" aria-describedby="PhoneHelp" />
                    </div>
                    <div class="custom-control custom-switch my-3">
                        <input id="agreement_gdpr" class="custom-control-input required" name="gdpr" required="" type="checkbox" />
                        <label class="custom-control-label" for="agreement_gdpr">Я принимаю <a href="#" rel="noindex">политику обработки персональных данных</a>.</label>
                    </div>
                    <input name="rfSubject" value="Скрытое поле для индивидуальной темы письма из каждой формы" type="hidden" />
                    <button class="btn btn-lg bg-dark text-white rf-button-send" type="submit"><i class="fa fa-paper-plane-o" aria-hidden="true"></i> Отправить</button>
                </form>
            </div>
        </div>
    </div>
</div>
<script type="text/javascript">
    $('#exampleModal2').on('show.bs.modal', function (event) {
      let button = $(event.relatedTarget); // Кнопка, вызвавшая модальное окно
      let formTitle= button.data('form-title'); // Получаем информацию из data-* атрибута
      // Обновляем информацию в модальном окне.
      let modal = $(this);
      // Устанавливаем заголовок модального окна
      modal.find('.modal-title').text(formTitle);
      // Устанавливаем тему письма для писем, отправляемых из формы.
      modal.find('.modal-body [name=rfSubject]').val(formTitle);
    })
</script>
```

**Пример javascript-кода без использования jQuery (для Bootstrap 5+)**

Bootstrap 5 отказался от использования библиотеки jQuery. Следуя этой тенденции привожу пример кода без использования jQuery.

```
(() => {
	// Работаем после полной загрузки страницы.
	document.addEventListener('DOMContentLoaded',() => {
		// Получаем наше модальное окно
		const contactFormModal = document.getElementById('contact_form_modal');
		  if (contactFormModal) {
			contactFormModal.addEventListener('show.bs.modal', event => {
				// Кнопка, вызвавшая модальное окно
				const button = event.relatedTarget;
				// Получаем инфу из  data-* атрибутов
				const formTitle = button.getAttribute('data-form-title');
				const formSubTitle = button.getAttribute('data-form-subtitle');
				// Обновляем информацию в модальном окне.
				const modalTitle = contactFormModal.querySelector('.modal-title');
				const modalBodyInput = contactFormModal.querySelector('.modal-body [name=rfSubject]');
				console.log(modalBodyInput);
				// Устанавливаем заголовок модального окна
				modalTitle.textContent = formTitle;
				// Устанавливаем тему письма для писем, отправляемых из формы.
				modalBodyInput.value = formTitle;
			});
		}
	});
})();
```

В data-атрибуты кнопки можно поместить самую разную информацию. В некоторых случаях я помещаю туда нужные для отображения поля формы (name, email, phone, comment), какие из них должны быть обязательными для заполнения и т.д. Например, получение обязательных полей из атрибута `data-fields-required` кнопки, имена которых указаны через запятую:

```
let fieldsRequired = button.data('fields-required');
				if (typeof fieldsRequired !== 'undefined'){
					fieldsRequired = fieldsRequired.split(',');
					$(fieldsRequired).each(function(index){
						$('.contact_form_modal_'+fieldsRequired[index]+'_group .form-control').attr('required','required');
					});
				  }
```

**Пример этого же javascript-кода без использования jQuery (для Bootstrap 5+).**

Обратите внимание на то, что в случае использования jQuery мы использовали метод `$('#elem').data('attr-name');`. Когда мы пишем на чистом javascript нам нужно указывать полностью имя атрибута: `data-fields`, `data-fields-required`.

```
let fields = button.getAttribute('data-fields');

if (typeof fields !== 'undefined'){
	fields = fields.split(',');
	fields.forEach(index => {
		let field = contactFormModal.querySelector('.contact_form_modal_' + index + '_group');
		field.style.removeProperty('display');
	});
}
let fieldsRequired = button.getAttribute('data-fields-required');
if (typeof fieldsRequired !== 'undefined'){
	fieldsRequired = fieldsRequired.split(',');

	fieldsRequired.forEach(index => {
		let field = contactFormModal.querySelector('.contact_form_modal_'+index+'_group .form-control');
		field.setAttribute('required','required');
	});
}
```

Подробно кейс создания множества форм в одной с примерами форм и кода был разобран здесь: [Интеграция форм обратной связи и Битрикс 24 на сайте Joomla](https://web-tolk.ru/blog/blog/integratsiya-form-obratnoj-svyazi-i-bitriks24-na-sajte-joomla.html).

Таким образом мы размещаем в коде сайта **только 1 модуль** с HTML-кодом формы обратной связи и в любом нужном нам месте кнопки для вызова модального окна с нужными data-атрибутами. А создание новой формы сводится к копированию кода кнопки и указанию нужных data-атрибутов. Также помним о том, что для Bootstrap 5+ data-атрибуты поменялись с `data-*` на `data-bs-*`.

```
<button class="btn btn-sm contact_form_modal_btn" data-toggle="modal" data-target="#contact_form_modal" data-form-title="Купить в 1 клик" data-form-subtitle="Вас интересует товар" data-vm-product-id="16869" data-fields="name,phone" data-fields-required="phone">Купить в 1 клик</button>
```

### Получение информации о товаре для формы обратной связи

Для красивого модального окна нам нужно брать информацию о товаре: картинку, название товара, артикул, цену.

#### Первый путь, совсем неправильный

Получение данных из HTML-верстки. Список товаров (категория). Разработчик в js-скрипте "стучится" в карточку товара, где указан класс или id с id или артикулом товара у родительского элемента. Таким образом можно получить путь картинки из `<img src="/..." class="product_image"/>` или название товара из `<span class="product_name">`.

Таким образом работает, например, ручная разметка целей аналитики мышкой в Яндекс.Метрике и Google Analytics. Если Вы поменяете HTML-разметку - проверьте работает ли отправка целей.

Огромный минус этого подхода в том, что если меняется дизайн и нарушается вложенность элементов - формы обратной связи "отваливаются" и нужно обновлять js-код.

Второе - если у сайта нет постоянного разработчика, то каждому следующему нужно разбираться в коде предыдущего. А далеко не все "чистят за собой" и порой в HTML-коде страницы видны "следы" нескольких разработчиков.

#### Второй путь, тоже неправильный

Приведу в качестве примера магазин на Virtuemart 3. Шаблоны дизайна для этого магазина делаются с помощью переопределений Joomla ([хороший мануал по шаблонам Virtuemart 3 и список макетов](https://wedal.ru/rasshireniya-joomla/nastrojka-shablona-virtuemart-3.html)). То есть файлы, где описана вёрстка, лежат в папке `templates/ваш_шаблон/html/com_virtuemart/`. В качестве подопытного кролика у нас будет список товаров в категории.

**Передача данных из php в javascript в Joomla**

Дело в том. что в Joomla есть простой и удобный способ передачи данных из php в javascript.

```
use Joomla\CMS\Factory;
//Массив данных о товарах Virtuemart
	$virtuemart_products = array();
// Добавление json-объекта с данными
	Factory::getDocument()->addScriptOptions('virtuemart_products_details',$virtuemart_products);
```

Данные передаются в виде json-объекта, доступ к которому с фронта получаем через функцию `Joomla.getOptions('virtuemart_products_details ')`. Это стандартная функция Joomla, никаких дополнительных плагинов для этого устанавливать не нужно.

Для этого мы идём в файл `templates/ваш_шаблон/html/com_virtuemart/category/default.php` и циклом добавляем нужные нам данные о товарах Virtuemart в отдельный массив.

```
<?php
use Joomla\CMS\Factory;
$doc = Factory::getDocument();
 //Данные товаров для форм обратной связи на Radical Form.
 // Доступ из js через let vm_products_data = Joomla.getOptions('virtuemart_products_details');
 // Каркас формы находится в модуле типа HTML-код. Там же js-обработка.
$vm_products_for_contact_form = array();
foreach($this->products as $product){
		//4-й параметр true возвращает только цену с валютой без HTML-обёртки
		$vm_price = $this->currency->createPriceDiv ('salesPrice', 'COM_VIRTUEMART_PRODUCT_SALESPRICE', $product->prices, true);
		$vm_products_for_contact_form[$product->virtuemart_product_id]['vm_product_name'] = $product->product_name;
		$vm_products_for_contact_form[$product->virtuemart_product_id]['vm_product_price'] = $vm_price;
		$vm_products_for_contact_form[$product->virtuemart_product_id]['vm_product_image_url'] = $product->file_url_thumb;
	}
$doc->addScriptOptions('virtuemart_products_details',$vm_products_for_contact_form);
?>
```

А затем получаем данные на фронте в js:

```
//Из документации Bootstrap - получаем последнюю нажатую кнопку
let button = $(event.relatedTarget);
// Заголовок модального окна и тема письма из data-атрибута
let formTitle = button.data('form-title');
// Id товара - ключ к массиву с данными
let vm_product_sku = button.data('vm-product-id');

let virtuemart_products_details = Joomla.getOptions('virtuemart_products_details');
let vm_product_name = virtuemart_products_details[vm_product_sku]['vm_product_name'];
let vm_product_price = virtuemart_products_details[vm_product_sku]['vm_product_price'];
let vm_product_image_url = virtuemart_products_details[vm_product_sku]['vm_product_image_url'];
```

Js-скрипт при клике на кнопку "купить в 1 клик" (например) из data-атрибутов считывает id товара и затем обращается в массив с данными, где id товара - ключ к получению значений. А дальше - дело техники - полученные данные подставляем в HTML-код формы обратной связи.

Для карточки товара аналогичные операции проводим с файлом `templates/ваш_шаблон/html/com_virtuemart/productdetails/default.php`

```
use Joomla\CMS\Factory;

/**
*	Добавляем опции для скрипта форм обратной связи с данными товара
*	- название
*	- артикул
*	- цена
*	- url миниатюры изображения
*
*	HTML-каркас формы находится в модуле типа HTML-код. Обработчик - плагин Radical Form.
*   Поля в форме скрываются/показываются динамически через js, который находится в том же модуле.
*   Заголовки модального окна, темы письма, подзаголовок берутся из data-атрибутов кнопки.
*/

$doc = Factory::getDocument();
$vm_price = $this->currency->createPriceDiv ('salesPrice', 'COM_VIRTUEMART_PRODUCT_SALESPRICE', $this->product->prices, true);
$vm_image = $this->product->images[0]->file_url_thumb;

$doc->addScriptOptions('virtuemart_products_details',array($this->product->virtuemart_product_id => array(
	'vm_product_name' => $this->product->product_name,
	'vm_product_price' => $vm_price,
	'vm_product_image_url' => $vm_image
	)
));
```

**Почему этот путь тоже неправильный?**

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

Логика сайта должна быть отделена от отображения. Поэтому **все подобные ситуации оформляются в Joomla в виде плагинов**. Системные плагины (группа system) срабатывают всегда и раньше, нежели плагины конкретных групп. Плагины групп срабатывают в определенном компоненте при определенных условиях. Если Вы знаете, что Ваш плагин должен работать только в одном конкретном месте - укажите ему группу плагинов. Это сэкономит ресурсы сервера, так как Ваш код не будет исполняться при каждом шевелении, а только в тот момент, когда он действительно необходим.

#### Третий путь, правильный - создание плагина

Приведем в качестве примера другой компонент интернет-магазина на Joomla - JoomShopping. Задача стоит та же самая. JoomShopping богат на триггеры для плагинов. Как создать плагин для Joomla - [читаем документацию](https://docs.joomla.org/J3.x:Creating_a_Plugin_for_Joomla). Это не так уж сложно.

Также Вам помогут мои статьи:

- [Создание плагинов с учётом новой структуры Joomla 4](https://habr.com/ru/articles/736412/)
- [Распространенные ошибки при написании плагинов Joomla 4](https://web-tolk.ru/blog/index.php?option=com_content&view=article&id=55:rasprostranennye-oshibki-pri-napisanii-plaginov-joomla-4&catid=10:blog&lang=ru-RU&Itemid=114)

Плагин создаем в группе `Jshoppingproducts`, таким образом не будет попытки выполнить наш код при просмотре статьей, страниц с контактами, при переходах в админке и т.д. Он будет работать только там, где надо. Так же наш код, будучи самостоятельным плагином, не пострадает при обновлении Joomla, при обновлении компонента магазина.

Для карточки товара мы находим событие `onAfterDisplayProduct`, куда приходит объект с данными товара.

```
use Joomla\CMS\Factory;
public function onAfterDisplayProduct(&$product)
	{
		$jShopConfig = JSFactory::getConfig();

		$product_info = array();
		$product_info['product_name'] =  $product->name;
		$product_info['product_image_url'] =  $jShopConfig->image_product_live_path.'/'.$product->image;
		$product_info['ean'] =  $product->product_ean;
		$product_info['old_price'] =  formatprice($product->product_old_price);
		$product_info['price'] = formatprice($product->product_price);
		$product_info['delivery_time'] =  $product->delivery_time;

    // Нужно для того, чтобы не переписывать js-код снаружи. Так же стучимся по id товара
		$product_array = array(
			$product->product_id => $product_info
		);

		$doc = Factory::getDocument();
		$doc->addScriptOptions('jshop_products_details',$product_array);

	}
```

Для категории товаров используем событие `onBeforeDisplayProductListView`, куда приходит `$view` целиком и список товаров отдельно `$productlist`**.**

Результат работы плагина будет таким:

Готовый плагин для добавления данных товара в json-объект для JoomShopping можно [скачать здесь](https://web-tolk.ru/blog/dev/joomla-plugins/wt-add-products-info-to-joomla-script-options.html).

**Updated:** с версии 1.1.1 плагин поддерживает Joomla 4. В плане работы плагина принципиальной разницы между Joomla 3 и Joomla 4 нет.

Добавлены параметры в настройку плагина:

![Скриншот настроек плагина Joomla 3](https://web-tolk.ru/blog/images/blog/razrabotka-form-obratnoj-svyazi-dlya-magazinov-na-joomla-3/ru-1.jpg)

![Скриншот настроек плагина Joomla 3 - 2](https://web-tolk.ru/blog/images/blog/razrabotka-form-obratnoj-svyazi-dlya-magazinov-na-joomla-3/ru-2.jpg)

![Скриншот настроек плагина Joomla 3 - 3](https://web-tolk.ru/blog/images/blog/razrabotka-form-obratnoj-svyazi-dlya-magazinov-na-joomla-3/ru-3.jpg)

## Пример JavaScript кода для получения данных во фронтенде

Это пример кода с использованием jQuery с одного из моих проектов. Не забудьте адаптировать данный код под свои нужды.

```
(function($) {
	      $('#contact_form_modal').on('shown.bs.modal', function (event) {
				  let button = $(event.relatedTarget);
				  let formTitle = button.data('form-title');
				  let formSubTitle = button.data('form-subtitle');
				  let product_id = button.data('product-id');
				  let comments = '';
				if (typeof product_id !== 'undefined'){

						let jshop_products_details = Joomla.getOptions('jshop_products_details');
						let product_name = jshop_products_details[product_id]['product_name'];
						let product_price = jshop_products_details[product_id]['price'];
						let product_image_url = jshop_products_details[product_id]['product_image_url'];
                  		let product_ean = jshop_products_details[product_id]['ean'];
						if (jQuery.isEmptyObject(jshop_products_details[product_id]) !== true) {
							comments = comments + formSubTitle + ' ' + product_name + ", код " + product_ean;
							formSubTitle =  "<span>" + formSubTitle + " <strong>" + product_name + ", код " + product_ean;
							if(product_image_url){
								let subTitleImg = "<img src=\"" + product_image_url +"\" width=\"auto\" height=\"64px\" class=\"me-2\" /> ";
								formSubTitle = subTitleImg + formSubTitle;
							}
							if(product_price){
								product_price = " за " + product_price;
								comments = comments + product_price;
								formSubTitle = formSubTitle + product_price;
							}

						formSubTitle = formSubTitle + "</strong></span>";
						//Запрос о скидки
						if(formTitle == 'Запрос скидки'){
						  comments = 'Я хочу получить скидку на ' + product_name +' код' +  product_ean + ' за '+ product_price + ' потому, что ...';
						}
					 }
				}//if typeof product_id !== 'undefined'

				let fields = button.data('fields');
                if (typeof fields !== 'undefined'){
                    fields = fields.split(',');
                    $(fields).each(function(index){
                        $('.contact_form_modal_' + fields[index] + '_group').show();
                    });
                }
				let fieldsRequired = button.data('fields-required');
				if (typeof fieldsRequired !== 'undefined'){
					fieldsRequired = fieldsRequired.split(',');
					$(fieldsRequired).each(function(index){
						$('.contact_form_modal_'+fieldsRequired[index]+'_group .form-control').attr('required','required');
					});
				  }

				let modal = $(this);
				modal.find('.modal-title').text(formTitle);
				modal.find('.modal-subtitle').html(formSubTitle);
				modal.find('.modal-body input[name=rfSubject]').val(formTitle);
           		modal.find('.modal-body [name=comments]').val(comments);

            console.log(comments);

            });//on('show.bs.modal'

			$('#contact_form_modal #agreement_gdpr').click(function() {
              if ($('#contact_form_modal #agreement_gdpr').is(':checked')) {
                	$('#contact_form_modal .rf-button-send').removeAttr("disabled", "disabled").fadeTo("slow",1);
              	}
              else
              	{
                  $('#contact_form_modal .rf-button-send').attr("disabled", "disabled").fadeTo("slow",0.4);
                }
            });

        $('#contact_form_modal').on('hide.bs.modal', function (event) {
            $('.form-group').hide();
          $('.form-group .form-control').removeAttr('required','required');
          $('#contact_form_modal').trigger('reset');
          $('#contact_form_modal .is-invalid').removeClass('is-invalid');

        });

})(jQuery);
```

## Пример Javascript-кода без использования jQuery

Так же не забудьте адаптировать код под реалии своего шаблона. Это пример кода для категории товаров.

```
(() => {
  document.addEventListener('DOMContentLoaded', () => {
	  let buy_one_click_buttons = document.querySelectorAll('.buy-one-click');

	  for (let i = 0, l = buy_one_click_buttons.length; l > i; i++) {
		  // Listen for click event

		  buy_one_click_buttons[i].addEventListener('click', event => {
			event.preventDefault();
			const {
			  target
			} = event;

			let product_id = target.getAttribute('data-product-id');
			if (typeof product_id !== 'undefined'){

				let jshop_products_details = Joomla.getOptions('jshop_products_details');
				let product_name = jshop_products_details[product_id]['product_name'];
				let product_ean = jshop_products_details[product_id]['ean'];
                let product_price = jshop_products_details[product_id]['price'];

				if(typeof product_price === 'undefined'){
					product_price = '';
				}

                let product_image_url = jshop_products_details[product_id]['product_image_url'];
				let product_image = "";

				if(product_image_url){
					product_image = "<img src=\"" + product_image_url +"\" width=\"auto\" height=\"64px\" class=\"me-2\" /> ";
				}
				console.log(product_image);
				let input_rfSubject = document.querySelector('#fast-order input[name=rfSubject]');
				input_rfSubject.value = target.getAttribute('data-form-title');

				let display_product_name = document.querySelector('#fast-order .product_name');
				display_product_name.innerText = product_name;

				let display_product_price = document.querySelector('#fast-order .price');
				display_product_price.innerText = product_price;

				let display_product_ean = document.querySelector('#fast-order .ean');
				display_product_ean.innerText = product_ean;

				let display_product_image = document.querySelector('#fast-order .product_image_url');
				display_product_image.innerHTML = product_image;

				let comments = 'Меня интересует товар ' + product_name + ' за ' + product_price + ', артикул ' +  product_ean;
				let input_comments = document.querySelector('#fast-order input[name=comments]');
				input_comments.value = comments;
			}
		  });
	  }
  });
 })();
```

Ещё один пример javascript кода. В целом в нём происходит всё то же самое.

```
// Формы обратной связи
// Вставить в template.js или в тело страницы
(() => {
  document.addEventListener('DOMContentLoaded', () => {
    const contactFormModal = document.getElementById('contact_form_modal');
    if (!contactFormModal) return;

    contactFormModal.addEventListener('show.bs.modal', (event) => {
      const button = event.relatedTarget;
      if (!button) return;

      const formTitle = button.getAttribute('data-form-title') || '';
      const formSubTitle = button.getAttribute('data-form-subtitle') || '';

      // Заголовки/поля
      const modalTitle = contactFormModal.querySelector('.modal-title');
      const modalSubTitle = contactFormModal.querySelector('.modal-subtitle');
      const modalBodyInput = contactFormModal.querySelector('.modal-body [name="rfSubject"]');

      if (modalTitle) modalTitle.textContent = formTitle;
      if (modalBodyInput) modalBodyInput.value = formTitle;

      if (modalSubTitle) {
        // если subtitle без HTML — лучше textContent
        modalSubTitle.innerHTML = formSubTitle;
      }

      // Перед показом: спрятать все группы и убрать required (чтобы не "залипало")
      contactFormModal.querySelectorAll('.form-group').forEach((g) => (g.style.display = 'none'));
      contactFormModal.querySelectorAll('.form-group .form-control').forEach((c) => c.removeAttribute('required'));

      // Показать нужные поля
      const fieldsRaw = button.getAttribute('data-fields'); // string | null
      if (fieldsRaw) {
        fieldsRaw
          .split(',')
          .map((s) => s.trim())
          .filter(Boolean)
          .forEach((name) => {
            const group = contactFormModal.querySelector(`.contact_form_modal_${name}_group`);
            if (group) group.style.removeProperty('display');
          });
      }

      // Сделать required
      const fieldsRequiredRaw = button.getAttribute('data-fields-required'); // string | null
      if (fieldsRequiredRaw) {
        fieldsRequiredRaw
          .split(',')
          .map((s) => s.trim())
          .filter(Boolean)
          .forEach((name) => {
            const control = contactFormModal.querySelector(`.contact_form_modal_${name}_group .form-control`);
            if (control) control.setAttribute('required', 'required');
          });
      }

      // Если цель "не отправлять скрытые" — надо disabled:
      contactFormModal.querySelectorAll('.form-group').forEach((group) => {
        const hidden = getComputedStyle(group).display === 'none';
        group.querySelectorAll('input, select, textarea, button').forEach((el) => {
          el.disabled = hidden;
        });
      });
    });
  });
})();
```

## Об авторе

![Толкачев Сергей Юрьевич](https://web-tolk.ru/images/uslugi/sergey-tolkachyov-apr-2023.webp)

### Толкачев Сергей Юрьевич

Joomla-разработчик. [Контрибьютер ядра Joomla](https://github.com/joomla/joomla-cms/pulls?q=is%3Apr+author%3Asergeytolkachyov+). Один из ведущих Telegram-канала русскоязычного Joomla-сообщества [JoomlaFeed](https://t.me/joomlafeed), один из модераторов [чата русскоязычного Joomla-сообщества](https://t.me/joomlaru). Мои расширения в официальном маркетплейсе расширений Joomla - [Joomla Extensions Directory](https://extensions.joomla.org/profile/profile/details/528051/). Имею публикации в [официальном журнале международного Joomla-сообщества - Joomla Community Magazine](https://magazine.joomla.org/authors/sergeytolkachyov) и на [официальном сайте русскоязычного Joomla-сообщества](https://joomlaportal.ru/users/sergey-tolkachyov).

Муж. Отец 3 детей.

Россия, Саратов.

## JSON-LD Schema

```json
{
    "@context": "https://schema.org",
    "@type": "BreadcrumbList",
    "@id": "https://web-tolk.ru/#/schema/BreadcrumbList/17",
    "itemListElement": [
        {
            "@type": "ListItem",
            "position": 1,
            "item": {
                "@id": "https://web-tolk.ru/",
                "name": "Главная"
            }
        },
        {
            "@type": "ListItem",
            "position": 2,
            "item": {
                "@id": "https://web-tolk.ru/blog",
                "name": "Блог"
            }
        },
        {
            "@type": "ListItem",
            "position": 3,
            "item": {
                "name": "Разработка форм обратной связи для магазинов на Joomla"
            }
        }
    ]
}
```

```json
{
    "@context": "https://schema.org",
    "@graph": [
        {
            "@type": "Organization",
            "@id": "https://web-tolk.ru/#/schema/Organization/base",
            "name": "WebTolk",
            "url": "https://web-tolk.ru/",
            "logo": {
                "@type": "ImageObject",
                "@id": "https://web-tolk.ru/#/schema/ImageObject/logo",
                "url": "images/webtolk-1080p.jpg",
                "contentUrl": "images/webtolk-1080p.jpg",
                "width": 1920,
                "height": 1080
            },
            "image": {
                "@id": "https://web-tolk.ru/#/schema/ImageObject/logo"
            },
            "sameAs": [
                "https://github.com/WebTolk",
                "https://github.com/sergeytolkachyov",
                "https://vk.com/web_tolk",
                "https://vk.com/webtolkru",
                "https://tenchat.ru/sergeytolkachyov",
                "https://t.me/sergeytolkachyov",
                "https://t.me/webtolkru"
            ]
        },
        {
            "@type": "WebSite",
            "@id": "https://web-tolk.ru/#/schema/WebSite/base",
            "url": "https://web-tolk.ru/",
            "name": "WebTolk",
            "publisher": {
                "@id": "https://web-tolk.ru/#/schema/Organization/base"
            }
        },
        {
            "@type": "WebPage",
            "@id": "https://web-tolk.ru/#/schema/WebPage/base",
            "url": "https://web-tolk.ru/blog/razrabotka-form-obratnoj-svyazi-dlya-magazinov-na-joomla",
            "name": "Разработка форм обратной связи для магазинов на Joomla - WebTolk",
            "description": "Статья о тонкостях разработки форм обратной связи для интернет магазинов на Joomla. Описанный способ подходит для построения форм не только для интернет магазин",
            "isPartOf": {
                "@id": "https://web-tolk.ru/#/schema/WebSite/base"
            },
            "about": {
                "@id": "https://web-tolk.ru/#/schema/Organization/base"
            },
            "inLanguage": "ru-RU",
            "breadcrumb": {
                "@id": "https://web-tolk.ru/#/schema/BreadcrumbList/17"
            }
        },
        {
            "@type": "Article",
            "image": "https://web-tolk.ru/images/blog/razrabotka-form-obratnoj-svyazi-dlya-magazinov-na-joomla-3/splash-1280x720.jpg",
            "headline": "Разработка форм обратной связи для магазинов на Joomla",
            "description": "Статья о тонкостях разработки форм обратной связи для интернет магазинов на Joomla. Описанный способ подходит для построения форм не только для интернет магазин",
            "@id": "https://web-tolk.ru/#/schema/com_content/article/43",
            "isPartOf": {
                "@id": "https://web-tolk.ru/#/schema/WebPage/base"
            }
        }
    ]
}
```
