Плагины для форм — это удобно, но они добавляют нагрузку, обновления и потенциальные уязвимости. В этой статье покажем, как создать полноценную контактную форму на WordPress с нуля: HTML-разметка, AJAX-отправка и доставка на почту через wp_mail(). Никаких Contact Form 7, WPForms и Gravity Forms.

Зачем делать формы без плагина?

  • Скорость — нет лишних CSS/JS файлов, которые грузит плагин
  • Контроль — вы точно знаете что происходит с данными
  • Безопасность — меньше кода = меньше точек атаки
  • Гибкость — форма точно под ваш дизайн, без костылей

Шаг 1: HTML-разметка формы

Создаём форму с полями имени, email, телефона и сообщения. Добавляем скрытое поле для nonce (защита от CSRF) и honeypot-поле (антиспам).

<?php
/**
 * Шорткод [contact_form] — выводит форму обратной связи
 */
function wenesis_contact_form_shortcode() {
    // Генерируем nonce для защиты
    $nonce = wp_create_nonce('contact_form_nonce');
    
    ob_start();
    ?>
    <form id="contact-form" class="contact-form" method="post">
        <!-- Nonce для безопасности -->
        <input type="hidden" name="contact_nonce" value="<?php echo $nonce; ?>">
        
        <!-- Honeypot: скрытое поле, боты его заполнят -->
        <div style="position:absolute;left:-9999px;" aria-hidden="true">
            <input type="text" name="website_url" tabindex="-1" autocomplete="off">
        </div>

        <div class="form-group">
            <label for="cf-name">Имя *</label>
            <input type="text" id="cf-name" name="name" required placeholder="Ваше имя">
        </div>

        <div class="form-group">
            <label for="cf-email">Email *</label>
            <input type="email" id="cf-email" name="email" required placeholder="example@mail.ru">
        </div>

        <div class="form-group">
            <label for="cf-phone">Телефон</label>
            <input type="tel" id="cf-phone" name="phone" placeholder="+7 (999) 123-45-67">
        </div>

        <div class="form-group">
            <label for="cf-message">Сообщение *</label>
            <textarea id="cf-message" name="message" rows="5" required placeholder="Расскажите о вашем проекте"></textarea>
        </div>

        <div class="form-group">
            <button type="submit" class="btn btn-primary">Отправить</button>
        </div>

        <div id="form-status" class="form-status" style="display:none;"></div>
    </form>
    <?php
    return ob_get_clean();
}
add_shortcode('contact_form', 'wenesis_contact_form_shortcode');

Теперь можно вывести форму на любой странице шорткодом [contact_form].

Шаг 2: AJAX-обработчик на PHP

Принимаем данные формы через AJAX, валидируем и отправляем письмо через wp_mail().

<?php
/**
 * AJAX-обработчик отправки формы
 */
function wenesis_handle_contact_form() {
    // 1. Проверяем nonce
    if (!isset($_POST['contact_nonce']) || !wp_verify_nonce($_POST['contact_nonce'], 'contact_form_nonce')) {
        wp_send_json_error('Ошибка безопасности. Обновите страницу.');
    }

    // 2. Антиспам: honeypot
    if (!empty($_POST['website_url'])) {
        wp_send_json_error('Spam detected');
    }

    // 3. Антиспам: таймер (менее 3 секунд = бот)
    $load_time = isset($_POST['page_load_time']) ? intval($_POST['page_load_time']) : 0;
    if ($load_time > 0 && $load_time < 3) {
        wp_send_json_error('Слишком быстро! Подождите немного.');
    }

    // 4. Получаем и очищаем данные
    $name    = sanitize_text_field($_POST['name'] ?? '');
    $email   = sanitize_email($_POST['email'] ?? '');
    $phone   = sanitize_text_field($_POST['phone'] ?? '');
    $message = sanitize_textarea_field($_POST['message'] ?? '');

    // 5. Валидация
    if (empty($name)) {
        wp_send_json_error('Укажите имя');
    }
    if (empty($email) || !is_email($email)) {
        wp_send_json_error('Укажите корректный email');
    }
    if (empty($message)) {
        wp_send_json_error('Напишите сообщение');
    }

    // 6. Антиспам: проверка на ссылки в имени
    if (preg_match('/https?:\/\/|www\./i', $name)) {
        wp_send_json_error('Недопустимое имя');
    }

    // 7. Антиспам: проверка на спам-слова
    $spam_words = ['casino', 'viagra', 'porn', 'crypto', 'bitcoin', 'loan', 'click here', 'заработок', 'казино'];
    $all_text   = strtolower($name . ' ' . $message);
    foreach ($spam_words as $word) {
        if (strpos($all_text, $word) !== false) {
            wp_send_json_error('Spam detected');
        }
    }

    // 8. Антиспам: лимит отправок с одного IP (5 в час)
    $ip            = $_SERVER['REMOTE_ADDR'];
    $transient_key = 'contact_submits_' . md5($ip);
    $submits       = get_transient($transient_key) ?: 0;
    if ($submits >= 5) {
        wp_send_json_error('Слишком много заявок. Попробуйте позже.');
    }
    set_transient($transient_key, $submits + 1, HOUR_IN_SECONDS);

    // 9. Формируем письмо
    $to      = get_option('admin_email');
    $subject = 'Новая заявка с сайта ' . get_bloginfo('name');

    $body  = "Имя: {$name}\n";
    $body .= "Email: {$email}\n";
    if ($phone) {
        $body .= "Телефон: {$phone}\n";
    }
    $body .= "\nСообщение:\n{$message}\n";
    $body .= "\n---\n";
    $body .= "IP: {$ip}\n";
    $body .= "Дата: " . current_time('d.m.Y H:i') . "\n";

    $headers = [
        'Content-Type: text/plain; charset=UTF-8',
        "Reply-To: {$name} <{$email}>",
    ];

    // 10. Отправляем письмо
    $sent = wp_mail($to, $subject, $body, $headers);

    if ($sent) {
        // Сохраняем заявку в базу (опционально)
        $post_id = wp_insert_post([
            'post_type'   => 'contact-submissions',
            'post_status' => 'private',
            'post_title'  => "Заявка от {$name} — {$email}",
            'post_content' => $body,
        ]);

        wp_send_json_success('Сообщение отправлено! Мы свяжемся с вами в ближайшее время.');
    } else {
        wp_send_json_error('Ошибка отправки. Попробуйте позже или свяжитесь с нами по телефону.');
    }
}

// Регистрируем AJAX-хуки (для авторизованных и гостей)
add_action('wp_ajax_send_contact_form', 'wenesis_handle_contact_form');
add_action('wp_ajax_nopriv_send_contact_form', 'wenesis_handle_contact_form');

Шаг 3: JavaScript для AJAX-отправки

Отправляем форму без перезагрузки страницы. Добавляем таймер загрузки для антиспама.

<?php
/**
 * Подключаем JS для AJAX-формы
 */
function wenesis_contact_form_scripts() {
    ?>
    <script>
    document.addEventListener('DOMContentLoaded', function() {
        // Запоминаем время загрузки страницы
        var pageLoadTime = Math.floor(Date.now() / 1000);
        var loadTimeInput = document.querySelector('input[name="page_load_time"]');
        if (loadTimeInput) {
            loadTimeInput.value = pageLoadTime;
        }

        var form = document.getElementById('contact-form');
        if (!form) return;

        form.addEventListener('submit', function(e) {
            e.preventDefault();

            var submitBtn = form.querySelector('button[type="submit"]');
            var status    = document.getElementById('form-status');
            
            // Блокируем кнопку
            submitBtn.disabled = true;
            submitBtn.textContent = 'Отправка...';
            status.style.display = 'none';

            // Собираем данные формы
            var formData = new FormData(form);
            formData.append('action', 'send_contact_form');

            // AJAX-запрос
            fetch('/wp-admin/admin-ajax.php', {
                method: 'POST',
                body: formData
            })
            .then(function(response) { return response.json(); })
            .then(function(data) {
                status.style.display = 'block';
                if (data.success) {
                    status.className = 'form-status success';
                    status.textContent = data.data;
                    form.reset();
                } else {
                    status.className = 'form-status error';
                    status.textContent = data.data;
                }
            })
            .catch(function(error) {
                status.style.display = 'block';
                status.className = 'form-status error';
                status.textContent = 'Ошибка сети. Попробуйте позже.';
            })
            .finally(function() {
                submitBtn.disabled = false;
                submitBtn.textContent = 'Отправить';
            });
        });
    });
    </script>
    <?php
}
add_action('wp_footer', 'wenesis_contact_form_scripts');

Шаг 4: CSS-стили для формы

Добавляем базовые стили, чтобы форма выглядела аккуратно.

<?php
/**
 * CSS стили для контактной формы
 */
function wenesis_contact_form_styles() {
    ?>
    <style>
    .contact-form {
        max-width: 600px;
        margin: 0 auto;
    }
    .contact-form .form-group {
        margin-bottom: 20px;
    }
    .contact-form label {
        display: block;
        margin-bottom: 6px;
        font-weight: 600;
        color: #333;
    }
    .contact-form input[type="text"],
    .contact-form input[type="email"],
    .contact-form input[type="tel"],
    .contact-form textarea {
        width: 100%;
        padding: 12px 16px;
        border: 2px solid #e0e0e0;
        border-radius: 8px;
        font-size: 16px;
        transition: border-color 0.3s;
    }
    .contact-form input:focus,
    .contact-form textarea:focus {
        outline: none;
        border-color: #3232ff;
    }
    .contact-form .btn-primary {
        background: #3232ff;
        color: #fff;
        border: none;
        padding: 14px 32px;
        font-size: 16px;
        border-radius: 8px;
        cursor: pointer;
        transition: background 0.3s;
    }
    .contact-form .btn-primary:hover {
        background: #1a1acc;
    }
    .contact-form .btn-primary:disabled {
        background: #999;
        cursor: not-allowed;
    }
    .form-status {
        margin-top: 16px;
        padding: 12px 16px;
        border-radius: 8px;
        font-size: 15px;
    }
    .form-status.success {
        background: #d4edda;
        color: #155724;
        border: 1px solid #c3e6cb;
    }
    .form-status.error {
        background: #f8d7da;
        color: #721c24;
        border: 1px solid #f5c6cb;
    }
    </style>
    <?php
}
add_action('wp_head', 'wenesis_contact_form_styles');

Шаг 5: Регистрация типа записей для заявок (опционально)

Если хотите сохранять заявки в админке WordPress — регистрируем кастомный тип записей.

<?php
/**
 * Регистрируем тип записей "Заявки" для хранения отправленных форм
 */
function wenesis_register_submissions_post_type() {
    register_post_type('contact-submissions', [
        'labels' => [
            'name'          => 'Заявки',
            'singular_name' => 'Заявка',
            'add_new'       => 'Новая заявка',
            'add_new_item'  => 'Добавить заявку',
            'all_items'     => 'Все заявки',
        ],
        'public'       => false,
        'show_ui'      => true,
        'show_in_menu' => true,
        'menu_icon'    => 'dashicons-email-alt',
        'supports'     => ['title', 'editor'],
        'has_archive'  => false,
    ]);
}
add_action('init', 'wenesis_register_submissions_post_type');

Итоговый код: всё в одном файле

Создайте файл contact-form.php в папке вашей темы и подключите через functions.php:

<?php
// В functions.php добавьте:
require_once get_template_directory() . '/inc/contact-form.php';

Или вставьте весь код прямо в functions.php — для простых случаев это допустимо.

Что мы получили

  • ✅ Форма с полями имя, email, телефон, сообщение
  • ✅ AJAX-отправка без перезагрузки страницы
  • ✅ Валидация на сервере
  • ✅ Защита nonce (CSRF)
  • ✅ Honeypot антиспам
  • ✅ Таймер загрузки (антибот)
  • ✅ Проверка на спам-слова
  • ✅ Лимит отправок с одного IP
  • ✅ Сохранение заявок в админке
  • ✅ Отправка письма через wp_mail()
  • ✅ Стили для формы
  • ✅ Никаких плагинов!

Расширение: добавить отправку в Telegram

Если хотите получать уведомления о заявках в Telegram — добавьте этот код после wp_mail():

<?php
/**
 * Отправка уведомления в Telegram
 *
 * @param string $name    Имя отправителя
 * @param string $email   Email отправителя
 * @param string $phone   Телефон
 * @param string $message Текст сообщения
 */
function wenesis_send_telegram($name, $email, $phone, $message) {
    $bot_token = 'ВАШ_ТОКЕН_БОТА';
    $chat_id   = 'ВАШ_CHAT_ID';

    $text  = "🆕 Новая заявка!\n\n";
    $text .= "👤 Имя: {$name}\n";
    $text .= "📧 Email: {$email}\n";
    if ($phone) {
        $text .= "📱 Телефон: {$phone}\n";
    }
    $text .= "\n💬 Сообщение:\n{$message}";

    $url = "https://api.telegram.org/bot{$bot_token}/sendMessage";
    
    wp_remote_post($url, [
        'body' => [
            'chat_id'    => $chat_id,
            'text'       => $text,
            'parse_mode' => 'HTML',
        ],
    ]);
}

// Вызываем после успешной отправки письма:
// wenesis_send_telegram($name, $email, $phone, $message);

Заключение

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

Код из этой статьи можно скопировать и использовать в любом проекте. Если нужны дополнительные поля — просто добавьте их в HTML и обработку в PHP.

Читайте также:

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

Разработка сайтов на Wordpress