WP-Polls

Description

WP-Polls adds a poll to your site: a question, its answers, and a result bar that replaces the voting form once a visitor has voted, without a page reload. A poll can go in a post with a shortcode or a block, in a sidebar with the widget, or anywhere in your theme with a template tag.

A poll can accept one answer or several, close on a date you set, and be shown as a form or as its result. The markup of every part of it is a template you can edit, and the bars are styled with CSS custom properties your theme can override.

Donations

I spent most of my free time creating, updating, maintaining and supporting these plugins, if you really love my plugins and could spare me a couple of bucks, I will really appreciate it. If not feel free to use it without any obligations.

Usage

Showing A Poll From A Theme

<?php if ( function_exists( 'vote_poll' ) && ! in_pollarchive() ): ?>
    <li>
        <h2>Polls</h2>
        <ul>
            <li><?php get_poll();?></li>
        </ul>
        <?php display_polls_archive_link(); ?>
    </li>
<?php endif; ?>
  • To show specific poll, use <?php get_poll(2); ?> where 2 is your poll id.
  • To show random poll, use <?php get_poll(-2); ?>
  • To embed a specific poll in your post, use [poll id="2"] where 2 is your poll id.
  • To embed a random poll in your post, use [poll id="-2"]
  • To embed a specific poll’s result in your post, use [poll id="2" type="result"] where 2 is your poll id.

Showing A Poll In A Block

Two blocks are available in the editor, under Widgets:

  • Poll — one poll, as its voting form or as its result. Set Poll ID in the sidebar, or leave it at zero for the current poll, which is what an empty [poll] does. Show chooses between the voting form and the result.
  • Polls Archive — every poll with its results, the same listing [page_polls] produces.

Both render on the server, so the block preview in the editor is the real poll rather than an approximation, and changing a poll updates every post showing it without re-saving anything.

The shortcodes still work and are not going anywhere. [poll], [poll=2] and [page_polls] behave exactly as they always have, and a post already containing one needs no change. The blocks call the same code the shortcodes call, so the two render identically — use whichever suits the post.

Showing A Poll In A Widget

  1. Go to WP-Admin -> Appearance -> Widgets.
  2. Add the Polls widget to a widget area. On block themes the widget is under the Legacy Widget block, or in Appearance -> Editor if your theme has no widget areas at all.
  3. Set its title and which poll it shows, then save.
  4. Scroll down for instructions on how to create a Polls Archive.

How To Add A Polls Archive?

  1. Go to WP-Admin -> Pages -> Add New.
  2. Type any title you like in the post’s title area.
  3. If you ARE using nice permalinks, after typing the title, WordPress will generate the permalink to the page. You will see an ‘Edit’ link just beside the permalink.
  4. Click ‘Edit’ and type in pollsarchive in the text field and click ‘Save’.
  5. Type [page_polls] in the post’s content area.
  6. Click ‘Publish’.
  • If you ARE NOT using nice permalinks, go to WP-Admin -> Polls -> Settings and fill in Poll Archive URL, under the Archive heading, with the URL of the Polls Archive page you created above.

To Display Total Polls

<?php if ( function_exists( 'get_pollquestions' ) ): ?>
    <?php get_pollquestions(); ?>
<?php endif; ?> 

To Display Total Poll Answers

<?php if ( function_exists( 'get_pollanswers' ) ): ?>
    <?php get_pollanswers(); ?>
<?php endif; ?> 

To Display Total Poll Votes

<?php if ( function_exists( 'get_pollvotes' ) ): ?>
    <?php get_pollvotes(); ?>
<?php endif; ?> 

To Display Poll Votes by ID

<?php if ( function_exists( 'get_pollvotes_by_id' ) ): ?>
    <?php get_pollvotes_by_id($poll_id); ?>
<?php endif; ?>

To Display Total Poll Voters

<?php if ( function_exists( 'get_pollvoters' ) ): ?>
    <?php get_pollvoters(); ?>
<?php endif; ?> 

To Display Poll Time by ID and date format

<?php if ( function_exists( 'get_polltime' ) ): ?>
    <?php get_polltime( $poll_id, $date_format ); ?>
<?php endif; ?>

WP-CLI

wp polls list
wp polls list --status=open
wp polls get 3
wp polls open 3
wp polls close 3
wp polls delete 3 --yes
wp polls list --status=open --format=ids | xargs -n1 wp polls close closes every open poll one at a time.

REST API

GET  /wp-json/polls/v1/poll/<id>
GET  /wp-json/polls/v1/poll/<id>/result
POST /wp-json/polls/v1/poll/<id>/vote

Reading is public, because a poll is public. Voting takes the same poll_<id>-nonce the rendered voting form already carries, passed as a nonce parameter, and is subject to the same eligibility and repeat-vote settings as voting through the page.

Each response carries the rendered markup as well as the numbers, because your templates decide what a poll looks like and a client that rebuilt the markup itself would ignore them.

A refusal answers 403, not 400 — a closed poll, a vote already cast, a bad nonce, nothing selected. 400 is kept for a parameter this plugin never had a chance to look at, and a poll that does not exist is 404. So a 403 means the request was understood and the answer is no, and sending it again differently will not help.

These routes are an addition. The admin-ajax.php polls action is unchanged and still supported.

Translating the template

The plugin templates can be translated via template variables.
There are these filters for the custom template variables

wp_polls_template_voteheader_variables
wp_polls_template_votebody_variables
wp_polls_template_votefooter_variables
wp_polls_template_resultheader_variables
wp_polls_template_resultbody_variables
wp_polls_template_resultfooter_variables

The Result Body (Voted) and Result Footer (Voted) templates are filtered by
wp_polls_template_resultbody_variables and wp_polls_template_resultfooter_variables
too – the variables are shared, only the markup filters are separate.

Add filter to your theme and register custom variable where you will add your translation.
Good practice is to name them for example with prefix STR_ in the example STR_TOTAL_VOTERS.

    /**
     * Localize wp_polls_template_resultfooter_variables.
     *
     * @param array $variables An array of template variables.
     * @return array $variables Modified template variables.
     */
    function wp_polls_template_resultfooter_variables( $variables ) {

        // Add strings.
        $variables['%STR_TOTAL_VOTERS%'] = __( 'Total voters', 'theme-textdomain' );

        return $variables;
    }

// Trigger the filter
add_filter( 'wp_polls_template_resultfooter_variables', 'wp_polls_template_resultfooter_variables' , 10, 1 );

In the admin side just call the custom variable like so and the variable has been translated in the front-end.
%STR_TOTAL_VOTERS%’

Screenshots

Blocks

This plugin provides 2 blocks.

  • Poll A poll, as a voting form or as its result.
  • Polls Archive Every poll, with its results, as an archive.

Installation

  1. Install and activate the plugin.
  2. Create your first poll at WP-Admin -> Polls -> Add Poll.
  3. Show it: type [poll] into a post, add the Poll block, add the Polls widget to a sidebar, or call get_poll() from your theme. Usage below covers all four.
  4. Templates, the bar, who may vote and how a repeat vote is spotted are all at WP-Admin -> Polls -> Settings.

FAQ

Everyone can vote as many times as they like

Check Settings -> Header That Contains The IP. If it names a header such as
HTTP_X_FORWARDED_FOR, make sure the proxy in front of WordPress always overwrites
that header. Anything a visitor can set themselves can be changed on every request,
and WP-Polls has no way to tell a real proxy from a forged header.

Before 3.0.0 WP-Polls also used the entire header value as the voter’s identity.
X-Forwarded-For is a list, client, proxy1, proxy2, so a visitor could append one
more entry and count as somebody new. It now reads only the first address in the list.

If you are not behind a proxy, leave the setting blank.

Every voter is logged with the same IP, or the wrong one

WordPress is behind a proxy or a CDN and every request reaches it from the proxy’s
address. Name the header your proxy sets under Settings -> Header That Contains
The IP
HTTP_CF_CONNECTING_IP for Cloudflare — or, to trust the usual set of
proxy headers without naming one, add this to wp-config.php:

define( 'WP_POLLS_TRUST_PROXY', true );

Sites that need to decide per request can use the wp_polls_trust_proxy filter, which
defaults to that constant.

Poll logs show a hashed IP rather than an address

That is deliberate and unchanged: WP-Polls stores wp_hash() of the address, so the
logs can tell two voters apart without keeping their IP addresses.

My poll bars lost their styling, or my customised result template came back

3.0.0 rebuilt the poll bar. It used to be one <div class="pollbar"> sized by an
inline width; it is now a track holding a fill:

<div class="wp-polls-bar" aria-hidden="true"><div class="wp-polls-bar-fill" style="width: 42%;"></div></div>

The Result Body and Result Body (Voted) templates are rewritten to that markup
on upgrade, including customised ones. There was no way to keep them: the class names
and the stylesheet changed with the markup, so a customised copy of the old template
would have rendered a bar with no rules left to match it. Re-apply your changes on
Poll Templates, keeping the two wp-polls-bar elements.

If you re-add a bar by hand, use %POLL_ANSWER_PERCENTAGE% for the width.
%POLL_ANSWER_IMAGEWIDTH% was removed in 3.0.0 and is no longer substituted, so a
template still containing it emits the literal token into the style attribute and
the bar renders with no width at all.

If your theme ships its own wp-polls.css, the bar rules are not in it — they used to
be generated by PHP into an inline <style> block, and they now live in the plugin’s
stylesheet. Either copy the .wp-polls-bar rules across, or delete your copy and
override these instead, which is the supported way now:

.wp-polls {
    --wp-polls-bar-height: 8px;
    --wp-polls-bar-background: #d8e1eb;
    --wp-polls-bar-border: #c8c8c8;
    --wp-polls-bar-radius: 3px;
}

Why doesn’t my poll’s answers add up to 100%?

  • It is because of rounding issues. To make it always round up to 100%, the last poll’s answer will get the remainding percentage added to it. To enable this feature, add this to your theme’s functions.php: add_filter( 'wp_polls_round_percentage', '__return_true' );

How Does WP-Polls Load CSS?

  • WP-Polls will load wp-polls.css from your theme’s directory if it exists.
  • If it does not exist, it loads the css/wp-polls.css that ships with WP-Polls.
  • This will allow you to upgrade WP-Polls without worrying about overwriting your polls styles that you have created.
  • A theme copy made before 3.0.0 has no poll bar rules in it, because they used to be generated by PHP. See My poll bars lost their styling above.

How Do I Have Individual Colors For Each Poll’s Bar?

  • Courtesy Of TreedBox.com
  • Set --wp-polls-bar-background on the answer rather than styling the bar itself. The bar reads that custom property, so this works whichever poll bar style is configured, and it keeps working if the markup changes again.
  • Add to the end of your wp-polls.css:
.wp-polls-ul li:nth-child(01) { --wp-polls-bar-background: #8fa0c5; }
.wp-polls-ul li:nth-child(02) { --wp-polls-bar-background: #ffff88; }
.wp-polls-ul li:nth-child(03) { --wp-polls-bar-background: #ff8a3b; }
.wp-polls-ul li:nth-child(04) { --wp-polls-bar-background: #a61e2a; }
.wp-polls-ul li:nth-child(05) { --wp-polls-bar-background: #4ebbff; }
.wp-polls-ul li:nth-child(06) { --wp-polls-bar-background: #fbca54; }
.wp-polls-ul li:nth-child(07) { --wp-polls-bar-background: #aad34f; }
.wp-polls-ul li:nth-child(08) { --wp-polls-bar-background: #66cc9a; }
.wp-polls-ul li:nth-child(09) { --wp-polls-bar-background: #98cbcb; }
.wp-polls-ul li:nth-child(10) { --wp-polls-bar-background: #a67c52; }
.wp-polls-ul li:hover { --wp-polls-bar-background: #ff0000; }
.wp-polls .wp-polls-bar-fill { transition: background-color 0.7s ease-in-out; }

Before 3.0.0 this was written against .pollbar, the single element the bar used to
be. That class no longer exists, so the old snippet colours nothing.

Reviews

Сентябр 27, 2025
This plugin is perfect. Thank you so much to the creators. The only thing that I miss is being able to make anonymous polls, so I would like to be able to activate an option in the poll for anonymous polls, in which the logs show all the votes together, without indicating what option each person has voted for.
Май 22, 2024
For the ones who know something about HTML and CSS syntax, this plugin is perfect! It does exactly what is needed regarding polls, while the looks can be fully customized. IMHO, a brilliant piece of work!
Апрел 29, 2023
Hi there, I’ve been using this plugin and loved it for its simplicity alongside with the ability to customize the look and feel. Somehow, at some point, the admin interface changed and I am now able to see the answers of all users. Before, I was only able to see how many users voted for each answer, not who. This is a major problem for me. Is there any way to hide the usernames from the answers given? I need to see which users voted, but not what answer they gave. The answers should only be seen as a total for each option. Thanks
Октябр 21, 2022
Love the feature set, easy to use, great to work with, but it fails with my cache setup (standard Cloudflare) setup. Have to remove it a site and move to another solution, sadly this was after my install, setting up on my custom post types, etc. Would love to see it updated in the future.
Июл 23, 2022
Excellent, easy going plugin. Thank you.
Read all 136 reviews

Contributors & Developers

“WP-Polls” is open source software. The following people have contributed to this plugin.

Contributors

“WP-Polls” has been translated into 16 locales. Thank you to the translators for their contributions.

Translate “WP-Polls” into your language.

Interested in development?

Browse the code, check out the SVN repository, or subscribe to the development log by RSS.

Changelog

3.0.0

  • FIXED: The limit on how many answers a vote may select was enforced in the browser and nowhere else, so one crafted request could vote for every answer of a single-choice poll — each answer gaining a vote and the poll’s total gaining several, while the voter count went up by one. That leaves the percentages, %POLL_MOST_ANSWER% and %POLL_LEAST_ANSWER% permanently wrong. The maximum is checked on the server now, on both the AJAX and REST paths
  • NEW: A wp polls WP-CLI command — list, get, open, close and delete.
  • NEW: A polls/v1 REST API for reading a poll, reading its result and voting. The admin-ajax.php polls action is unchanged and still supported.
  • NEW: Two editor blocks, Poll and Polls Archive, both under Widgets. They render on the server through the same code the shortcodes use, so a block and a shortcode showing the same poll produce the same markup. The [poll], [poll=2] and [page_polls] shortcodes are unchanged and still supported — nothing needs converting, and posts already containing them keep working.
  • BREAKING: Requires WordPress 6.8 and PHP 8.2, up from 6.0 and 7.4.
  • BREAKING: The scripts no longer define any global JavaScript functions. poll_vote(), poll_result(), poll_booth() and the admin equivalents are now private, so custom templates or themes that called them directly must move to data-poll-id / data-poll-action attributes. WP-Polls converts the stock templates for you on upgrade and warns in wp-admin about any it could not convert.
  • CHANGED: Options, templates, settings, the widget and the install/upgrade routine moved into classes under includes/. The documented extension points are unchanged: every wp_polls_* filter and action, both the [poll] and [page_polls] shortcodes, and the template tags keep their exact names and signatures.
  • CHANGED: The thirty-odd separate wp_options rows are now a single wp_polls_options row holding a nested array. Your settings are migrated automatically on upgrade; the old rows are removed once they have been folded in.
  • FIXED: XSS in the Poll Templates screen. Inline onclick handlers are replaced by data-poll-action / data-poll-id attributes and onclick is no longer an allowed attribute in poll templates.
  • FIXED: On multisite, uninstall called restore_current_blog() once after the loop rather than once per site. switch_to_blog() pushes onto a stack, so the stack was left unwound by every site but the first.
  • FIXED: On uninstall the three poll tables were dropped from inside the loop over option rows, so the drop ran 36 times per site and issued three DROP TABLE statements each instead of three in total.
  • CHANGED: Uninstall asks get_sites() for IDs only rather than hydrating a WP_Site object per site, and its table-dropping helper is now prefixed wp_polls_uninstall_site() instead of occupying the unprefixed global name plugin_uninstalled().
  • FIXED: Network activating on multisite was a fatal error. The activation routine called wp_get_sites(), which WordPress removed in 5.1.
  • FIXED: On multisite the three poll tables were not registered with $wpdb, so any query made inside switch_to_blog() read and wrote the wrong site’s polls.
  • FIXED: Adding or removing a poll answer in wp-admin no longer breaks. It called jQuery’s .size(), which was removed in jQuery 3.
  • FIXED: The poll bar tooltip showed a literal &amp; for any answer containing an ampersand. The polls archive had its own copy of the same bug in %POLL_ANSWER_TEXT%, which is fixed too.
  • FIXED: Poll Logs had the same double encoding: an answer containing an ampersand showed a literal &amp; in both the answer filter and the log table.
  • FIXED: Voters identified by the comment author cookie were logged with a backslash before any apostrophe, so a commenter named O'Brien appeared in Poll Logs as O\'Brien.
  • FIXED: $_SERVER['REMOTE_ADDR'] is no longer read unguarded, which warned under WP-CLI and cron on PHP 8.
  • FIXED: The result and vote links no longer follow their placeholder href when clicked.
  • FIXED: Removed the duplicated shortcode registration.
  • FIXED: Undefined array key warnings on missing stats_display options.
  • FIXED: Warnings when rendering a poll whose ID no longer exists.
  • FIXED: The voting endpoint read $_REQUEST['view'] without checking it was set, which warned on PHP 8 for any request that left it out.
  • FIXED: Activation looked for wp-admin/upgrade-functions.php, which WordPress removed in 2.x, and stopped with an error message if it found neither that nor the current file.
  • FIXED: Poll Options could offer a poll bar style that saving then rejected, reverting it while still reporting «Settings saved.» The screen and the sanitiser now build the list of available styles the same way.
  • FIXED: Every stylesheet, script and image URL was built from a hardcoded wp-polls/ path, so renaming the plugin directory left WP-Polls loading none of its own assets. All paths now come from the plugin file itself.
  • CHANGED: Poll Options and Poll Templates now use the WordPress Settings API instead of hand-rolled form handling. Every row on both screens is registered with add_settings_section() and add_settings_field() and rendered by do_settings_sections(), so the screens look and behave like the rest of wp-admin and neither one writes any table markup of its own.
  • CHANGED: Poll Bar Background and Poll Bar Border are colour pickers now – the browser’s own colour input, the same control WP-Postratings uses – rather than six character text fields with a # printed beside them and a swatch kept in step by JavaScript. The bar preview follows the colour as it is picked. The setting is still stored as the six digits without the #, so a theme or filter reading it sees what it always did; a three digit value left over from 2.x is expanded to six on the way out, because a colour input will not display #abc.
  • CHANGED: Manage Polls is now a WP_List_Table, so it paginates at 20 polls a page, sorts on ID, Total Voters and Start Date, and puts Edit, Logs and Delete in hover row actions instead of three columns of links. The poll the site is currently showing is still highlighted.
  • CHANGED: Add Poll, Edit Poll and Poll Logs are built out of the standard wp-admin furniture – form-table rows with real labels, submit_button(), notice messages, and one h1 per screen – rather than tables laid out with width, valign and align attributes. The Cancel buttons are links back to Manage Polls instead of a history.go(-1) that could not be middle-clicked or opened in a new tab.
  • FIXED: The stats under Manage Polls were accumulated while printing rows, which would have counted only the page being looked at once the list paginated. They are summed in SQL now.
  • FIXED: Opening the logs of a poll that allows multiple answers raised four undefined variable warnings: that filter’s fields were only initialised inside the branch that handles its own submission.
  • FIXED: The poll logs named their answers from a list built while printing the filter dropdown, so with the wp_polls_log_show_log_filter filter turned off every group heading in the log was blank. A vote recorded against no answer at all also warned instead of printing «Null Votes».
  • FIXED: Rows in the by-voter poll log never alternated: the row counter was reset inside the loop rather than at each new voter.
  • FIXED: Changing «Expiry Time For Cookie And Log» did not reschedule the cron job. The callback that rebuilds the schedule was registered while the Poll Options screen rendered, but the save happens on options.php, which never loads that screen.
  • CHANGED: Removed every remaining inline onclick/onblur/onchange handler from the admin pages in favour of data-poll-action attributes and delegated listeners, so poll questions and answers no longer have to be escaped into a JavaScript context.
  • CHANGED: Dropped the jQuery dependency. Both scripts, the inline admin scripts and the TinyMCE plugin now use the browser’s own APIs, so WP-Polls no longer forces jQuery to load on the front end.
  • CHANGED: The scripts ship as readable source; the .dev.js copies have been removed.
  • FIXED: The polls-admin AJAX handler now checks the manage_polls capability instead of relying on its nonces for authorisation.
  • FIXED: Escaped the poll bar colours, the voting form action and %POLL_RESULT_URL% on output, and validated the poll bar colours on save.
  • BREAKING: «Poll Logging Method» is now «Check For Repeat Votes», and it no longer decides whether anything is logged. It never did anything but choose what a returning visitor is matched against, and the two readings pointed opposite ways: a site that picked «Do Not Log» or «Logged By Cookie» got no vote log, no rows on the Logs screen and no WP-Stats figures, which is not what either choice sounds like. Every vote is now recorded whatever this is set to. The choices read «Do Not Check», «Check By Cookie», «Check By IP Address», «Check By Cookie And IP Address» and «Check By Username»; the stored numbers are unchanged, so your setting means what it always meant. The option key inside wp_polls_options is check_method rather than logging_method, migrated automatically. Sites that would rather not keep the record can return false from the new wp_polls_log_vote filter; the answer tallies and poll totals are columns on the poll tables and are updated either way.
  • BREAKING: «Expiry Time For Cookie And Log» is now «Remember A Voter For», and its hint no longer says the opposite of what the setting does. It offered «0 to disable»; zero disables nothing, it is what makes the block permanent — a cookie lasting a year and no time limit at all on the IP and username queries. Nothing expires in the sense of being deleted either: the poll log keeps every vote whatever this says. All it decides is how far back a repeat-vote check looks. The value is unchanged, so existing sites behave exactly as before.
  • BREAKING: The «Polls AJAX Style» settings are gone. They chose whether to show a loading indicator and whether to fade the poll while a vote was in flight. Telling somebody their vote is being processed is feedback rather than decoration, so the indicator now always shows; and whether to animate is the visitor’s answer rather than the site owner’s, so the fade follows prefers-reduced-motion like the spinner and the result bars already did. poll_ajax_style is dropped on upgrade rather than carried.
  • BREAKING: The poll bar has been rebuilt and the change is applied on upgrade. It was one <div class="pollbar"> sized by an inline width; it is now a wp-polls-bar track holding a wp-polls-bar-fill, which is what lets a 100% answer render at a true 100%. The Result Body and Result Body (Voted) templates are rewritten to the new markup on upgrade even if you had customised them – the class names and the stylesheet moved with the markup, so a customised copy of the old template has no rules left to match it. Re-apply your changes on Poll Templates. See the FAQ.
  • BREAKING: The poll bar rules moved out of the PHP-generated inline <style> block and into css/wp-polls.css. Only four custom properties are emitted inline now – --wp-polls-bar-height, --wp-polls-bar-background, --wp-polls-bar-border and --wp-polls-bar-image – and overriding those is the supported way to restyle the bar. If your theme ships its own wp-polls.css, the bar rules are not in it; see the FAQ.
  • BREAKING: The images/default and images/default_gradient poll bar tiles are gone. The two shaded styles were 1px wide GIFs that carried their own colours, so picking one silently discarded the Poll Bar Background setting. Poll Bar Style is now Flat or Gradient, both drawn in CSS from the colour you configure. default and default_gradient become Gradient on upgrade, and the old «Use CSS Style» becomes Flat.
  • FIXED: A poll answer with every vote drew a 99% bar, and in the polls archive every bar drew at 90% of its real percentage, so the same answer was a visibly different length in the two places. Both fudges existed to stop the old bar’s border overflowing its container and are no longer needed.
  • FIXED: An answer with no votes drew a 1% sliver of a bar rather than an empty one.
  • FIXED: The polls archive applied the wp_polls_round_percentage rounding buffer unconditionally while the poll itself only applied it when the filter was turned on, so on a default install the same poll reported one set of percentages on the page and a different set in the archive. The archive now honours the filter, which defaults to off. If you relied on archive percentages summing to exactly 100, add add_filter( 'wp_polls_round_percentage', '__return_true' ); to turn it back on — it now applies in both places.
  • FIXED: With the wp_polls_round_percentage filter enabled, the last answer’s printed percentage gets a rounding buffer added so the column sums to 100. The bar width was calculated before that happened, so the last answer printed one number and drew a different one. Every bar now matches the percentage beside it.
  • BREAKING: The %POLL_ANSWER_IMAGEWIDTH% template variable has been removed and is no longer substituted. It only ever held the percentage with a fudge applied so the old bar’s border did not overflow, and with the fudges gone it said nothing %POLL_ANSWER_PERCENTAGE% does not. Use %POLL_ANSWER_PERCENTAGE% instead. The upgrade rewrites both result templates, so you only need to act if you re-customise them afterwards.
  • CHANGED: The poll bar no longer carries a title tooltip repeating the percentage and vote count that are already printed beside it, and is marked aria-hidden so screen readers do not read those numbers twice. On Result Body (Voted) the «You Have Voted For This Choice» tooltip moves onto the answer text itself.
  • CHANGED: The bar fill animates in, and honours prefers-reduced-motion.
  • CHANGED: wp-polls-rtl.css has been removed. css/wp-polls.css now uses CSS logical properties, so the one stylesheet lays out correctly in both directions and right-to-left sites load one file fewer. If your theme overrides wp-polls-rtl.css, fold those rules into your wp-polls.css.
  • BREAKING: If you set «Header That Contains The IP», WP-Polls used the whole header as the voter’s identity. X-Forwarded-For is a chain the visitor controls the left of, so appending one more hop produced a different identity and another vote. It now takes the first valid address in the header, and falls back to REMOTE_ADDR when the header holds no address at all. Sites that left the setting blank are unaffected and their existing vote logs still match. See the FAQ.
  • CHANGED: Added the WP_POLLS_TRUST_PROXY constant and the wp_polls_trust_proxy filter, matching WP-Email and WP-UserOnline, so sites behind Cloudflare or a load balancer can opt in to the usual proxy headers without naming one on the settings screen. Proxy headers are still ignored unless you opt in.
  • CHANGED: Reformatted to the WordPress Coding Standards. Fifteen translatable strings gained numbered placeholders (%1$s), which changes their msgid, so those strings need retranslating.
  • BREAKING: The settings row is named wp_polls_options rather than poll_options, and the two version markers poll_version and poll_db_version collapse into one wp_polls_version row holding plugin and db. All three old rows are folded in and removed on upgrade.
  • BREAKING: Poll Options and Poll Templates are two tabs of one Polls -> Settings screen instead of two menu entries. Their URLs change from admin.php?page=wp-polls/polls-options.php and …/polls-templates.php to admin.php?page=wp-polls-settings&tab=options and &tab=templates, and Manage Polls and Add Poll move to admin.php?page=wp-polls and ?page=wp-polls-add.
  • BREAKING: WP-Polls no longer reads or writes WP-Stats’ shared stats_display row. Whether the polls block appears on the WP-Stats page is now a WP-Polls setting, under WP-Polls -> Settings -> WP-Stats, and WP-Polls contributes its block through the wp_stats_sections filter. Update all seven WP-Stats plugins together.
  • BREAKING: Every class is prefixed WP_Polls_: Polls_Options is WP_Polls_Options, Polls_Display is WP_Polls_Display, Polls_Vote is WP_Polls_Vote, Polls_Settings is WP_Polls_Settings, Polls_Install is WP_Polls_Install, Polls_Widget is WP_Polls_Widget, Polls_List_Table is WP_Polls_List_Table, Polls_Templates is WP_Polls_Template and Polls_Core is plain WP_Polls. The template tags, the shortcodes and every wp_polls_* hook are unchanged.
  • NEW: WP_POLLS_DB_VERSION alongside WP_POLLS_VERSION, and a wp_polls_capability filter over the manage_polls check.
  • CHANGED: The plugin files are laid out the way every other plugin here is: the five loose screens move into includes/, the stylesheets into css/ and the scripts into js/, named after the plugin. A theme overriding polls-css.css should rename its copy wp-polls.css.
  • CHANGED: The localised script objects are wpPollsL10n and wpPollsAdminL10n, replacing pollsL10n and pollsAdminL10n.
  • CHANGED: The loading indicator is drawn in CSS instead of loading images/loading.gif, so it inherits the theme’s colour, scales with the font size and stops animating for a visitor who has asked for reduced motion. images/ is gone.
  • CHANGED: No wp-admin screen carries an inline style attribute any more: status messages use core’s notice classes and anything that starts hidden uses core’s .hidden class.
  • CHANGED: The front end stylesheet sets no font and no text colour, and its hardcoded blues, blacks and whites become currentColor plus the --wp-polls-border and --wp-polls-surface custom properties, so a poll is legible on a dark theme without a second stylesheet.
  • CHANGED: The two inline <script> blocks the settings screens carried – the poll bar preview and the Restore Default Template buttons – moved into js/wp-polls-admin.js.
  • FIXED: current_time( 'timestamp' ), which WordPress deprecated, is replaced by WP_Polls::now(). Poll times are still stored as site-local, so nothing shifts.
  • NOTE: Every filter and action WP-Polls fires now carries a docblock recording what it is passed and which release introduced it.
  • FIXED: The «maximum number of choices allowed» alert ended in a trailing space inside the translated string, and the script added a space of its own — so the number was preceded by two. The space belongs to the script, which is the same in every language