Отправляем форму Ajax’ом и сохраняем письма в админке WordPress

Всем привет!

Сегодня рассмотрим как в WordPress отправлять формы c помощью ajax’a и сохранять отправленные письма в админке, Вы удивитесь, как на самом деле все просто.

thumb

Такой механизм задействован в одном из проектов 2015 в котором я участвовал, спасибо Сереге!

Пример я буду показывать на стандартной теме Twenty Fifteen, в процессе работы мы пройдем следующие этапы

  1. Создадим шаблон с формой и подключим его в подвале сайта
  2. Подключим стили и JS
  3. Создадим произвольный тип записи mail где будут храниться отправленные письма
  4. Напишем функцию обработки формы

Шаблон формы обратной связи

Создадим в папке inc файл contact-form.php, со следующим кодом:

<form action="<?php echo admin_url('admin-ajax.php?action=send_mail'); ?>" method="post" class="form-send-mail">

    <div class="form-view">

        <h4><?php _e('Написать сейчас'); ?></h4>

        <div class="form-field">
            <input type="text" id="client_fio" name="client_fio" placeholder="<?php _e('Ваше имя'); ?>" class="req-field"/>
        </div>

        <div class="form-field">
            <input type="text" id="client_mail" name="client_mail" placeholder="<?php _e('Ваш e-mail'); ?>" class="req-field rf-mail"/>
        </div>

        <div class="form-field">
            <textarea id="client_quest" name="client_quest" placeholder="<?php _e('Ваше сообщение'); ?>" class="req-field"></textarea>
        </div>

        <div class="form-submit">
            <button type="submit"><?php _e('Отправить'); ?></button>
        </div>

    </div>

    <div class="form-is-sending">
        <span class="pa-spinner"></span>
    </div>

    <div class="form-is-more">
        <button type="button">
            <?php _e('Отправить еще'); ?>
        </button>
    </div>

</form>

Пройдемся по форме

  • В атрибуте action указываем путь к обработчику нашей формы, в WordPress это файл admin-ajax.php, сама функция оработки данных send_mail описывается в файле functions.php
  • Контейнер div.form-view содержит поля формы и кнопку ‘отправки / отмены’ сообщения
  • Контейнер div.form-is-sending отображает лоадер, по умолчанию скрыт и расположен по центру блока с формой
  • В контейнере div.form-is-more находится кнопка ‘Отправить еще’, по умолчанию скрыта и расположена по центру блока с формой
  • Поля из которых мы будем собирать данные должны иметь заполненый атрибут name и класс .req-field — для проверки

Выведем форму в футере

Открываем файл footer.php и с помощью get_template_part() выводим контакную форму:

<footer id="colophon" class="site-footer" role="contentinfo">

	<?php get_template_part('inc/contact-form'); ?>

	<div class="site-info">

Займемся стилями и js’ом

Создадим в папке js файл с названием contact-form.js, а в папке css файл с название contact-form.css.

Откроем файл functions.php, найдем в нем функцию twentyfifteen_scripts() и подключим в ней наши стили и js для формы:

// Load contact form style
wp_enqueue_style('contact-form-style', get_template_directory_uri() . '/css/contact.css', array(), '20170101');
// Load contact form js
wp_enqueue_script('contact-form-js', get_template_directory_uri() . '/js/contact-form.js', array(), '20170101', true);

Оформление формы

я уже давненько юзаю Sass, поэтому обычный CSS Вы увидите, только в исходниках. Итак файл contact-form.css будет содержать ниже приведенный сконвертированный Sass:

.form-style {
    padding: 30px 0;
    background-color: #fff;
    position: relative;
    min-height: 400px;

    h4 {
        display: block;
        margin-bottom: 20px;
        font-size: 20px;
    }

    .form-view {
        position: relative;
        transition: opacity .3s, visibility .3s;
    }

    .form-is-sending {
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        z-index: 2;
        opacity: 0;
        visibility: hidden;
        transition: opacity .3s, visibility .3s;
    }

    .form-is-more {
        position: absolute;
        top: 50%;
        left: 50%;
        width: auto;
        height: auto;
        transform: translate(-50%, -50%);
        z-index: 3;
        opacity: 0;
        visibility: hidden;
        transition: opacity .3s, visibility .3s;
    }

    &.is-sending {
        .form-view {
            opacity: 0;
            visibility: hidden;
        }
        .form-is-sending {
            opacity: 1;
            visibility: visible;
        }
    }

    &.is-sending-complete {
        .form-view {
            opacity: 0;
            visibility: hidden;
        }
        .form-is-more {
            opacity: 1;
            visibility: visible;
        }
    }

}

.form-field {
    margin-bottom: 15px;

    input[type="text"],
    input[type="password"],
    input[type="email"],
    textarea {
        border: 0;
        border-bottom: 1px solid rgba(#000, .1);
        transition: border-color .3s;
        padding: 0 10px;
        width: 100%;
        box-sizing: border-box;
        height: 40px;
        font-family: Helvetica, Arial, sans-serif;
        font-size: 16px;
        color: #444;
        background: transparent;

        &.rf-error {
            border-color: #f04040;
        }
    }

    textarea {
        height: 100px;
        padding: 10px;
        overflow: auto;
        resize: none;
    }

}

.pa-spinner {
    position: absolute;
    top: 50%;
    left: 50%;
    width: 50px;
    height: 50px;
    z-index: 1;
    margin: -25px 0 0 -25px;
    border: 3px solid #ebebeb;
    border-radius: 50%;
    border-left-color: transparent;
    border-right-color: transparent;
    animation: cssload-spin 1325ms infinite linear;
}

@keyframes cssload-spin {
    100% {
        transform: rotate(360deg);
    }
}

@media screen and (min-width: 59.6875em) {
    .form-style {
        padding: 30px 10%;
    }
}

Пояснять тут особо нечего, это стили) играйте как хотите

Скриптик

jQuery(document).ready(function($){

	var form = $('.form-send-mail'),
		action = form.attr('action'),
		pattern = /^([a-z0-9_\.-])+@[a-z0-9-]+\.([a-z]{2,4}\.)?[a-z]{2,4}$/i;

	form.find('.req-field').addClass('empty-field');

	function checkInput() {
		form.find('.req-field').each(function () {
			var el = $(this);
			if (el.hasClass('rf-mail')) {
				if (pattern.test(el.val())) {
					el.removeClass('empty-field');
				} else {
					el.addClass('empty-field');
				}
			} else if (el.val() != '') {
				el.removeClass('empty-field');
			} else {
				el.addClass('empty-field');
			}
		});
	}

	function lightEmpty() {
		form.find('.empty-field').addClass('rf-error');
		setTimeout(function () {
			form.find('.rf-error').removeClass('rf-error');
		}, 1000);
	}

	$(document).on('submit', '.form-send-mail', function (e) {
		var formData = {
			client_fio: $('#client_fio').prop('value'),
			client_mail: $('#client_mail').prop('value'),
			client_quest: $('#client_quest').prop('value')
		};

		$.ajax({
			type: 'POST',
			url: action,
			data: formData,
			beforeSend: function () {
				form.addClass('is-sending');
			},
			error: function (request, txtstatus, errorThrown) {
				console.log(request);
				console.log(txtstatus);
				console.log(errorThrown);
			},
			success: function () {
				form.removeClass('is-sending').addClass('is-sending-complete');
			}
		});

		e.preventDefault();

	});

	$(document).on('click', '.form-send-mail button[type="submit"]', function (e) {

		checkInput();

		var errorNum = form.find('.empty-field').length;

		if (errorNum > 0) {
			lightEmpty();
			e.preventDefault();
		}

	});

	$(document).on('click', '.form-is-more button', function () {

		form.find('input').val('');

		form.find('textarea').val('');

		form.removeClass('is-sending-complete');

	});

});

Скрипт очень простой:

  1. Объявляем переменные необходимые нам для работы — форма, путь к обработчику формы и патерн для проверки мыла
  2. Всем обязательным полям добавляем класс empty-field
  3. Функция checkInput() проверяет поля на заполненность и корректность email’а
  4. Функция lightEmpty() подсвечивает проблемные поля классом rf-error
  5. Далее пишем обработчик отправки формы (о нем ниже подробней)
  6. Следующим шагом описываем клик по кнопке отправки формы — по клику запускается функция checkInput(), считаем к-во ошибочных полей, если они есть то запускается функция lightEmpty() и процесс прекращается, в противном случае происходит обработка отправки формы
  7. И финальный этап это клик по кнопке «Отправить еще» — по клику очищаются поля формы и у формы удаляется класс, который показывает кнопку

Обработчик отправки формы:

  1. в массив formData — собираем данные формы
  2. запускаем Ajax обработчик
  3. в фукнции beforeSend добавляем форме класс is-sending — тоесть скрываем форму и показывается лоадер
  4. в фукнции error — если он есть то в консоль выводятся всевозможные ошибки
  5. в фукнции success у формы удаляется класс is-sending и добавляется класс is-sending-complete — то есть скрывается лоадер и форма, а показывается кнопка с предложением отправить еще одну форму
  6. предотвращаем обычное поведение элемента — перезагрузку страницы

Итак на данном этапе мы получили красиво оформленную форму в подвале сайта, для которой осталось написать php обработчик для полученных данных.

Создадим произвольный тип записи

Произвольный тип записи нужен для хранения отправленных писем в базе данных сайта, соответственно письма будут доступны из админки WordPress. Открываем файл functions.php и в самом низу добавляем следующий код:

add_action( 'init', 'cpt_mail_calback' );

function cpt_mail_calback() {

    $labels = array(
        "name" => "Mail",
        "singular_name" => "Mail",
        "menu_name" => "Mail",
        "all_items" => "All mail",
        "add_new" => "Add New",
        "add_new_item" => "Add New",
        "edit" => "Edit",
        "edit_item" => "Edit",
        "new_item" => "New item",
        "view" => "View",
        "view_item" => "View item",
        "search_items" => "Search item",
        "not_found" => "No found",
        "not_found_in_trash" => "No found",
    );

    $args = array(
        "labels" => $labels,
        "description" => "",
        "public" => true,
        "show_ui" => true,
        "has_archive" => false,
        "show_in_menu" => true,
        "exclude_from_search" => true,
        "capability_type" => "post",
        "map_meta_cap" => true,
        "hierarchical" => true,
        "rewrite" => false,
        "query_var" => true,
        "menu_position" => 7,
        "menu_icon" => "dashicons-email-alt",
        "supports" => array( "title", "editor" ),
    );

    register_post_type( "mail", $args );

}

Сохраним файл, обновим админку и увидим в меню пункт «Mail», в этом произвольном типе записи будут хранится все отправленные нам письма. Следующим шагом опишем функцию обработки ajax запроса send_mail().

Ajax обработчик формы

function send_mail() {

  /* Забираем отправленные данные */
  $client_fio = $_POST['client_fio'];
  $client_mail = $_POST['client_mail'];
  $client_quest = $_POST['client_quest'];

  /* Отправляем нам письмо */
  $emailTo = 'admin@test.com';
  $subject = 'Test mail рассылки!';
  $headers = "Content-type: text/html; charset=\"utf-8\"";
  $mailBody = "$client_fio <br/><br/> $client_mail <br/><br/> $client_quest";

  wp_mail($emailTo, $subject, $mailBody, $headers);

  /* Создаем новый пост-письмо */
  $post_data = array(
   'post_title'    => $client_fio,
   'post_content'  => $client_quest . '<br/>' .$client_mail,
   'post_status'   => 'publish',
   'post_author'   => 1,
   'post_type' => 'mail',
  );

  wp_insert_post( $post_data );

  /* Завершаем выполнение ajax */
  die();
  
}

add_action("wp_ajax_send_mail", "send_mail");
add_action("wp_ajax_nopriv_send_mail", "send_mail");

Все. Обработчик формы готов, теперь смело заходим на наш локальный сайт, заполняем или не заполняем поля, кликаем по отправке, дозаполняем поля, чтобы форма отправилась, кликаем еще раз отправить… и все готово. Форма отправлена, можем отправить еще раз если сильно охота, переходим в админку и видим что у нас появилась новая запись с информацией отправленного письма. Ура!)

Послесловие #1

Будет ситуация когда Вам не нужно хранить письма в админке, это 100% )

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

Послесловие #2

Если хотите отправить письмо на несколько email адресов, то их нужно перечислить через запятую:

$emailTo = 'admin@test.com, sale@test.com, info@test.com';

Послесловие #3

Бонус #1 — Заменяем имя отправителя

function htm_mail_name( $email ){
    return 'Howtomake';
}
add_filter( 'wp_mail_from_name', 'htm_mail_name' );

Бонус #2 — Заменяем email отправителя

function htm_mail_from ($email ){
    return 'info@howtomake.com.ua';
}
add_filter( 'wp_mail_from', 'htm_mail_from' );

Заключение

Это первая полноценная статья за последние… года 2-4 (может дольше) извиняйте, что редко пишу..

У Вас теперь есть полноценный инструмент для отправки и обработки практически любых форм в WordPress. Вопросы, пожелания, непонятки и благодарности пишите в комментариях. Всем хорошего настроения

Добавить комментарий: