Проста форма зворотнього зв'язку для 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() створює ряд фільтрів і хуков, якими можуть скористатися встановлені плагіни, наприклад 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