Простая форма обратной связи для WordPress-темы - Блог chomovva

Форма обратной связи или форма оставления заявки в том или ином виде существует на подавляющем большинстве сайтов. По сути это способ связи с владельцем. Можно написать электронный адрес, но это не очень удобно потому, что пользователь может не иметь возможности воспользоваться своей почтой. Это вынудит его уйти со страниц сайта, что бы авторизоваться в почте. Форма обратной связи – наиболее удобный способ общения между владельцем и посетителями.

Форма обратной связи обычно содержит минимум полей и единственную кнопку «Отправить». Правилом хорошего тона будет проверка полей формы перед отправкой и информирование о результате. То есть после обработки сообщения нужно показать ответ. это может быть «Спасибо, Ваше сообщение отправлено. Мы ответим вам в течение 1 часа» или «К сожалению сейчас невозможно отправить Ваше сообщение, попробуйте позже или напиши администратору сайта admin@example.com». Если же ничего не произойдёт, то это скорей всего запутает пользователя и создать плохое впечатление о сайте.

Варианты реализации

Добавить форму обратной связи можно установив один из плагинов Contact Form 7, WPForm, Ninja Forms или любого подобного. Это просто, быстро, нет необходимости «лазить в код», плагины могут иметь широкий дополнительный функционал. Но когда нужна только одна форма из нескольких полей, это не оправдано. Установка и работа плагина создаёт дополнительную нагрузку на сервер, плагин встроит на страницу дополнительные скрипты и стили, которые незначительно, но увеличат время загрузки страницы. Такой с установкой плагина подойдёт когда на сайте используется много форм или достаточно сложные формы. Если нужен дополнительный функционал, такой как сохранение писем в базу данных или выгрузка в Google Таблицы прочее, то без плагина просто не обойтись.

Наша форма обратной связи будет «дефолтной», т.е. доступной сразу после установки темы. Её настройка не потребует дополнительных телодвижений от администратора сайта. Такую форму просто сделать с помощью шорткода. Если пользователь в дальнейшем захочет расширить функционал формы, то он всегда сможет установить плагин и заменить шорткод на новый сгенерированный плагином.

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

Предположим, что внизу главной странице нашего сайта будет форма обратной связи, эта же форма появится и на внутненей странице «Контакты». На главную добавим её с помощью настроек, а на внутрених – шорткода в видуальном редакторе. Сейчас хорошим тоном при создании темы будет использование настроек добавленны в Customizer API.

Настройка формы обратной связи в Customizer API темы
Настройка формы обратной связи в Customizer API темы
Форма обратной связи в публичной части сайта
Форма обратной связи в публичной части сайта

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

$wp_customize->add_setting(
	"{$slug}_questions_shortcode",
	array(
		'default'           => '[contacts_form]',
		'transport'         => 'reset',
		'sanitize_callback' => 'sanitize_text_field',
	)
);
$wp_customize->add_control(
	"{$slug}_questions_shortcode",
	array(
		'section'           => "{$slug}_questions",
		'label'             => __( 'Шорткод формы', $textdomain),
		'type'              => 'text',
	)
); /**/
echo get_theme_mod( "{$slug}_questions_shortcode", '[contacts_form]' );

Регистрация шорткода и его описание

Шорткоды — это функции PHP, которые можно задействовать внутри содержимого поста, используя условные обозначения. Шорткод имеет вид [ xxxxxxxx arg1=value arg2=value ], где xxxxxxxx это имя шорткода, а arg1=value параметр и его значение. Пример стандартного вордпрессовского шорткода [ gallery ], он позволяет вывести галерею внутри поста. Шорткод нашей формы будет иметь такой вид: [ defaut_contact_form ]

Подробней про работу шорткодов: Shortcode API.

function get_defaut_contact_form() {
    // реализация шорткода
}
add_shortcode( 'defaut_contact_form', 'get_defaut_contact_form' );
примерная схема работы шорткода
примерная схема работы шорткода

Защита от спама

Форму нужно обязательно защитить от ботов, иначе Вашу почту забросают спамом. Существует множество методов, описанные ниже наиболее простые, т. к. они не требуют каких либо зависимостей, сторонних библиотек и их довольно быстро реализовать.

«Бочка с мёдом»

Суть метода «бочка с мёдом» это добавление скрытого поля с красивым именем email, name, password в форму. Это поле будет видно для ботов и не видно для посетителей сайта, бот не различает видимость полей и заполнит это поле в соответствии с именем. Далее в обработчике формы добавляем условие проверки на пустое поле. Если поле пустое — всё норм, продолжаем работать, если поле заполнено — это бот.

Черный список WordPress

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

wp_blacklist_check( $author, $email, $url, $comment, $user_ip, $user_agent );

Функция проверяет содержит ли комментарий символы или слова из черного списка. Чёрный список заполняется в стандартных настройках WordPress: Настройки → Обсуждение → Чёрный список. По умолчанию это поле пустое и при настройки его нужно заполнить.

Помимо проверки на «стоп-слова» чёрного списка эта функция создаёт одноимённое событие-зацепку для произвольных функций, т. е. если на сайте установлены плагины безопасности или фильтры спама, то они тоже сработают и проверят данные формы.

Защита с помощью времени формирования формы

Форма обратной связи не требует много времени для заполнения, конечно может найтись «юзверь», который будет заполнять её несколько суток, а то и недель, но это очень маловероятно. А боты «просканируют» поля формы один раз и будут пытаться отправлять на неё спам напрямую без перегенерации. Чтобы такого не произошло нужно добавить скрытое поле с зашифрованным временем формирования формы на сервере, а при отправке сравнивать с текущим. Разница должна быть не более суток, хотя промежуток можно сделать меньше.

Отправка письма

Для отправки письма воспользуемся стандартной функцией WordPress wp_mail. Эта функция похожа на mail() в PHP, но создаёт ряд фильтров и хуков, которыми могут воспользоваться установленные плагины, к примеру SMTP Mailer.

По умолчанию имя отправителя: WordPress, а email: wordpress@yoursite.com, но мы их изменим подставив имя и email пользователя отправившего форму.

Адресат — администратор сайта, email которого указывается в: Настройки → Общие настройки → Административный адрес email.

Функция возвращает true/false. true — удалось отправить письмо. false — не удалось.

<?php
function get_defaut_contact_form() {
  // получаем md5-хеш с текущей датой, в дальнейшем он будет использоваться с скрытом поле формы и для защиты от использования "слепков" формы
  $check = md5( date( 'Y-m-d' ) );
  // объявляем массив полей формы и инициализируем его исходными данными
  $fields = array( 'email' => '', 'author' => '', 'message' => '', 'check' => '' );
  // в эту переменную будет записан результат работы шорткода
  $result = __return_empty_string();
  // проверяем нужно ли вывести пустую форму или обработать данные
  if ( isset( $_POST[ 'check' ] ) && isset( $_POST[ 'resume_contact_form_data' ] ) ) {
    // email - обязательное поле, без него нет смысла продолжать, проверяем наличие этого поля и дату заполнения формы
    if ( isset( $_POST[ 'email' ] ) && empty( $_POST[ 'email' ] ) && $_POST[ 'check' ] == $check ) {
      // получаем и очищаем имя пользователя
      if ( isset( $_POST[ 'resume_contact_form_data' ][ 'author' ] ) ) {
        $fields[ 'author' ] = sanitize_text_field( $_POST[ 'resume_contact_form_data' ][ 'author' ] );
      } else {
        $fields[ 'author' ] = '';
      }
      if ( empty( trim( $fields[ 'author' ] ) ) ) {
        $fields[ 'author' ] = __( 'Аноним', RESUME_TEXTDOMAIN );
      }
      // получаем и очищаем поле email пользователя
      $fields[ 'email' ] = sanitize_email( $_POST[ 'resume_contact_form_data' ][ 'email' ] );
      // получаем и очищаем текст сообщения
      $fields[ 'message' ] = sanitize_textarea_field( $_POST[ 'resume_contact_form_data' ][ 'message' ] );
      // проверяем корректнось введённого email адреса
      if ( is_email( $fields[ 'email' ] ) ) {
        // получаем IP пользователя, который будет нужен при проверке в "черном списке"
        $user_ip = __return_empty_string();
        if ( ! empty( $_SERVER[ 'HTTP_CLIENT_IP' ] ) ) {
          $user_ip = $_SERVER[ 'HTTP_CLIENT_IP' ];
        } elseif ( ! empty( $_SERVER[ 'HTTP_X_FORWARDED_FOR' ] ) ) {
          $user_ip = $_SERVER[ 'HTTP_X_FORWARDED_FOR' ];
        } else {
          $user_ip = $_SERVER[ 'REMOTE_ADDR' ];
        }
        // проверяем содержит ли форма поля из черного списка, если нет, то начинаем формировать сообщение
        if ( ! wp_blacklist_check( $fields[ 'author' ], $fields[ 'email' ], '', $fields[ 'message' ], $user_ip, '' ) ) {
          // формирование сообщения админу
          ob_start();
          ?>
            <table cellspacing="0" style="border: 1px solid #bbbbbb; width: 100%;">
              <tbody>
                <tr>
                  <td style="border: 1px solid #bbbbbb; padding: 2px 5px; width: 30%;">
                    <?php _e( 'IP пользователя', RESUME_TEXTDOMAIN ); ?>
                  </td>
                  <td style="border: 1px solid #bbbbbb; padding: 2px 5px;">
                    <?php echo $user_ip; ?>
                  </td>
                </tr>
                <tr>
                  <td style="border: 1px solid #bbbbbb; padding: 2px 5px; width: 30%;">
                    <?php _e( 'Имя пользователя', RESUME_TEXTDOMAIN ); ?>
                  </td>
                  <td style="border: 1px solid #bbbbbb; padding: 2px 5px;">
                    <?php echo $fields[ 'author' ] ?>
                  </td>
                </tr>
                <tr>
                  <td style="border: 1px solid #bbbbbb; padding: 2px 5px; width: 30%;">
                    <?php _e( 'Email пользователя', RESUME_TEXTDOMAIN ); ?></td>
                  <td style="border: 1px solid #bbbbbb; padding: 2px 5px;">
                    <a href="mailto:<?php echo esc_attr( $fields[ 'email' ] ); ?>"><?php echo $fields[ 'email' ]; ?></a>
                  </td>
                </tr>
                <tr>
                  <td style="border: 1px solid #bbbbbb; padding: 2px 5px; width: 30%;">
                    <?php _e( 'Сообщение', RESUME_TEXTDOMAIN ); ?>
                  </td>
                  <td style="border: 1px solid #bbbbbb; padding: 2px 5px;">
                    <?php echo $fields[ 'message' ]; ?>
                  </td>
                </tr>
              </tbody>
            </table>
          <?php
          $content = ob_get_contents();
          ob_end_clean();
          $headers = sprintf( 'From: %1$s <%2$s>%3$sContent-type: text/html%3$scharset=utf-8%3$s', $fields[ 'author' ], $fields[ 'email' ], "\r\n" );
          $subject = sprintf( '%1$s %2$s', __( 'Сообщение с сайта', RESUME_TEXTDOMAIN ), get_bloginfo( 'name', 'raw' ) );
          if ( wp_mail( get_bloginfo( 'admin_email', 'raw' ), $subject, $content, $headers ) ) {
            $fields = array_map( '__return_empty_string', $fields );
            $result = '<div class="text-primary">' . __( 'Сообщение отправлено, мы с Вами обяжательно свяжемся.', RESUME_TEXTDOMAIN ) . '</div>';
          } else {
            $result = '<div class="text-warning">' . __( 'Произошла ошибка. Попробуйте позже или свяжитесь с администратором', RESUME_TEXTDOMAIN ) . '</div>';
          }
        } else {
          $result = '<div class="text-warning">' . __( 'Вы в черном списке. Попробуйте позже или свяжитесь с администратором', RESUME_TEXTDOMAIN ) . '</div>';
        }
      } else {
        $result = '<div class="text-warning">' . __( 'Введён некорректный email', RESUME_TEXTDOMAIN ) . '</div>';
      }
    } else {
      $result = '<div class="text-warning">' . __( 'Подозрение на спам. Попробуйте ещё раз.', RESUME_TEXTDOMAIN ) . '</div>';
    }
  }
  ob_start();
  ?>
    <form method="post">
      <?php echo $result; ?>
      <div class="form-group">
        <label for="resume_contact_form_author"><?php _e( 'Ваше имя', RESUME_TEXTDOMAIN ); ?></label>
        <input id="resume_contact_form_author" type="text" name="resume_contact_form_data[author]" value="<?php echo esc_attr( $fields[ 'author' ] ); ?>" required="required">
      </div>
      <div class="form-group">
        <label for="resume_contact_form_email"><?php _e( 'Ваш email', RESUME_TEXTDOMAIN ); ?></label>
        <input id="resume_contact_form_email" type="email" name="resume_contact_form_data[email]" value="<?php echo esc_attr( $fields[ 'email' ] ); ?>" required="required">
      </div>
      <div class="form-group">
        <label for="resume_contact_form_message"><?php _e( 'Сообщение', RESUME_TEXTDOMAIN ); ?></label>
        <textarea id="resume_contact_form_message" name="resume_contact_form_data[message]" required="required"><?php echo $fields[ 'message' ]; ?></textarea>
      </div>
      <input type="hidden" name="check" value="<?php echo esc_attr( $check ); ?>">
      <input type="email" name="email" value="" style="visibility: hidden;">
      <div class="form-group">
        <button type="submit"><?php _e( 'Отправить', RESUME_TEXTDOMAIN ); ?></button>
      </div>
      <br>
    </form>
  <?
  $html = ob_get_contents();
  ob_end_clean();
  return $html;
}

Итог

У такого подхода хватает недостатков, к примеру нельзя заменить email для пересылки, если использовать форму на странице несколько раз, то произойдёт ошибка, отправка формы вызывает перезагрузку страницы, а это не очень удобно. Но хватает и преимуществ: форма проста и достаточно надёжна, создать такую несложно и это не займёт много времени, её можно легко переносить из проекта в проект, а при необходимости достаточно быстро заменить на более продвинутую. Недостатки формы можно победить, как — смотрите в следующих постах.

Git-репозиторий проекта: https://github.com/chomovva/default-contact-form

голос
Рейтинг статьи
Подписаться
Уведомить о
guest
0 комментариев
Межтекстовые Отзывы
Посмотреть все комментарии
0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x
()
x