Как запретить отправку Contact Form 7 на один и тот же email дважды

Сценарий простой: форма уходит, письмо приходит, но в CRM, почте или таблице заявок появляется второй дубль с тем же email. Это не то же самое, что двойная отправка формы в браузере — здесь проблема часто в логике обработки данных после отправки. В Contact Form 7 такое обычно всплывает, когда одну и ту же форму используют для нескольких получателей, подключают сторонние интеграции или пытаются проверять email уже после сабмита.

Ниже разберём, где именно возникает дубль, как его отловить и что делать без выдуманных хуков и «магии» в functions.php.

Когда это действительно дубль, а не два разных события

Сначала важно понять, что именно вы видите. Если письмо пришло один раз, а в CRM запись появилась дважды, это чаще всего не проблема Contact Form 7 как такового. Форма отправилась один раз, но:

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

Если же в админке Contact Form 7 вы видите два отдельных сообщения, тогда уже нужно смотреть на отправку формы, JavaScript и серверную обработку. Но в этой статье речь именно о запрете повторной фиксации заявки на один и тот же email.

Диагностика: где появляется повтор

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

1. Проверьте, что форма отправляется один раз

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

  • двойной обработчик клика по кнопке отправки;
  • дублирующийся JavaScript в теме;
  • скрипт, который повторно вызывает submit() или имитирует клик;
  • кешированный/вставленный дважды блок формы.

2. Сверьте email в исходных данных

Если дубль появляется только в CRM, посмотрите, одинаковый ли email у обеих записей. Иногда форма отправляет один и тот же шаблон, но поле email подставляется из автозаполнения браузера или из скрытого поля. Тогда проблема не в дубле, а в том, что вы принимаете одинаковые данные как две разные заявки.

3. Проверьте интеграции

Если подключены Zapier, Make, webhook в сторонний сервис или собственный endpoint, проверьте логи на стороне получателя. Очень часто один и тот же payload приходит повторно после таймаута или из-за повторной попытки доставки. Это уже вопрос идемпотентности: один email должен создавать одну запись, а повторный запрос — обновлять существующую или игнорироваться.

Рабочая схема: отсекаем повтор по email до создания записи

Самый надёжный вариант — проверять email на стороне WordPress до того, как вы отправите данные дальше в CRM или сохраните их в своей таблице. Для этого удобно использовать хук Contact Form 7 wpcf7_before_send_mail. Он срабатывает перед отправкой письма и позволяет остановить обработку формы.

Ниже пример: если email уже встречался в записях формы, отправку можно прервать. В реальном проекте лучше хранить не просто email, а связку email + form_id, чтобы одна и та же почта могла оставить заявку в разных формах.

<?php
add_action( 'wpcf7_before_send_mail', 'cf7_block_duplicate_email' );

function cf7_block_duplicate_email( $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'] ) : '';

    if ( ! $email || ! is_email( $email ) ) {
        return;
    }

    $form_id = (int) $contact_form->id();
    $key     = 'cf7_email_' . $form_id . '_' . md5( strtolower( $email ) );

    if ( get_transient( $key ) ) {
        $contact_form->skip_mail = true;
        $submission->set_status( 'validation_failed' );
        $submission->set_response( 'Заявка с этим email уже была отправлена.' );
        return;
    }

    set_transient( $key, 1, DAY_IN_SECONDS );
}

Что здесь важно:

  • your-email должен совпадать с именем поля в форме;
  • мы нормализуем email через sanitize_email() и is_email();
  • ключ transient привязан к ID формы;
  • повтор в течение суток блокируется без записи в почту.

Если вам нужно не блокировать заявку полностью, а только не создавать дубликат в CRM, то вместо skip_mail лучше оставить письмо, но в интеграции проверять, существует ли уже такой email.

Если дубли создаёт CRM или вебхук

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

Практически это решается так:

  1. на стороне WordPress отправляйте в CRM не только email, но и уникальный ключ заявки;
  2. на стороне CRM ищите запись по email перед созданием новой;
  3. если запись уже есть, обновляйте её или пропускайте создание;
  4. логируйте ответ сервиса, чтобы видеть, где именно возник повтор.

Если вы пишете свой обработчик webhook, используйте email как один из ключей, но не единственный. Лучше хранить form_id, email и дату первой отправки. Тогда можно отдельно решать, считать ли повтор через час ошибкой, а через неделю — новой заявкой.

Пример проверки перед отправкой в внешний API

<?php
function cf7_send_to_crm_once( $email, $payload ) {
    $email = sanitize_email( $email );

    if ( ! is_email( $email ) ) {
        return new WP_Error( 'invalid_email', 'Некорректный email' );
    }

    $hash = md5( strtolower( $email ) . '|' . ( $payload['form_id'] ?? 0 ) );

    if ( get_option( 'cf7_crm_sent_' . $hash ) ) {
        return true;
    }

    $response = wp_remote_post( 'https://crm.example.com/api/leads', array(
        'timeout' => 15,
        'headers' => array(
            'Content-Type' => 'application/json',
        ),
        'body' => wp_json_encode( $payload ),
    ) );

    if ( is_wp_error( $response ) ) {
        return $response;
    }

    $code = wp_remote_retrieve_response_code( $response );

    if ( $code >= 200 && $code < 300 ) {
        update_option( 'cf7_crm_sent_' . $hash, time(), false );
    }

    return $response;
}

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

Чек-лист перед внедрением

  • Проверьте имя поля email в форме Contact Form 7.
  • Убедитесь, что дубль появляется именно после отправки, а не из-за автозаполнения.
  • Посмотрите Network: один ли POST уходит при сабмите.
  • Проверьте, не дублируется ли JS-код темы или плагина.
  • Если есть CRM/webhook, проверьте логи повторных запросов.
  • Решите, где блокировать дубль: в WordPress или на стороне внешнего сервиса.

Проверка результата после внедрения

После добавления защиты не ограничивайтесь одной тестовой отправкой. Сделайте три проверки:

  1. Отправьте форму с новым email — заявка должна пройти.
  2. Отправьте ту же форму с тем же email ещё раз — повтор должен быть заблокирован или не должен создаваться в CRM.
  3. Проверьте журнал внешнего сервиса: второй запрос либо не приходит, либо приходит, но не создаёт новую запись.

Если вы используете transient-логику, учитывайте TTL. Через сутки или другой заданный срок email снова сможет пройти. Это нормально, если вы сознательно выбрали временную защиту от дублей, а не вечную блокировку.

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

Проверяют только письмо, а не запись в CRM

Письмо может уйти один раз, а CRM создаст две карточки. В таком случае проблема не в почте и не в Contact Form 7, а в интеграции. Ищите повторный webhook или отсутствие проверки существующей записи.

Ставят блокировку по email без учёта формы

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

Используют wp_options для большого потока заявок

Для пары десятков лидов это терпимо, но при росте объёма options разрастается и усложняет обслуживание. Если заявок много, лучше отдельная таблица или внешний сервис с нормальной дедупликацией.

Не нормализуют email

Test@Example.com и test@example.com должны считаться одним и тем же адресом. Перед сравнением приводите email к нижнему регистру и очищайте через sanitize_email().

Пытаются лечить дубль через кеш

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

Что выбрать: плагин, код или проверка на стороне CRM

ПодходКогда подходитМинус
Код в WordPressНужно быстро отсеять повтор по email до отправки дальшеНужно поддерживать свой код
Проверка в CRMДанные уже уходят во внешний сервисДубль всё равно доходит до интеграции
Плагин-автоматизацияЕсть сложные сценарии и несколько формДополнительная зависимость и нагрузка

Если у вас уже есть плагин для технической чистки WordPress, например Clearfy Pro, он может помочь убрать лишние дубли и мусорные настройки в самой установке, но саму логику дедупликации заявок всё равно лучше держать в коде или в CRM. Для формы это вопрос бизнес-логики, а не только SEO или оптимизации.

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

Не храните email в открытом виде там, где это не требуется. Если вы делаете ключ дедупликации, достаточно хеша. Это снижает риск утечки персональных данных из логов и опций. Также не забывайте ограничивать срок жизни transient, иначе вы получите вечную блокировку повторных заявок.

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

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

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

⭐⭐⭐⭐⭐
Как запретить отправку Contact Form 7 на один и тот же email дважды
03.09.2026
Contact Form 7 не отправляет письма: как убрать спам и настроить SMTP
22.08.2026
Contact Form 7: как запретить отправку формы без согласия на обработку данных
31.08.2026
Contact Form 7 отправляет пустые заявки: как отсечь пустые поля и спам-боты
25.08.2026
Contact Form 7: загрузка файлов не приходит во вложении
28.08.2026
×

AI-плагин от WPShop.ru

анализирует конкурентов

пишет статьи

готовит SEO

генерирует изображения

и еще кое-что...
WPGPT
Плагин, который наполняет ваш сайт WordPress
Узнать больше