Как скрыть опрос от гостей и показывать результаты только после голоса в WordPress

Сценарий простой, но на практике ломается часто: гость видит результаты опроса сразу, хотя по логике сайта должен сначала проголосовать. Или наоборот — пользователь уже отправил голос, а результаты не появляются из-за кэша, неверной проверки авторизации или того, что тема рендерит блок опроса статически.

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

Когда проблема проявляется

Обычно это видно в одном из таких случаев:

  • гость открывает страницу и сразу видит диаграмму или проценты;
  • после голосования блок не переключается на результаты;
  • для авторизованных пользователей всё работает, а для гостей — нет;
  • страница кэшируется, и один пользователь видит состояние другого;
  • результаты скрыты, но форма голосования всё равно доступна повторно после обновления страницы.

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

Диагностика: что именно ломает показ результатов

Перед правкой кода стоит понять, где сбой: в логике, в кэше или в способе хранения голоса.

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

Чаще всего разработчики опираются только на is_user_logged_in(). Это недостаточно, если голосовать могут гости. Тогда нужен второй признак: голос уже отправлен с этого браузера или с этой учётной записи.

Для гостей обычно используют cookie. Для авторизованных пользователей — метку в user meta. Если хранить только cookie, пользователь легко обходит ограничение через другой браузер. Если хранить только user meta, гости всегда будут считаться не голосовавшими.

Проверяем кэш

Если страница с опросом кэшируется на уровне плагина, сервера или CDN, один и тот же HTML может отдаваться всем. Тогда результаты будут «залипать» в одном состоянии. Для таких блоков важно либо исключить страницу из кэша, либо рендерить состояние через AJAX после загрузки.

Минимальная проверка: откройте страницу в режиме инкогнито, проголосуйте, затем откройте ту же страницу в другом браузере. Если состояние одинаковое до и после голосования, значит, блок не различает пользователей корректно.

Рабочая схема: форма скрыта, результаты показываются после голоса

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

<?php
add_shortcode('poll_gate', function($atts) {
    $atts = shortcode_atts([
        'poll_id' => 0,
    ], $atts, 'poll_gate');

    $poll_id = absint($atts['poll_id']);
    if (!$poll_id) {
        return '';
    }

    $voted = false;

    if (is_user_logged_in()) {
        $user_id = get_current_user_id();
        $voted = (bool) get_user_meta($user_id, 'poll_voted_' . $poll_id, true);
    } else {
        $cookie_name = 'poll_voted_' . $poll_id;
        $voted = !empty($_COOKIE[$cookie_name]);
    }

    ob_start();

    if ($voted) {
        echo '<div class="poll-results" data-poll-id="' . esc_attr($poll_id) . '">';
        echo '<p>Спасибо за голос. Здесь показываем результаты.</p>';
        echo '</div>';
    } else {
        echo '<form class="poll-form" method="post" action="' . esc_url(admin_url('admin-post.php')) . '">';
        echo '<input type="hidden" name="action" value="submit_poll_vote">';
        echo '<input type="hidden" name="poll_id" value="' . esc_attr($poll_id) . '">';
        wp_nonce_field('submit_poll_vote_' . $poll_id, '_poll_nonce');
        echo '<label><input type="radio" name="answer" value="1" required> Вариант 1</label><br>';
        echo '<label><input type="radio" name="answer" value="2" required> Вариант 2</label><br>';
        echo '<button type="submit">Проголосовать</button>';
        echo '</form>';
    }

    return ob_get_clean();
});

add_action('admin_post_nopriv_submit_poll_vote', 'handle_poll_vote');
add_action('admin_post_submit_poll_vote', 'handle_poll_vote');

function handle_poll_vote() {
    $poll_id = isset($_POST['poll_id']) ? absint($_POST['poll_id']) : 0;
    if (!$poll_id) {
        wp_die('Некорректный опрос');
    }

    check_admin_referer('submit_poll_vote_' . $poll_id, '_poll_nonce');

    $answer = isset($_POST['answer']) ? sanitize_text_field(wp_unslash($_POST['answer'])) : '';
    if ($answer === '') {
        wp_die('Не выбран ответ');
    }

    if (is_user_logged_in()) {
        update_user_meta(get_current_user_id(), 'poll_voted_' . $poll_id, 1);
    } else {
        setcookie('poll_voted_' . $poll_id, '1', time() + MONTH_IN_SECONDS, COOKIEPATH ?: '/', COOKIE_DOMAIN, is_ssl(), true);
        $_COOKIE['poll_voted_' . $poll_id] = '1';
    }

    wp_safe_redirect(wp_get_referer() ?: home_url('/'));
    exit;
}

Это базовый каркас. В реальном проекте вместо текста «здесь показываем результаты» подставьте вывод данных вашего опроса: из post meta, таблицы плагина или отдельной сущности.

Почему здесь важен nonce

Без wp_nonce_field() и check_admin_referer() форму можно отправлять с чужого сайта. Для опросов это не критично как для платежей, но защита от CSRF всё равно нужна. Особенно если голос меняет состояние пользователя и открывает доступ к результатам.

Если опрос уже есть в плагине

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

ПодходКогда подходитМинус
Настройка плагинаЕсли есть готовая опция «hide results until vote»Зависимость от конкретного плагина
Шорткод + cookie/user metaЕсли нужен контроль над логикой показаНужно следить за кэшем и безопасностью
AJAX-переключениеЕсли страница активно кэшируетсяСложнее отлаживать и поддерживать

Если используете плагин с собственным AJAX, проверьте, не отдаёт ли он результаты в HTML сразу после первого рендера. В таком случае скрытие через CSS — плохая идея: данные всё равно присутствуют в исходнике страницы и могут быть видны в коде.

Как не сломать кэш и не показать чужие результаты

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

Есть три безопасных варианта:

  1. исключить страницу с опросом из кэша;
  2. выносить результаты в AJAX-запрос после загрузки страницы;
  3. делать отдельный endpoint, который отдает только состояние конкретного пользователя.

Если у вас Cloudflare, LiteSpeed Cache, WP Rocket или другой кэш-плагин, проверьте исключения для страницы, где расположен опрос. Если опрос встроен в запись, а запись кэшируется, лучше не пытаться «прятать» результаты только CSS-классом.

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

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

  • гость открывает страницу до голосования — видит только форму;
  • тот же гость голосует — после отправки видит результаты;
  • другой браузер или инкогнито — не наследует состояние первого пользователя.

Дополнительно проверьте исходный HTML страницы. Если результаты должны быть скрыты до голосования, их не должно быть в разметке до отправки формы. Это можно увидеть через «Просмотр кода страницы» или вкладку Network в DevTools.

Для авторизованного пользователя полезно проверить user meta:

<?php
$user_id = get_current_user_id();
$flag = get_user_meta($user_id, 'poll_voted_123', true);
var_dump($flag);

Если флаг ставится, а интерфейс не меняется, проблема уже не в хранении голоса, а в шаблоне вывода или кэше.

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

Результаты скрыты, но голос можно отправить повторно

Причина обычно в том, что вы проверяете только отображение, а не сам факт повторной отправки. Нужно блокировать повторный сабмит на сервере: по cookie, по user meta, по IP или по комбинации признаков. Только фронтенд-защита не работает.

Cookie ставится, но не читается

Часто это происходит из-за неверного пути cookie или из-за того, что сайт работает на HTTPS, а cookie ставится без флага secure. В примере выше setcookie() использует is_ssl(), чтобы не терять cookie на защищённом сайте.

После голосования страница не обновляет состояние

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

Гость видит результаты в исходнике

Это признак того, что данные рендерятся на сервере до проверки прав доступа. Не прячьте их через display:none. Сначала решите, можно ли вообще отдавать этот HTML пользователю.

Практические советы по безопасности и производительности

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

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

  • проверка должна быть на сервере, а не только в JS;
  • nonce нужен даже для простого голосования;
  • cookie не считается надёжным доказательством личности, только маркером состояния браузера.

Если вам нужно быстро закрыть типовые проблемы с дублями, кэшом и лишними скриптами на сайте, иногда проще сначала почистить фронтенд и отключить лишние оптимизации. Для этого может подойти Clearfy Pro: https://wpshop.ru/plugins/clearfy?utm_source=wppolls.ru&utm_medium=article&utm_campaign=kak-skryt-opros-ot-gostey-i-pokazyvat-rezultaty-tolko-posle-golosa-v-wordpress. Но саму логику показа результатов всё равно лучше держать в коде или в настройках плагина опросов.

Если после внедрения всё ещё есть расхождения между тем, что видит пользователь, и тем, что хранится в базе, начните с проверки кэша, cookie и правки шаблона. В таких задачах обычно ломается не одна вещь, а связка из двух-трёх мелких ошибок.

Интеграция опросов WordPress в WooCommerce для сбора отзывов: практическое руководство
06.05.2026
Отзывы с выбором оценки в WordPress: пошаговое руководство
13.12.2025
Как сделать автоподсказку в опросе WordPress для повышения удобства пользователей
18.01.2026
Как создать расписание публикаций в WordPress: полный гайд
30.11.2025
Как сделать защиту от множественных голосов в опросе WordPress
07.02.2026