Init Review System adds a clean and customizable 5-star rating system to your WordPress site. Votes are stored via REST API, tracked with
localStorage, and the average score is auto-calculated and optionally displayed with schema markup.
Built to be lightweight, developer-friendly, and easy to integrate into any theme or custom UI. Now with
multi-criteria reviews, an
emoji reactions system for richer user interaction, native
Block Editor support, and read-only
Abilities API integration for WordPress 6.9+.
This plugin is part of the
Init Plugin Suite — a collection of minimalist, fast, and developer-focused tools for WordPress.
GitHub repository:
https://github.com/brokensmile2103/init-review-system
Highlights:
- NEW: Block Editor (Gutenberg) support — 4 blocks, one per shortcode
- NEW: Abilities API support (WordPress 6.9+) — 3 read-only abilities
- 5-star voting via frontend
- Multi-criteria review support
- Emoji Reactions with Login Enforcement
- Average score display
- Optional login requirement
- Optional strict IP checking
- REST API for vote submission
- JSON-LD schema for SEO
- Works with any post type
- Minimal, theme-friendly UI
2.0.1 – September 26, 2026
- Fixed: the activation hook was registered from
includes/init.php with the wrong __FILE__, so it never ran — tables were only created the first time an administrator opened wp-admin, and front-end requests before that could fail. Tables are now created on activation (network-wide activation creates them for every site)
- Fixed: the bundled translations (e.g. Vietnamese) were never loaded for PHP strings because
load_plugin_textdomain() was missing. WordPress.org language packs still take priority
- Fixed: the Block Editor Vietnamese JSON translation was double UTF-8 encoded (garbled text). Regenerated with WP-CLI;
blocks-editor.js now uses __() directly so its strings are extracted automatically by wp i18n make-pot
- Fixed: with strict IP check enabled, a guest whose review was rejected by moderation (banned word, repetition...) could not fix it and resubmit, because the IP was recorded before moderation. The IP is now recorded only after the review is saved
- Fixed: admin notices after approving/rejecting/deleting a single review were never shown (redirect happened first). Bulk actions now also redirect (no resubmission on refresh) and keep the current filters
- Fixed: the review management handlers ran on every admin request (including admin-ajax) and could trigger "Security check failed" for other plugins using the same
action / review_id parameters. They now only run on the plugin's own page
- Fixed:
review-management.js was not loaded when the admin language was not English (the page hook name depends on the translated menu title)
- Fixed: saving a post re-calculated
_init_review_total from the rounded average even when nothing was changed in the Review Score metabox, slowly drifting the total (e.g. 13 → 12.99). _init_review_weighted is now also recalculated on manual adjustment and removed on reset
- Fixed: "Load more reviews" always started from page 2 even when
paged > 1, and could show up on the last page. Double clicks no longer load the same page twice
- Fixed: default avatar URL contained a double slash (
assets//img)
- Fixed: the delete confirmation dialog broke with translations containing quotes; review statuses in the admin list are now translated
- Fixed: shortcode builder translations never loaded (wrong global name), the Copy button failed on non-HTTPS admin,
[init_review_score] offered an unsupported schema option (replaced by sub, show_count, hide_if_empty) and unchecked default-on options (e.g. css) were ignored
- Security: REST endpoints and abilities no longer expose or accept votes/reviews/reactions for draft, private, or scheduled posts to visitors who cannot read them (filterable via
init_plugin_suite_review_system_can_view_post)
- Improved (performance): a vote no longer clears the site-wide average cache, which previously forced an
AVG() over the whole postmeta table on almost every vote
- Improved (performance): criteria score summary uses one query instead of two and sanitizes each label once instead of once per score; admin summary stats use one query instead of three; review content is tokenized once instead of twice
- Improved (performance): user objects for the initial review list are primed in bulk; the review list query is skipped when there are no reviews
- Improved: review cache versions are time-based, so a persistent object cache evicting the version key can never revive stale entries; the site-wide review list is invalidated too
- Improved: reactions — no DB writes or recount when removing a reaction that does not exist; DB errors are reported instead of returning success; the reactions script data is printed once per page instead of once per bar
- Improved (JS): scripts initialize correctly when deferred/delayed by optimization plugins; star listeners in the review modal were bound twice; re-firing
init-review-system:criteria-loaded no longer binds handlers twice (which could submit a review twice); blocked localStorage no longer breaks the script; multiple reactions bars for the same post share one summary request
- Improved:
[init_review_criteria] now honors the init_plugin_suite_review_system_criteria filter (previously only the REST API did); class attributes accept multiple classes; the vote auto-insert and comment-form hooks are named functions (removable with remove_action)
- Changed:
wpmu_new_blog (deprecated) replaced by wp_initialize_site; uninstall also removes the DB version option and the global average transient (review data is still kept)
- Dev: codebase follows WordPress Coding Standards (WPCS 3); JavaScript source files are shipped unminified-readable
- New filters:
init_plugin_suite_review_system_can_view_post, init_plugin_suite_review_system_client_ip, init_plugin_suite_review_system_enqueue_style; new action: init_plugin_suite_review_system_after_admin_review_action
2.0.0 – August 4, 2026
- New: Abilities API support (WordPress 6.9+): registers three read-only abilities under the
init-review-system category — init-review-system/get-review-score (average score + vote count), init-review-system/get-criteria-reviews (criteria breakdown + a page of written reviews), and init-review-system/get-reactions-summary (emoji reaction counts). All three are discoverable and executable via PHP, wp_get_abilities(), and — when a site opts in — the wp-abilities/v1 REST namespace. Actions that write data (vote, submit review, toggle reaction) are intentionally not exposed as abilities. Fully optional and backward-compatible: on WordPress versions older than 6.9, the integration silently does nothing
- New: Block Editor (Gutenberg) support: four dynamic blocks, grouped under their own Init Review System block category (instead of the generic "Widgets" category) — Review Score, Review Widget, Review Criteria, and Reactions Bar, matching
[init_review_score], [init_review_system], [init_review_criteria], and [init_reactions] respectively. Each block is registered via block.json (with a PHP render.php file wired through the "render" field, WP 6.1+) that calls the exact same shortcode function as its shortcode counterpart — no duplicated display logic, output always matches. The editor integration is a single, no-build-step vanilla JavaScript file using wp.serverSideRender for a live preview directly in the editor
- Changed: the four shortcode handlers were converted from anonymous closures to named functions (
init_plugin_suite_review_system_shortcode_*) so the new blocks' render.php files can call them directly instead of duplicating logic. No change in shortcode behavior or output
- Changed:
Requires at least raised from 5.5 to 6.9 to support the Abilities API integration. Requires PHP remains 7.4
- Improved:
/get-criteria-reviews (REST) and /reactions/summary (REST) now share their core data-assembly logic with the new abilities via two internal helper functions, instead of the same query/formatting logic existing twice
Tested up to: 7.1
1.19 – August 2, 2026
- Fixed: vote totals (
_init_review_total / _init_review_count) were updated with a read-then-write pattern that could silently drop a vote when two requests landed at nearly the same time on a busy post. Now uses an atomic SQL increment so concurrent votes are never lost.
- Fixed: reaction counters could drift from real data for the same read-then-write reason. Reaction counts are now computed directly (COUNT) from the
init_reactions table — the table is the single source of truth — with a 1 hour object cache. Post meta _irs_rx_* is kept in sync for backward compatibility (e.g. sites using it in orderby/meta_query) but is no longer authoritative.
- Fixed: the DB upgrade routine only ran table creation when a table was missing, so schema changes in new versions (like the indexes below) never reached sites that already had the plugin installed. It now always re-runs
dbDelta(), which is additive/safe by design.
- Fixed: after submitting a multi-criteria review, the frontend re-computed the new overall average/breakdown with a client-side moving-average formula based on numbers snapshotted at page load — if another visitor submitted a review in the meantime, the displayed score could be briefly wrong until the page was reloaded.
/submit-criteria-review now returns the real, freshly-queried summary (overall_avg/breakdown/total) and the frontend just renders it directly.
- Changed:
init_plugin_suite_review_system_get_reviews_by_post_id() / ..._get_total_reviews_by_post_id() are now cached for 5 minutes by default (was disabled by default). Still fully overridable via the init_plugin_suite_review_system_ttl filter (return 0 to disable). Cache is versioned per post and correctly invalidated on new review submission and on admin approve/reject/delete (single or bulk) — previously those admin actions modified the DB directly without clearing any cache.
- Added: composite indexes
(post_id, status) and (user_id, status) on init_criteria_reviews to speed up the most common lookups on large sites.
- Improved:
init_plugin_suite_review_system_get_score_summary_by_post_id() now computes the overall average with SQL AVG() instead of summing every row in PHP.
- Improved: admin review list and the
/get-criteria-reviews REST endpoint now prime post/user object caches in bulk instead of calling get_post() / get_userdata() once per row.
1.18 – April 21, 2026
- Fixed
admin_init running database table checks on every admin page load
- Introduced
irs_plugin_db_version option flag to gate table checks behind a version comparison
- Table creation now only runs when stored DB version is lower than current plugin version
- Added
register_activation_hook to handle fresh installs and multisite network activation
- Added
wpmu_new_blog hook to provision tables automatically on new multisite subsite creation
- Added
upgrader_process_complete hook to reset version flag after plugin update, triggering re-check on next admin load
1.17 – March 25, 2026
- Added object cache (1 hour TTL) to
init_plugin_suite_review_system_get_score_summary_by_post_id()
- Added object cache (1 hour TTL) to
init_plugin_suite_review_system_has_user_reviewed()
- Added object cache (1 hour TTL) to
init_plugin_suite_review_system_get_user_reaction()
- Cache for
has_user_reviewed and get_user_reaction stores sentinel values to distinguish cache miss from negative results
- Cache invalidation for score summary and has-reviewed fires on
init_plugin_suite_review_system_after_insert action hook
- Cache invalidation for user reaction fires inside
init_plugin_suite_review_system_apply_user_reaction() after each write
1.16 – March 1, 2026
- Fixed Load More showing wrong user avatar and display name
- Fixed post-submit review rendering hardcoded HTML incompatible with custom templates
- Added
review-item.php as standalone overridable template
- Added
init_plugin_suite_review_system_get_criteria_by_post_id() helper
- Added
init_plugin_suite_review_system_get_review_by_id() helper
- REST endpoints now server-render review HTML; JS only injects, no longer builds DOM
- Removed unused
insertNewReview() JS function
1.15 – February 25, 2026
- Added
$per_page cap (max 100) in REST endpoint to prevent excessive data queries
- Added
init_plugin_suite_review_system_ttl filter (default 0) to opt-in object cache for review queries
- When TTL > 0, query results are cached via
wp_cache_set with group init_review_system
- Cache invalidation can be handled via
init_plugin_suite_review_system_after_insert action hook
1.14 – January 29, 2026
- Introduced Bayesian Weighted Rating for reliable ranking calculations
- New derived meta key
_init_review_weighted generated on vote submission
- Prevents low-sample bias (e.g. 1×5★ no longer outranks 1000×4.9★)
- Uses configurable minimum vote threshold via filter\
init_plugin_suite_review_system_min_votes_threshold
- Rating architecture improvements:
- Weighted score is calculated on-write (at REST endpoint), not at query time
- Establishes clear separation between raw data and ranking data
- Plugin now acts as the single source of truth for rating-based sorting
- Performance & stability:
- Global average rating is cached using transients for cross-environment reliability
- Automatic transient invalidation on new vote to prevent stale calculations
- Developer experience:
- Enhanced
init_plugin_suite_review_system_after_vote hook now passes:
- New average score
- Total vote count
- Weighted ranking score
- Fully backward compatible — no changes required for existing consumers
- No UI or frontend behavior changes
- No breaking changes to REST API responses
1.13 – January 19, 2026
- Added
.dark modifier for .init-reaction-bar to support Dark Mode
- Improved visual contrast for reactions in dark environments
- Polished hover, active and disabled states in Dark Mode
- Pure CSS enhancement, no JS or logic changes
1.12 – November 14, 2025
- Added anti–double-submit protection to the front-end rating widget
- New
isSubmitting state prevents rapid multi-clicks from firing multiple requests
- Fully compatible with both single-click and double-click confirmation modes
- Pending hover logic (
.hovering) remains intact with zero behavior changes
- Improved client-side stability:
- Ensures only one vote request is sent at a time
- Allows retrying when the API returns an error (non-blocking UX)
- No changes to REST API, server logic, or existing rating flow — fully backward compatible
1.11 – November 5, 2025
- Added User Review Fetching API
- New function
init_plugin_suite_review_system_get_reviews_by_user_id()
- Supports pagination (
paged, per_page) just like the post-based fetcher
- Automatically joins with
wp_posts to exclude orphaned reviews
- Returns unserialized
criteria_scores for direct UI rendering
- Added Total Pages Counter for User Reviews
- New function
init_plugin_suite_review_system_get_total_pages_by_user_id()
- Counts reviews belonging to a specific user (filtered by
status)
- Returns the total number of pages (minimum value:
1 for UX consistency)
- Performance and internal improvements:
- Consistent sanitization and safety (
absint(), max(), typed values)
- All SQL queries use
$wpdb->prepare() — no unbound parameters
- PHPCS/WPCS compliant and follows plugin prefix standard
1.10 – November 3, 2025
- Added Admin Reset & Manual Score Adjustment Metabox
- Visible only when a post already has rating data
- New UI: compact stat chips showing Avg / Votes / Total (premium-style mini cards)
- Supports manual override: admin can set Average (0–5) and Vote Count
- Internal logic auto-calculates
Total = Avg × Count (rounded to 2 decimals)
- All displayed values are fully escaped (
esc_html() / esc_attr()) following PHPCS
- Metabox is registered per-post, not globally — zero UI clutter
- Security and permissions:
- Only users with capability
edit_others_posts (Editor+) can view or interact with the metabox
save_post handler validates nonce + capability, protects against unauthorized POST submissions
- Input sanitized:
sanitize_text_field( wp_unslash() ) before casting to float/int
- UX improvements:
- No inline
<style> tags — every style moved to inline attribute (WordPress admin standard)
- Metabox does not appear at all until the first vote exists (no "empty" box)
1.9 – October 31, 2025
- Added Double-Click Confirmation Rating (anti-misclick mechanic)
- New setting:
Require double-click to rate
- When enabled, users must click the same star twice to confirm rating
- First click enters pending state, visually marked with
.hovering
- Second click submits rating and disables the block as usual
- JavaScript improvements:
- New pending handler with auto-timeout (2.2s) — no accidental lock state
.hovering class persists across mouseleave while pending
- Clean async state teardown ensures no ghost states
- No UI popups, no alerts — rating confirmation is purely action-based
- Zero breaking changes — existing rating logic untouched
1.8 – October 6, 2025
- Updated function
init_plugin_suite_review_system_get_reviews_by_post_id():
- When
$post_id = 0, orphaned reviews are now automatically excluded (posts that no longer exist across all CPTs).
- Shortcode
[init_review_criteria] enhanced:
- Added new attribute
paged to control review pagination.
- Internal call now passes
$paged dynamically to init_plugin_suite_review_system_get_reviews_by_post_id().
1.7 – September 13, 2025
- Added content moderation: banned words, banned phrases, no-whitespace, excessive repetition
- New settings: enable JS precheck (optional), manage banned words/phrases in textarea fields
- Improved modal UX: must rate all required criteria, inline error/success messages under submit button
- JavaScript updated: i18n error mapping, client-side prechecks, red outline highlight for missing scores
- CSS enhancements:
.init-review-inline-msg for messages, .init-review-criteria-error for criteria validation (with dark mode support)
1.6 – September 2, 2025
- Reactions endpoint
/reactions/toggle now requires login: enforced is_user_logged_in() and nonce validation
- Updated REST API registration:
permission_callback for /reactions/toggle now only allows logged-in users
- Shortcode
[init_reactions] updated: require_login is always true, ensuring consistent frontend behavior
- Improved JS logic:
- Removed guest/localStorage fallback (no more anonymous reactions)
- Preserved initial
disabled state for buttons; guest users always see counts but cannot interact
- Fixed bug where guest buttons could be re-enabled after API calls
- CSS adjustments: new
.is-disabled style keeps emoji + counts fully visible, while visually indicating login requirement
- Enhanced accessibility: reaction buttons now toggle
aria-pressed accurately and support is-active state for current user reaction
- Code cleanup: removed obsolete guest handling code paths and simplified state management
1.5 – September 1, 2025
- Enhanced Reactions System with total reactions counter displayed under “What do you think?”
- Added unique
id for total counter span (irs-total-reactions-{post_id}) to support JS live updates
- Updated JavaScript: total reaction count now updates instantly when users toggle reactions
- Synced UIkit theme template with total reactions output for consistent frontend display
- Added CSS styles for
.init-reaction-total (font weight, spacing, responsive display)
- Improved accessibility: total reactions wrapped with
aria-live="polite" for screen reader updates
- Minor code cleanups and consistency improvements
1.4 – August 31, 2025
- Introduced Reactions System: emoji-based reactions (👍 😄 😍 😯 😠 😢)
- Added shortcode + template for reactions bar
- Reactions stored in both post meta (counts) and dedicated
init_reactions table (user↔post map)
- Guest-friendly: works without login (tracked via localStorage)
- Added developer filters:
init_plugin_suite_review_system_get_reaction_types
init_plugin_suite_review_system_reaction_meta_key
- Internal refactor: extracted reaction-core functions, silent table creation with
dbDelta()
1.3 – August 25, 2025
- Restructured admin interface: moved from Settings submenu to dedicated main menu with star icon
- Added comprehensive review management system with bulk operations and filtering capabilities
- Implemented review approval workflow with pending/approved/rejected status management
- Enhanced admin dashboard with review statistics, search functionality, and pagination
- Added individual review actions: approve, reject, delete with proper nonce security
- Integrated bulk actions for managing multiple reviews simultaneously
- Created dedicated review management page with detailed review display and user information
- Improved database queries with proper prepared statements and PHPCS compliance
- Added admin-only review management scripts with proper enqueueing standards
- Refined plugin architecture for better scalability and maintainability
1.2 – July 27, 2025
- Standardized all output with
esc_html(), esc_attr(), and wp_kses() for frontend safety
- Secured REST API endpoint with enforced login + nonce validation for logged-in users
- Added
uninstall.php to clean up plugin options when uninstalled
- Refined UI labels and descriptions on settings page
- Improved shortcode documentation and attributes in
readme.txt
- Enhanced multi-criteria input layout for better clarity
1.1 – July 11, 2025
- Added support for multi-criteria reviews
- New shortcode for criteria-based score display
- Separate logic and schema handling for criteria reviews
- Improved review interface and modal UX
- Refactored code to support both single and multi-criteria review paths
1.0 – June 28, 2025
- Initial release
- Shortcode
[init_review_system] for 5-star voting block
- Shortcode
[init_review_score] for average score display
- REST API endpoint
/wp-json/initrsys/v1/vote with conditional login and nonce check
- Vote tracking via
localStorage for guest users
- Optional login restriction + strict IP check using hashed IP + transient
- JSON-LD schema output using
AggregateRating
- Auto-insert system: before/after post content or comment form
- Admin settings page with shortcode builder and control toggles
- Minimal, responsive, theme-inheriting design
- Developer-friendly: filters, actions, and reusable helpers