=== KindlyVote ===
Contributors: generalistsam
Tags: voting, elections, contest, awards, poll
Requires at least: 6.4
Tested up to: 7.1
Requires PHP: 8.1
Stable tag: 1.4.3
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Modern voting & elections for WordPress — events, contestants, and webhook-verified payments for Africa.

== Description ==

KindlyVote turns any WordPress site into a complete voting and elections platform. Run beauty
pageants, award shows, talent contests, and school, church, or association elections — as free
polls, or as paid contests where every vote is only counted after the payment gateway confirms it.

Built for African organizers, KindlyVote supports **Paystack** and **Flutterwave** out of the box,
works in local currencies (NGN, GHS, ZAR, KES, RWF, XOF), and records paid votes only after a
signature-verified webhook — so a vote is never counted before the money is confirmed.

= Use cases =

* Beauty pageants and modeling contests
* Award shows and "of the year" competitions
* Talent shows and fan voting
* School and student-union elections
* Church, NGO, and association elections
* Any contest that sells votes, or any free poll

= Create your event =

* Unlimited voting events, each with its own start and end window (timezone-aware)
* Paid or free mode per event, with a simple price-per-vote for paid contests
* Organize contestants into categories or positions, each with its own ready-to-copy shortcode

= Contestant profiles =

* Featured photo, bio, brand or business name, and a contest number
* A drag-to-reorder photo gallery, with thumbnails that swap the main image
* Social links (Instagram, Facebook, X, TikTok, website) and a video URL

= Free voting =

* One vote per email — per contestant, per category, per event, or unlimited
* Optional CAPTCHA — Cloudflare Turnstile or Google reCAPTCHA
* Per-IP rate limiting to curb spam
* Restrict voting to specific email domains (e.g. only @company.com) for internal elections

= Paid voting =

* Paystack and Flutterwave, with webhook plus server-side verification
* The amount is always set on the server — the browser can never change the price
* Idempotent recording — a webhook and a browser callback can both fire without double-counting

= Display and results =

* `[kvote_contest]` — a responsive grid of contestants with vote buttons
* `[kvote_leaderboard]` — a ranked standings board with vote bars
* A mobile-friendly vote popup, and a Primary colour setting to match your site

= Administration and audit =

* A paginated Voting Logs screen — filter by status, voter email, and date range for a full audit trail
* Add or set a contestant's vote count manually, recorded as an auditable adjustment
* A dashboard with live totals, revenue, and top contestants

KindlyVote is built on modern, secure, object-oriented foundations and is designed to scale to
large events. For live real-time results, advanced analytics, and fully hosted elections, see
KindlyVote Cloud at https://kindlyvote.com.

== External services ==

This plugin relies on third-party payment and bot-protection services. None of them are contacted
until you enable and configure that specific service in the plugin settings. If you run only free
events with no CAPTCHA, the plugin makes no external connections.

**Paystack** (payment gateway)

* What it is and why: a payment gateway used to collect votes as payments on paid events.
* What is sent and when: when a voter chooses to pay, the plugin loads Paystack's checkout script
  from `js.paystack.co` and sends the transaction details (amount, currency, a unique reference, and
  the voter's email) to `api.paystack.co` to create and then verify the payment. Verification also
  happens server-to-server against `api.paystack.co`, and Paystack confirms payments back to your
  site via a signed webhook.
* Conditions: only on paid votes, and only if you have entered your Paystack API keys.
* Terms of service: https://paystack.com/terms
* Privacy policy: https://paystack.com/privacy/merchant

**Flutterwave** (payment gateway)

* What it is and why: a payment gateway used to collect votes as payments on paid events.
* What is sent and when: when a voter chooses to pay, the plugin loads Flutterwave's checkout script
  from `checkout.flutterwave.com` and sends the transaction details (amount, currency, a unique
  reference, and the voter's email) to Flutterwave. Verification happens server-to-server against
  `api.flutterwave.com`, and Flutterwave confirms payments back to your site via a signed webhook.
* Conditions: only on paid votes, and only if you have entered your Flutterwave API keys and selected
  Flutterwave as a gateway.
* Terms of service: https://flutterwave.com/terms
* Privacy policy: https://flutterwave.com/privacy-policy

**Cloudflare Turnstile** (optional CAPTCHA)

* What it is and why: a bot-protection challenge on the free vote form, used only if you enable
  Turnstile as your CAPTCHA provider.
* What is sent and when: when the vote form is shown, the challenge widget is loaded from
  `challenges.cloudflare.com`; on submit, the challenge token and the visitor's IP are sent
  server-to-server to `challenges.cloudflare.com/turnstile/v0/siteverify` to confirm the visitor is
  human.
* Conditions: only on free-vote submissions, and only if Turnstile is configured.
* Terms of service: https://www.cloudflare.com/website-terms/
* Privacy policy: https://www.cloudflare.com/privacypolicy/

**Google reCAPTCHA** (optional CAPTCHA)

* What it is and why: a bot-protection challenge on the free vote form, used only if you enable
  reCAPTCHA as your CAPTCHA provider.
* What is sent and when: when the vote form is shown, the reCAPTCHA widget is loaded from
  `www.google.com/recaptcha`; on submit, the challenge token and the visitor's IP are sent
  server-to-server to `www.google.com/recaptcha/api/siteverify` to confirm the visitor is human.
* Conditions: only on free-vote submissions, and only if reCAPTCHA is configured.
* Terms of service: https://policies.google.com/terms
* Privacy policy: https://policies.google.com/privacy

== Installation ==

1. Upload the `kindlyvote` folder to `/wp-content/plugins/`, or install it from the Plugins screen.
2. Activate the plugin through the "Plugins" menu in WordPress.
3. Set your site timezone under Settings → General so voting windows are accurate.
4. Open **KindlyVote → Settings** to choose your currency and, for paid contests, add your payment
   gateway keys.
5. Create an **Event**, add **Categories** and **Contestants**.
6. Place the `[kvote_contest]` shortcode (shown on the Categories screen) on any page to start voting,
   and `[kvote_leaderboard]` to show standings.

== Frequently Asked Questions ==

= Do I need to know how to code? =

No. You manage everything from the WordPress admin and display contestants with a shortcode you copy
from the Categories screen.

= Which payment gateways are supported? =

Paystack and Flutterwave. You can enable one or both and choose a primary gateway.

= Can I run a completely free election? =

Yes. Set an event to "free" mode and no payment is required — ideal for internal or community elections.

= Are votes counted before payment is confirmed? =

No. Paid votes are recorded only after the gateway's webhook confirms and the payment is re-verified
on your server. The vote amount is always calculated server-side, so it cannot be tampered with.

= How do I display contestants on a page? =

Use the `[kvote_contest]` shortcode. The Categories screen shows the exact shortcode for each category
(with its ID filled in) — just copy and paste it onto any page or post.

= Can I limit each person to one vote? =

Yes. For free events you can allow one vote per email — per contestant, per category, per event — or
allow unlimited votes. Paid votes are never limited, since each vote is purchased.

= Which currencies are supported? =

Nigerian Naira (NGN), Ghanaian Cedi (GHS), South African Rand (ZAR), Kenyan Shilling (KES), Rwandan
Franc (RWF), and West African CFA Franc (XOF).

= Does uninstalling delete my data? =

Only if you choose to. Data is preserved by default; enable "Delete all data on uninstall" in
Settings if you want everything removed when the plugin is deleted.

== Screenshots ==

1. The KindlyVote dashboard — live totals, revenue, and top contestants.
2. Creating a voting event with dates, mode, and price-per-vote.
3. A contestant profile with photo gallery and social links.
4. The front-end contestant grid with vote buttons.
5. The mobile-friendly vote popup.
6. The leaderboard with ranked standings.
7. Voting Logs — a filterable audit trail of every vote.
8. Settings — currency and payment gateways.

== Changelog ==

= 1.4.3 =
* Renamed all internal registrations (post types, taxonomy, shortcodes, AJAX actions, capability,
  meta keys, and database tables) to use a longer, more distinctive prefix, preventing name
  collisions with other plugins. The front-end shortcodes are now `[kvote_contest]` and
  `[kvote_leaderboard]` (the legacy `[kindlyvote_contest]` alias still works).

= 1.4.2 =
* Fixed: a contestant's video URL now appears as a "Watch video" link on the front-end contestant
  card (the field was previously saved but not displayed).

= 1.4.1 =
* Code-quality and security hardening pass (output escaping and autoloader robustness) plus readme
  improvements for the WordPress.org listing.

= 1.4.0 =
* Front end: the Vote button now opens a modal popup (better on mobile than inline fields).
* Settings: a Primary colour option drives vote buttons, leaderboard bars, and highlights.
* Dashboard: added KindlyVote Cloud and KindlyVote AI cards.

= 1.3.2 =
* Dashboard: added a "KindlyVote Cloud" panel highlighting hosted-platform features.

= 1.3.1 =
* Categories screen now offers a ready-to-copy, category-scoped [kv_leaderboard] shortcode alongside
  the contestants one, so leaderboards are scoped by default.

= 1.3.0 =
* New: contestant photo gallery — add multiple images from the media library (drag to reorder);
  thumbnails on the contestant card swap the main photo.

= 1.2.1 =
* New: a Shortcodes reference page (KindlyVote → Shortcodes) documenting every shortcode with
  attributes and copy-ready examples.

= 1.2.0 =
* New: [kv_leaderboard] shortcode — a ranked standings board (by category, event, or overall) with
  vote bars and optional photos.

= 1.1.0 =
* Contestants: added profile fields — brand/business name, contest number, social links, and a video
  URL, shown on the front-end contestant cards.
* Contestants: set a vote count to an exact number directly (recorded as a single ledger adjustment,
  so totals stay auditable).

= 1.0.10 =
* Voting Logs: added a From / To date-range filter.

= 1.0.8 =
* New: Voting Logs admin page — a paginated, filterable audit view of every free, paid, and manual
  vote (status and voter-email filters).

= 1.0.7 =
* Voting window: interpret event start/end in the site timezone, and clearly distinguish "Voting
  opens on <date>" (not started) from "Voting has closed".

= 1.0.6 =
* Voting form: show the allowed email domain(s) as a hint, with an instant client-side check before
  submit (the server still enforces eligibility).

= 1.0.5 =
* Events: restrict voting to specific email domains (e.g. only @company.com) via a per-event
  "Allowed email domains" setting. Applies to free and paid voting.

= 1.0.4 =
* Anti-fraud: optional CAPTCHA on free voting — Cloudflare Turnstile or Google reCAPTCHA, with
  server-side token verification.

= 1.0.3 =
* Free voting: added a "Free vote limit" setting to control repeat votes from the same email — per
  contestant (default), per category, per event, or unlimited.

= 1.0.2 =
* Flutterwave: reliably dismiss the inline checkout after a successful payment.

= 1.0.0 =
* Initial build: events, contestants, categories, settings, and lifecycle management.

== Upgrade Notice ==

= 1.4.3 =
First public release of KindlyVote.
