Всем привет. В данном посту мы рассмотрим простой пример создания формы обратной связи, форму обратного звонка на сайте. Реализовать форму вы сможете у себя на сайте, это может быть отдельная страница, либо модальное окно, которое будет доступно при клике на определённые кнопки. Заявки, отправляемые с формы, будут записываться в информационных блок, так же администрации сайта будут отправляться почтовые уведомления о новых заявках.
Теперь давайте приступим непосредственно к примеру. Первым делом, что требуется нам сделать, это подготовить информационный блок, в который будут записываться данные, а также, создать почтовое событие + шаблон для отправки письма уведомления на почту.
Создаем информационный блок «Заявки», и добавляем свойства для информационного блока. В моём примере путь к созданию нового инфоблока следующий:
Контент > Инфоблоки > Типы инфоблоков > Каталог > Добавить инфоблок
Назначение полей свойств говорит само за себя, мы будет записывать ID элемента, с которого отправляется форма, имя пользователя, телефон, почтовый адрес, а также записывать URL страницы, с которой были отправлены данные.
Далее создаём почтовое событие, которое будет вызываться при успешной отправке данных с формы на сервер.
Добавить новое почтовое событие можно по пути:
Настройки > Настройки продукта > Почтовые события > Типы почтовых событий > Добавить тип
Тип почтового события я указал как NEW_USER_RESPONSE, в самом деле вы можете назвать его по-своему, это не так принципиально. Далее создаем почтовый шаблон, который будет использован для отправки писем на почту администрации сайта.
Путь к созданию нового почтового шаблона такой:
Настройки > Настройки продукта > Почтовые события > Почтовые шаблоны > Добавить шаблон
Выбираем в качестве почтового события запись с кодом NEW_USER_RESPONSE, далее, как показано на скриншоте:
После того как сохранили почтовый шаблон, можно приступать непосредственно к самой форме отправки. Сайт, который использовался в примере свёрстан с использованием bootstrap 4, этого не говорит о том, что вам необходимо его так же использовать. Вы можете реализовать эту форму самостоятельно, без использование сторонних фреймворков для верстки. В моём же примере используется модальные окна, которые хорошо описаны в документации по bootstrap 4.
Сам код формы я поместил в основной файл шаблона header.php, так как модальное окно с формой должно быть доступно по всему сайту.
<!--modal--> <div class="modal" tabindex="-1" role="dialog" id="customer-response"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title">Напишите нам</h5> <button type="button" class="close" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">×</span> </button> </div> <div class="modal-body"> <div class="md-resp-msg"></div> <form id="cust-resp-form" class="contact" name="contact" action="#" method="post"> <input type="hidden" name="resp_item_id" id="resp_item_id" value="0"> <div class="form-group"> <label for="md-resp-name">Представьтесь<span class="red-text">*</span></label> <input type="text" id="md-resp-name" name="md-resp-name" class="form-control" placeholder="Иван Иванов" required=""> </div> <div class="form-group"> <label for="md-resp-phone">Телефон<span class="red-text">*</span></label> <input type="text" id="md-resp-phone" name="md-resp-phone" class="form-control" placeholder="+7(___)___-__-__" required=""> </div> <div class="form-group"> <label for="md-resp-email">Почта</label> <input type="text" id="md-resp-email" name="md-resp-email" class="form-control" placeholder="example@mail.ru"> </div> <div class="form-group"> <label for="md-resp-message">Описание заявки</label><br> <textarea name="md-resp-message" class="form-control" rows="5" id="md-resp-message"></textarea> </div> <div class="form-group"> <p class="required-fields">* Обязательные поля для заполнения</p> <p class="user-agrement">Нажимая кнопку, я принимаю <a href="#">соглашение о конфиденциальности</a> и соглашаюсь с обработкой персональных данных</p> </div> </form> </div> <div class="modal-footer"> <button type="button" class="md-resp-send">Отправить</button> </div> </div> </div> </div>
Кнопка вызова модального окна так же располагается на странице, выглядит она таким образом:
<a href="javascript:void(0);" class="top-nav_callback" data-toggle="modal" data-target="#customer-response">Заказать обратный звонок</a>
Итак, действие с открыванием и закрыванием модального окна выполняется самим фреймворком bootstrap, и большого интереса для нашего поста это не представляет. Для нас интересна сама отправка данных с формы. Начинать проверку полей и отправку мы будем при нажатии на кнопке «отправить».
Код написан на js + jquery, выполняет валидацию заполнения полей, а также отправку данных на сервер:
// ----------- callback response --------------- $(".md-resp-send").on("click",function(e){ e.preventDefault(); $(".md-resp-msg").hide(); $(".md-resp-msg").html(''); var err=0; // person name if ( $("#md-resp-name").val() == '' ){ err++ $("#md-resp-name").addClass("hasError"); } else { $("#md-resp-name").removeClass("hasError"); } // phone if ( $("#md-resp-phone").val() == '' ){ err++ $("#md-resp-phone").addClass("hasError"); } else { $("#md-resp-phone").removeClass("hasError"); } // email if ( $("#md-resp-email").val() != '' ){ var pattern = /\S+@\S+\.\S+/; if ( !pattern.test( $("#md-resp-email").val() )){ err++ $("#md-resp-email").addClass("hasError"); } else { $("#md-resp-email").removeClass("hasError"); } } else { $("#md-resp-email").removeClass("hasError"); } var resp_type = ''; if ( $("#resp_item_id").val() == 0 ){ resp_type = '?action=call'; } if (err == 0){ $.ajax({ type: "POST", url: '/ajax.customer-response.php'+resp_type, data: { 'item_id': $("#resp_item_id").val(), // set in catalog.js 'name': $("#md-resp-name").val(), 'phone': $("#md-resp-phone").val(), 'email': $("#md-resp-email").val(), 'message': $("#md-resp-message").val() }, dataType: "json", success: function(data){ if (data.status == true){ $("#md-resp-name").val(''); $("#md-resp-phone").val(''); $("#md-resp-email").val(''); $("#md-resp-message").val(''); } if (data.msg && data.msg.length > 0){ $(".md-resp-msg").fadeIn(); $.each( data.msg, function( key,field ) { if (field.type == true){ $(".md-resp-msg").append('<p class="md-true">'+field.text+'</p>'); } else { $(".md-resp-msg").append('<p class="md-error">'+field.text+'</p>'); } }); } } }); } });
Хотелось бы немного пояснить по коду js. В коде объявляется переменная err, которая по сути является счётчиком ошибок при валидации. Если ошибок проверки полей не возникало, то значение счётчика соответственно равно 0. Это означает что после проверки полей, будет выполняться отправка данных на сервер, посредством ajax-запроса. В случае успешной отправки, значения полей будет очищаться. Если сервер отправил сообщение об ошибке или успешной отправке, они будут записываться в блок с классом .md-resp-msg, с указанием дополнительного класса для типа сообщения .md-true или .md-error. Это используется для стилизации цвета текста сообщения.
В корне сайта создаем ajax.customer-response.php который будет выполнять код на стороне сервера, при ajax-запросе.
// подключаем пролог, для использования Bitrix API без подключения шаблона require_once($_SERVER['DOCUMENT_ROOT'] . "/bitrix/modules/main/include/prolog_before.php"); // поключаем модуль инфоблоков CModule::IncludeModule('iblock'); $arResult = array('status' => false); // переменная для результата $err = 0; // счётчик ошибок $PROP = array(); // данные для полей элемента инфоблока // если передан ID элемента, то заявка отправлена со страницы карточки товара if (isset($_POST['item_id']) && $_POST['item_id'] > 0){ $PROP['ITEM_ID'] = (int)$_POST['item_id']; } // имя пользователя if (isset($_POST['name']) && !empty($_POST['name'])){ $PROP['PERSON_NAME'] = htmlspecialchars( $_POST['name'], ENT_QUOTES ); } else { $err++; $arResult['msg'][] = array( 'text' =>'Вы не указали Ваше имя.', 'type' => false ); } // указываем тему отклика, в зависимости от передаваемого типа if (isset($_POST['action']) && $_POST['action'] == 'call'){ $TITLE = 'Новая заявка звонка с сайта: '.$PROP['PERSON_NAME'].' от '.date("d.m.Y H:i:s"); } else { $TITLE = 'Новая заявка: '.$PROP['PERSON_NAME'].' от '.date("d.m.Y H:i:s"); } // номер телефона if (isset($_POST['phone']) && !empty($_POST['phone'])){ $PROP['PHONE'] = htmlspecialchars( $_POST['phone'], ENT_QUOTES ); } else { $err++; $arResult['msg'][] = array( 'text' =>'Вы не указали номер телефона.', 'type' => false ); } // почтовый адрес if (isset($_POST['email']) && filter_var($_POST['email'], FILTER_VALIDATE_EMAIL)){ $PROP['EMAIL'] = htmlspecialchars( $_POST['email'], ENT_QUOTES ); } // сообщение от пользователя if (isset($_POST['message']) && !empty($_POST['message'])){ $PREVIEW_TEXT = htmlspecialchars( $_POST['message'], ENT_QUOTES ); } // страница, с которой был отправлен запрос $PROP['HTTP_REFERER'] = $_SERVER['HTTP_REFERER']; if ($err == 0){ $el = new CIBlockElement; // массив полей для нового элемента $arElem = Array( "IBLOCK_SECTION_ID" => false, "IBLOCK_ID" => 9, "PROPERTY_VALUES"=> $PROP, "NAME" => $TITLE, "ACTIVE" => "Y", "PREVIEW_TEXT" => $PREVIEW_TEXT ); if ($PRODUCT_ID = $el->Add($arElem)){ // устанавливаем статус $arResult['status'] = true; $arResult['msg'][] = array( 'text' =>'Ваши данные отправлены успешно!<br>Ожидайте звонка наших операторов.', 'type' => true ); // подготавливаем поля для почтового события $arEventFields = array( 'ITEM_ID' => $PROP['ITEM_ID'], 'PERSON_NAME' => $PROP['PERSON_NAME'], 'PERSON_MAIL' => $PROP['EMAIL'], 'PERSON_PHONE' => $PROP['PHONE'], 'HTTP_REFERER' => $PROP['HTTP_REFERER'], 'RESPONSE_THEME' => $TITLE ); // отправка почты CEvent::Send("NEW_USER_RESPONSE", "s1", $arEventFields); } else { $arResult['msg'][] = array( 'text' =>'Не удалось сохранить запись. ' . $el->LAST_ERROR, 'type' => false ); } } echo json_encode($arResult);
Код на стороне сервера довольно прост, не смотря на его объем. Первое что выполняется – проверка отправленных полей, количество ошибок записывается в переменную $err, как вы, наверное, уже поняли с примером на js, если количество ошибок равно нулю, создается элемент в инфоблоке, а после вызывается почтовое событие, которому передаются ключевые поля для почтового шаблона. В качестве результата скрипт возвращает массив полей, конвертированный в строку json. Ключевой параметр в массиве, обозначающий успешность выполнения операции называется «status», по умолчанию он равен false, при успешном выполнении параметр переводится в значение true. Параллельно с ним, так же отправляются сообщения посредством поля msg. Сообщение формируется из двух полей, text – текст сообщения, type – обозначает тип сообщения, может быть true – успех, false – ошибка. Вот в целом собственно и всё. Если остались какие-либо вопросы, вы можете писать их в комментарии. Разумеется, форму можно переделать под ваши нужды, к примеру, добавить полей, или наоборот убрать их. Всё зависит от ваших задач.
Добрый день. Расскажите как подключить гугл капчу к данной форме? Заранее благодарен.
Установка reCAPTCHA на сайт
Добрый день! Спасибо за хорошую и подробную инструкцию. Остался вопрос, как грамотно использовать 5 форм (с учетом в любом месте сайта, на одной или разных страницах) желательно не через id (например класс, конечно кроме ID самой форм), все формы с разным набором полей (где одно, а где четыре). Подскажите как правильно исправить ваш код.
Если набор полей отличается, то стоит их условно разбить на типы, для каждого типа формы прописать проверку, аналогично примеру. Если поле id не принципиально, то можно исключить отправку item_id в Ajax запросе.
Добрый день!
Скажите код в ajax.customer-response.php указывать как в примере или синтаксис в примере не полный (в частности нету в конце)
Также у меня проблема.
Не выводится информация о не заполненных полях при попытке отправить пустые.
Однако, если эти поля удалить совсем в html, то при попытки отправки сообщения о незаполненных полях появляются
Код указанный в примере рабочий, и актуален для данной формы. В php-скрипте проверяются поля которые ему передаются, затем записываются в инфоблок и отправляется письмо. Если передаваемые поля не отличаются от примера, то переделывать ничего не нужно, разве что указать IBLOCK_ID вашего инфоблока, и создать почтовое событие как в примере.
Спасибо!
Подскажите пожалуйста, при удалении поля Имя пользователя, и при попытке отправки, появляется ошибка:
"Не удалось сохранить запись. Не введено название."
В массиве добавляемого элемента $arElem нужно задать название для элемента поле NAME
Я прошу прощения за назойливость, но я не очень хорошо знаю bitrix. Не могли бы вы дать более наглядный ответ, на вопрос как отправлять разные формы с разным количеством полей. Так что бы они не выдавали ошибки на поля которых нет. Т.е. есть две формы у одной только телефон, у другой почта и телефон. Напишите пожалуйста участок кода который нужно заменить и на что что бы обе формы работали независимо с теми полями которые даны по условию выше. Буду очень сильно благодарен Вам и вашему ресурсу.
Данная форма не совсем подходит под ваши задачи, скрипт работает с некоторыми атрибутами id элементов на форме (как вы знаете id в структуре страницы не должен повторяться), поэтому нужно переделывать разметку, переделывать js-обработчик, и проверку на стороне сервера.
Добрый вечер!
Подскажите, пожалуйста, почему не приходят уведомления о наличии заполненной формы?
В каком направлении курить? Сайт базируется у хостинг провайдера.
Заполненные формы успешно сохраняются
Стоит проверить создаётся ли запись в базе, таблица b_events, там же есть колонка со статусом отправки.
Добрый день,
Проверил, события в b-event сохраняются
Статус отправки это я так понял колонка SUCCES_EXEC там у всех 0
Разобрался
Причина проблемы была в том что:
в файле ajax.....-widget-response.php
в самом низу где строка:
// отправка почты
CEvent::Send("NEW_USER_RESPONSE", "s1", $arEventFields);
вместо : NEW_USER_RESPONSE нужно указывать название из "Тип события: NEW_PARTNER_JOIN" - указанного на этапе создания типа события.
Огромное спасибо автору статья, форма агонь!
Добрый день, все формы перестали работать
в базе данных таблицы b_events
DATE_EXEC
NULL
SUCCESS_EXEC
N
Скажите, пожалуйста, может это быть вызвано обновлениями Битрикса и каком направлении искать ошибку?
Спасибо!
Агенты в Bitrix выполняются по крону или на хитах?
Подскажите, пожалуйста, , блок кода js вставляется в тот же файл ajax.customer-response.php?
Нет, js-код должен исполняться в браузере пользователя и загружаться вместе с html-формой
Добрый день, подскажите пожалуйста.
Если нужно две формы одна которая уже есть на странице а другая открывается по кнопке.
Как это можно реализовать у меня не получается.
У html-элементов значения атрибутов id на странице должны быть уникальными. Выход из ситуации - использовать CSS классы вместо id, и из JQuery обращаться к классам, а не по атрибуту id.
Добрый вечер, поменял id на class. Заработало только теперь если есть 2 формы нужно что бы обе были заполнены как сделать что бы не надо было заполнять обе, а только одну?
Думаю можно попробовать найти общий родительский элемент для формы где была нажата кнопка отправки,
после уже уже обращаться ко вложенным полям относительно текущего родительского элемента.
Помогло спасибо.
Добрый день! Подскажите где, в каком файле и как вставить код отслеживания цели в Метрике вида: ym(XXXXXX,'reachGoal','target')
Спасибо!
Добрый день, если хотите отслеживать сам факт отправки формы пользователем, то при возврате статуса ajax-запроса (success).
Спасибо!
Добрый день, к сожалению на сайте перестали работать формы
Есть подозрение что в структуре битрикса произошли некоторые изменения и теперь данная схема не работает
При попытке отправить форму страница перезагружается, данные не отправляются
Стоит отметить что, в случае не заполнения всех полей перестала работать проверка, а именно не отображается уведомление о некорректном или не полном заполнении формы
В этой связи склоняюсь к тому что проблема не в битриксе...
Добрый день. Смотрите ошибки в консоли браузера, с большой вероятностью что-то не так с JS-скриптами.
Здравствуйте!
По какой-то причине не отрабатывает JS, то есть вообще не отрабатывается код при нажатии на кнопку отправить.
Вероятно есть ошибки в синтаксисе JS, из-за чего перестаёт выполняться скрипт. Смотрите ошибки в консоли браузера.