Database schema

{prefix}lh_poll_options

Per-site on Multisite.

Column Type Description
option_id BIGINT UNSIGNED Primary key
poll_id BIGINT UNSIGNED Parent poll post ID
label VARCHAR(255) Display label
menu_order INT Sort order

{prefix}lh_poll_votes

Per-site on Multisite.

Column Type Description
vote_id BIGINT UNSIGNED Primary key
poll_id BIGINT UNSIGNED Parent poll post ID
option_id BIGINT UNSIGNED Option voted for
user_id BIGINT UNSIGNED Voter
comment_id BIGINT UNSIGNED Linked wp_comments row
voted_at DATETIME Vote timestamp

Unique constraint: (option_id, user_id) – one vote per user per option, enforced at the database level.

wp_comments (comment_type = lh_vote)

Every vote creates a wp_comments row of type lh_vote attached to the poll post (comment_post_ID = poll_id). This enables optional comment text alongside a vote, viewing/deleting votes via the standard WP comments admin screen, and vote counts visible as comment_count on the poll post. Vote comments are excluded from all standard comment queries, feeds, and counts on non-poll posts. Deleting a vote comment via the WP comments screen automatically removes the corresponding vote row via the deleted_comment hook. post_parent on lh_poll is unused (default 0) – not repurposed for anything.

Caching

All poll read queries (options list, option IDs, vote counts, per-option vote list, per-user voted flags) are cached as transients backed by the persistent object cache (Redis on LocalHero). Cache is keyed per poll/option/user and flushed explicitly on any vote insert, delete, or option change via LH_Polls_DB::flush_poll_cache() – TTL (DAY_IN_SECONDS) is a safety net only, since invalidation is explicit on every write.

Cache invalidation (page cache)

After a vote is cast or changed, the plugin fires do_action(‘litespeed_purge_url’, $page_url) to purge the embedding page from LiteSpeed’s page cache. A no-op on non-LiteSpeed environments.