Ситуация знакомая: форма отправляется один раз, а в админке WPForms появляется две одинаковые записи. Иногда дубли видны только в списке Entries, иногда еще и в почте приходят повторные уведомления. Проблема почти всегда упирается не в сам WPForms, а в повторную обработку отправки: двойной клик по кнопке, конфликт скриптов, кеш/оптимизация JS, сторонний код на хуках или повторный POST после редиректа.
Ниже разберем, как быстро понять источник дублей и что делать, если нужно именно убрать повторные записи, а не просто «переустановить плагин».
Когда это действительно дубли, а не нормальное поведение
Сначала проверьте, что вы видите именно повторную запись, а не две разные формы с похожими данными. В WPForms дубли обычно выглядят так:
- одинаковые имя, email и сообщение;
- одинаковое время отправки с разницей в секунды;
- одинаковый источник страницы;
- два одинаковых письма на один и тот же адрес.
Если запись одна, а письмо приходит дважды, это уже другая задача: там надо смотреть уведомления формы и сторонние SMTP/хуки. Если же в базе реально две записи, значит форма обрабатывается повторно.
Диагностика проблемы: где искать причину дублей
Перед правками полезно понять, на каком уровне возникает повтор:
1. Повторный клик по кнопке отправки
Пользователь нажимает Submit дважды, особенно если страница «подвисает» из-за тяжелых скриптов или медленного ответа сервера. В этом случае в браузере обычно видно два POST-запроса почти подряд.
2. Конфликт JavaScript
Оптимизаторы, минификация и отложенная загрузка скриптов иногда ломают логику WPForms. Форма может отправиться, а затем скрипт повторно инициирует сабмит.
3. Кастомный код на хуках
Если вы добавляли обработку через wpforms_process_complete, wpforms_process или похожие хуки, проверьте, не создается ли запись вручную второй раз. Это частая ошибка при интеграции с CRM, CRM-логикой или собственными таблицами.
4. Кеширование и оптимизация
Сам по себе кеш не должен дублировать записи, но связка «кеш + агрессивная оптимизация JS + AJAX-форма» часто создает повторную отправку. Особенно если на странице одновременно есть lazy load, defer и сторонние виджеты.
Для быстрой проверки откройте DevTools в браузере, вкладку Network, отправьте форму и посмотрите, сколько запросов уходит на обработку. Если POST один, а запись все равно дублируется, проблема почти наверняка в серверной логике или хуках.
Пошаговое решение без лишних рисков
Шаг 1. Отключите все, что может повторно дергать submit
На тестовой странице временно выключите:
- delay/defer для JS;
- объединение скриптов;
- антиспам-скрипты сторонних плагинов;
- кастомные обработчики кнопки отправки.
Если дубли исчезли, значит причина в фронтенде. Дальше включайте оптимизацию по одному пункту и проверяйте повторно.
Шаг 2. Проверьте, не срабатывает ли ваш код дважды
Если у вас есть собственная интеграция, убедитесь, что обработчик не привязан к нескольким хукам одновременно. Например, не нужно одновременно создавать запись в wpforms_process_complete и в AJAX-обработчике той же формы без явной защиты от повторного вызова.
<?php
add_action( 'wpforms_process_complete', function( $fields, $entry, $form_data, $entry_id ) {
if ( empty( $form_data['id'] ) || (int) $form_data['id'] !== 123 ) {
return;
}
// Пример защиты от повторной обработки в рамках одного запроса.
static $processed = false;
if ( $processed ) {
return;
}
$processed = true;
// Здесь только одна бизнес-операция.
// Например, отправка данных во внешнюю систему.
}, 10, 4 );Это не универсальная защита от всех дублей, но полезный первый барьер, если код случайно выполняется повторно внутри одного запроса.
Шаг 3. Добавьте блокировку повторной отправки на уровне формы
Если проблема в двойном клике, лучше не надеяться на пользователя. Кнопку отправки можно временно блокировать до ответа сервера. Это не заменяет серверную защиту, но снижает число повторов.
<script>
document.addEventListener('DOMContentLoaded', function () {
document.querySelectorAll('.wpforms-form').forEach(function (form) {
form.addEventListener('submit', function () {
var button = form.querySelector('button[type="submit"], input[type="submit"]');
if (!button) return;
if (button.disabled) {
return;
}
button.disabled = true;
button.dataset.originalText = button.value || button.textContent;
if (button.tagName === 'INPUT') {
button.value = 'Отправка...';
} else {
button.textContent = 'Отправка...';
}
});
});
});
</script>Такой код лучше подключать только там, где он нужен, а не глобально на весь сайт. Иначе можно сломать формы, которые рассчитывают на повторный сабмит в особых сценариях.
Шаг 4. Уберите повторную запись через серверную проверку
Если вы точно знаете, что дубли идут из-за повторного POST или повторной бизнес-логики, добавьте проверку по хэшу данных формы. Идея простая: если за короткое время пришел тот же набор полей, второй раз запись не создаем.
<?php
add_action( 'wpforms_process_complete', function( $fields, $entry, $form_data, $entry_id ) {
if ( (int) $form_data['id'] !== 123 ) {
return;
}
$email = '';
$name = '';
foreach ( $fields as $field ) {
if ( isset( $field['name'] ) && stripos( $field['name'], 'email' ) !== false ) {
$email = sanitize_email( $field['value'] );
}
if ( isset( $field['name'] ) && stripos( $field['name'], 'name' ) !== false ) {
$name = sanitize_text_field( $field['value'] );
}
}
$fingerprint = md5( strtolower( $email . '|' . $name . '|' . $entry_id ) );
$cache_key = 'wpforms_dedup_' . $fingerprint;
if ( get_transient( $cache_key ) ) {
return;
}
set_transient( $cache_key, 1, 10 * MINUTE_IN_SECONDS );
// Выполняем действие только один раз.
}, 10, 4 );Это не отменяет саму запись WPForms, но помогает не запускать вашу дополнительную обработку дважды. Если дубли создаются именно в сторонней системе, такой подход обычно самый практичный.
Сравнение подходов: что выбрать в реальном проекте
| Подход | Когда подходит | Минус |
|---|---|---|
| Отключить оптимизацию JS | Если дубли появились после ускорения сайта | Может снизить производительность |
| Блокировать кнопку submit | Если пользователи часто жмут кнопку дважды | Не решает серверные повторы |
| Проверка по хэшу/транзиенту | Если дубли идут из кастомного кода или интеграций | Нужно аккуратно подобрать окно времени |
Как проверить, что решение сработало
После правок не ограничивайтесь одной тестовой отправкой. Проверьте сценарий целиком:
- отправьте форму один раз и убедитесь, что в Entries появилась одна запись;
- обновите страницу после отправки и проверьте, не создается ли повтор;
- отправьте форму быстро дважды подряд;
- посмотрите Network в браузере: должен быть один корректный POST на одну отправку;
- если есть интеграция с CRM, проверьте, что в ней тоже одна сделка или один лид.
Если запись одна, а внешняя система получает две, значит проблема не в WPForms как таковом, а в вашем обработчике или webhook-логике.
Частые ошибки и как их исправить
Отключили кеш целиком вместо точечной настройки
Это слишком грубое решение. Лучше исключить только страницу с формой или отключить конкретную оптимизацию JS, которая ломает сабмит.
Добавили защиту только в JavaScript
JS-защита полезна, но ее можно обойти. Если дубли критичны, нужна еще и серверная проверка.
Используют слишком короткий интервал дедупликации
Если транзиент живет 2–3 секунды, повторный запрос может пройти. Если сделать окно слишком длинным, можно случайно заблокировать реальную повторную отправку от пользователя. Обычно интервал подбирают по сценарию формы.
Проверяют только письмо, а не запись в базе
Письмо может дублироваться из-за уведомлений, а запись — нет. Сначала определите, что именно повторяется.
Когда стоит смотреть в сторону очистки и технической оптимизации
Если дубли появляются только на тяжелых страницах, полезно проверить не саму форму, а окружение: лишние скрипты, тяжелые блоки, сторонние виджеты, дублирующиеся CSS и JS. Для таких задач иногда помогает точечная чистка сайта и удаление лишнего кода, например через Clearfy Pro: https://wpshop.ru/plugins/clearfy.
Но важно не превращать оптимизацию в «выключим все подряд». Сначала найдите источник дубля, потом убирайте только то, что реально мешает форме.
Практический чек-лист перед публикацией исправления
- Проверен один и тот же сценарий отправки в браузере и в админке.
- Отключены подозрительные оптимизации JS по одному пункту.
- Проверены кастомные хуки и обработчики формы.
- Добавлена защита от двойного клика на кнопке.
- Проверено, что внешние интеграции не создают дубли сами по себе.
- Тест выполнен на реальной странице, а не только в черновике.
Если после этого дубли остаются, имеет смысл включить логирование на уровне вашего кода и посмотреть, не вызывается ли обработчик повторно из-за темы, плагина кеша или нестандартной AJAX-логики.