Как запретить дубли сообщений в Contact Form 7 при повторной отправке

Дубли в Contact Form 7 обычно появляются не из-за одной причины, а из-за набора мелких сбоев: пользователь нажал кнопку дважды, браузер повторил запрос после ошибки сети, форма отправилась повторно из-за автосабмита, а на стороне сайта нет проверки на уже обработанный запрос. Если форма уходит в CRM, почту и вебхук одновременно, один дубль быстро превращается в несколько одинаковых лидов.

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

Когда проблема точно в дублях, а не в почте

Сначала важно не перепутать дубли с другой типичной проблемой — когда письмо не дошло, а пользователь отправил форму еще раз. В этом сценарии в админке, CRM или логах видно несколько одинаковых событий с разницей в секунды. Если же письмо одно, а форма в браузере показывает ошибку, это уже другая задача.

Признаки повторной отправки

  • в CRM появляются одинаковые заявки с одинаковым временем;
  • в логах вебхука видно два POST-запроса подряд;
  • пользователь жалуется, что нажал кнопку один раз, но получил два письма или два ответа;
  • после обновления страницы форма иногда отправляется повторно.

Если у вас включены интеграции через сторонние плагины или собственный код, проверяйте не только Contact Form 7, но и обработчики после успешной отправки. Часто дубль рождается уже там.

Что проверить перед исправлением

Перед правкой кода полезно понять, на каком уровне возникает повтор:

  1. Откройте DevTools и вкладку Network.
  2. Отправьте форму один раз и посмотрите, сколько запросов уходит на сервер.
  3. Проверьте, не срабатывает ли отправка дважды из-за JS-обработчика, который навешан повторно.
  4. Посмотрите, есть ли у формы интеграция с CRM, webhook или кастомный functions.php-хук, который отправляет данные еще раз.

Если в Network один запрос, а дубль появляется уже в CRM, значит защита нужна на серверной стороне. Если запросов два, сначала чините фронтенд.

Пошаговое решение: защита от повторной отправки

Надежнее всего сочетать два уровня защиты: блокировку повторного клика на клиенте и серверную проверку на дубликат. Один только JavaScript не спасает от повторного POST-запроса, а одна только серверная проверка не убирает раздражающий двойной клик пользователя.

1. Отключите повторный клик на кнопке отправки

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

document.addEventListener('wpcf7submit', function (event) {
  const form = event.target;
  const button = form.querySelector('input[type="submit"], button[type="submit"]');
  if (button) {
    button.disabled = false;
    button.value = button.dataset.originalValue || button.value;
  }
}, false);

document.addEventListener('click', function (event) {
  const button = event.target.closest('.wpcf7 form input[type="submit"], .wpcf7 form button[type="submit"]');
  if (!button) return;

  if (!button.dataset.originalValue && button.tagName === 'INPUT') {
    button.dataset.originalValue = button.value;
  }

  button.disabled = true;
  if (button.tagName === 'INPUT') {
    button.value = 'Отправка...';
  }
}, false);

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

2. Добавьте серверную защиту через nonce и временный токен

В Contact Form 7 уже есть внутренняя защита, но для борьбы с дублями удобнее добавить собственный одноразовый токен и проверять его на сервере. Логика простая: форма получает уникальный токен, а после успешной обработки токен помечается как использованный. Повторный запрос с тем же токеном отклоняется.

Ниже пример для functions.php или небольшого mu-plugin. Он добавляет скрытое поле и проверяет его на этапе валидации.

add_action('wpcf7_init', function () {
    wpcf7_add_form_tag('dedupe_token', function () {
        $token = wp_generate_uuid4();
        return '<input type="hidden" name="dedupe_token" value="' . esc_attr($token) . '">';
    });
});

add_filter('wpcf7_validate_hidden', function ($result, $tag) {
    if ($tag->name !== 'dedupe_token') {
        return $result;
    }

    $token = isset($_POST['dedupe_token']) ? sanitize_text_field(wp_unslash($_POST['dedupe_token'])) : '';
    if (!$token) {
        $result->invalidate($tag, 'Не удалось проверить отправку формы.');
        return $result;
    }

    $key = 'cf7_dedupe_' . md5($token);
    if (get_transient($key)) {
        $result->invalidate($tag, 'Эта форма уже была отправлена.');
        return $result;
    }

    set_transient($key, 1, HOUR_IN_SECONDS);
    return $result;
}, 10, 2);

Здесь есть важная оговорка: такой код защищает от повторной отправки с тем же токеном, но не от двух разных отправок подряд от одного пользователя. Если вам нужна более строгая антидубль-проверка, добавьте сравнение по email, телефону и времени.

3. Сравнивайте ключевые поля перед созданием заявки

Если форма собирает контактные данные, можно не создавать новую запись, когда в течение короткого промежутка уже приходила заявка с теми же значениями. Это особенно полезно для форм обратного звонка и заявок на консультацию.

add_action('wpcf7_before_send_mail', function ($contact_form) {
    $submission = WPCF7_Submission::get_instance();
    if (!$submission) {
        return;
    }

    $data = $submission->get_posted_data();
    $email = isset($data['your-email']) ? sanitize_email($data['your-email']) : '';
    $phone = isset($data['your-phone']) ? preg_replace('/\D+/', '', $data['your-phone']) : '';

    if (!$email && !$phone) {
        return;
    }

    $fingerprint = md5(strtolower($email . '|' . $phone));
    $key = 'cf7_last_submit_' . $fingerprint;

    if (get_transient($key)) {
        $submission->set_status('validation_failed');
        $submission->set_response('Похоже, эта заявка уже была отправлена.');
        return;
    }

    set_transient($key, time(), 10 * MINUTE_IN_SECONDS);
}, 10, 1);

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

Сравнение подходов

ПодходЧто решаетМинус
Отключение кнопки на фронтендеДвойной клик, случайное повторное нажатиеНе защищает от повторного запроса
Одноразовый токенПовторную отправку одного и того же запросаНужен код и аккуратная интеграция
Проверка по email/телефонуПовторы в короткий промежутокЕсть риск ложных срабатываний

Как проверить, что защита сработала

После внедрения не ограничивайтесь визуальной проверкой формы. Нужна проверка по факту запроса и по итоговому событию.

  • Отправьте форму один раз и убедитесь, что в Network уходит один POST.
  • Попробуйте нажать кнопку дважды подряд — второй клик не должен создать новую заявку.
  • Обновите страницу сразу после отправки и проверьте, не повторяется ли POST.
  • Если есть CRM или вебхук, сравните количество входящих событий до и после правки.

Для отладки удобно временно логировать данные в error_log() или смотреть записи в журнале сервера. Если у вас включен плагин логирования, проверяйте именно момент создания заявки, а не только факт показа сообщения об успехе.

Частые ошибки и как их исправить

Защиту ставят только в JavaScript

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

Токен живет слишком долго

Если хранить антидубль-токен сутки или неделю, вы начнете блокировать нормальные повторные обращения. Для контактной формы обычно достаточно короткого окна: от нескольких минут до часа, в зависимости от сценария.

Проверка по email ломает реальные повторные заявки

Если человек дважды отправляет форму с одним и тем же email, это не всегда дубль. Например, он мог изменить тему обращения или отправить заявку повторно после ошибки. Поэтому проверку по полям лучше делать только как временную антидубль-защиту, а не как жесткий бизнес-барьер.

Код размещают в теме

Если вы добавляете такую логику в functions.php активной темы, при смене темы защита исчезнет. Для стабильной работы лучше вынести код в небольшой mu-plugin или отдельный плагин проекта.

Безопасность и производительность

Антидубль-логика не должна создавать лишнюю нагрузку. Не пишите каждый запрос в базу без необходимости и не храните бесконечные ключи в transient. Для большинства сайтов transient с коротким TTL достаточно.

Если форма принимает персональные данные, не сохраняйте их в открытом виде в логах. Для сравнения используйте хеш или нормализованный fingerprint, а не полный набор полей. Это уменьшает риск утечки и не мешает проверке дублей.

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

Когда лучше не блокировать повторную отправку жестко

Есть сценарии, где строгая антидубль-защита вреднее, чем полезна. Это формы с длинным циклом принятия решения, заявки на разные услуги с одинаковым email или формы, где пользователь может отправить несколько обращений подряд. В таких случаях лучше:

  • показывать предупреждение о повторной отправке;
  • ограничивать только очень короткий интервал;
  • логировать повторы, но не блокировать их полностью;
  • проверять дубли уже на стороне CRM, где виден контекст обращения.

Если задача сводится к тому, чтобы убрать случайные повторные клики и одинаковые заявки из-за сетевых сбоев, связка из отключения кнопки, одноразового токена и короткой серверной проверки закрывает проблему без тяжелых костылей.

Добавь в закладки и поделись с друзьями:

⭐⭐⭐⭐⭐
Как отключить скрипты Contact Form 7 на страницах без формы
24.09.2026
Как запретить дубли сообщений в Contact Form 7 при повторной отправке
30.09.2026
Contact Form 7 не отправляет письма через SMTP: как найти причину и исправить
24.09.2026
Как добавить отдельное сообщение об успешной отправке для каждой формы Contact Form 7
27.09.2026
×

AI-плагин

WPGPT
Сам создает статьи для вашего сайта WordPress

SEO и мета-теги

Парсинг конкурентов

Изображения

Комментарии

Подробнее