Description
EffortLess Simple Reviews Editor lets visitors submit reviews (pending admin approval) and displays published reviews in a responsive card grid with infinite scroll.
Features:
- Front-end review submission form with star rating, name, title, and review text fields
- Admin approval workflow — all submissions are set to “Pending”
- Responsive card grid with configurable columns
- Infinite scroll (IntersectionObserver) for seamless loading
- Spam protection: honeypot field + rate limiting (1 submission per 60 s)
- Accessible star rating with keyboard navigation
- One-time-use review links — send unique links to clients
- Programmatic link generation via
elsre_create_review_link() - No external dependencies — pure CSS stars, vanilla JavaScript
- i18n ready —
.pottranslation template included
Shortcodes
[elsre_reviews] — Display Reviews Grid
Place this shortcode on any page or post to display published reviews.
Attributes:
per_page(default:6) — Reviews per load batchcolumns(default:3) — Grid columns on desktop (1–6)ids(default: empty) — Comma-separated review IDs; disables paginationorder(default:desc) — Sort order:descfor newest first,ascfor oldest firststar_size(default:18px) — Star icon size (any CSS unit)text_size(default:15px) — Review text font sizename_size(default:14px) — Reviewer name font size
Examples:
[elsre_reviews]
[elsre_reviews per_page="9" columns="3"]
[elsre_reviews ids="12,45,78" columns="2"]
[elsre_reviews star_size="28px" text_size="18px" name_size="16px"]
[elsre_form] — Review Submission Form
Place this shortcode on any page or post to display the submission form.
Attributes:
require_token(default:no) — Set toyesto require a one-time-use link tokenstar_size(default:32px) — Star icon size in the rating picker
Examples:
[elsre_form]
[elsre_form require_token="yes"]
[elsre_form star_size="48px"]<h3>One-Time Review Links</h3>
1. Create a page with [elsre_form require_token="yes"].
2. Go to Reviews Review Links in the admin.
3. Click Generate Link (optionally add a label for your reference).
4. Copy the link and send it to your client.
Each link works only once. After the client submits their review, the link is marked as used.
Developer Integration
Generate review links programmatically from your own plugin or theme:
$link = elsre_create_review_link( 'client@example.com' );
$link = elsre_create_review_link( 'client@example.com', 'John Doe', 42 );
- First parameter: client email (unique identifier — reuses existing unused token if found)
- Second parameter: optional label for admin reference
- Third parameter: optional page ID containing
[elsre_form](auto-detected if omitted) - Returns the full URL with token, or empty string if no form page found
Check availability before calling: function_exists( 'elsre_create_review_link' )
Admin Pages
Reviews List (Dashboard Reviews)
All submitted reviews are listed here as a standard WordPress post list.
Extra columns show the key review data at a glance:
┌──────────────┬────────┬──────────────┬─────────────┬────────────┐
│ Title │ Rating │ Reviewer │ Date │ Status │
├──────────────┼────────┼──────────────┼─────────────┼────────────┤
│ Great hotel! │ ★★★★★ │ Jane Doe │ 2026-03-01 │ Pending │
│ Good service │ ★★★★☆ │ John Smith │ 2026-02-28 │ Published │
└──────────────┴────────┴──────────────┴─────────────┴────────────┘
Publish a review to make it appear on the front end. Leave it as Pending to
keep it hidden until you have reviewed it.
Review Edit Screen
Each review has a Review Details meta box below the title field:
┌─────────────────────────────────────────┐
│ REVIEW DETAILS │
├──────────────┬──────────────────────────┤
│ Reviewer Name│ Jane Doe │
│ Review Title │ Perfect weekend getaway! │
│ Rating │ ★ ★ ★ ★ ★ │
│ Review Text │ Fantastic experience... │
│ Review Date │ 2026-03-01 │
└──────────────┴──────────────────────────┘
The star picker is fully keyboard-accessible (arrow keys, Enter, Space).
Review Links Page (Dashboard Reviews Review Links)
Generate one-time-use links to send to specific clients:
┌──────────────────────────────────────────────────────────────┐
│ GENERATE NEW LINK │
│ Client Email [client@example.com ] │
│ Label [e.g. John's booking ] (optional) │
│ Form Page [Leave a Review ▾ ] │
│ [ Generate Link ] │
└──────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────────┐
│ ALL LINKS │
├──────────────┬───────────┬────────┬────────────┬────────┬───────────┤
│ Email │ Label │ Status │ Created │ Used │ Actions │
├──────────────┼───────────┼────────┼────────────┼────────┼───────────┤
│ jane@... │ Jane Doe │ Active │ 2026-03-01 │ — │ Copy Link │
│ john@... │ John Smith│ Used │ 2026-02-28 │ Mar 01 │ Expired │
└──────────────┴───────────┴────────┴────────────┴────────┴───────────┘
After generating, a success banner shows the link ready to copy:
┌─────────────────────────────────────────────────────────────┐
│ ✓ Link generated! Send this link to your client: │
│ https://example.com/review/?elsre_token=abc123 [ Copy ] │
└─────────────────────────────────────────────────────────────┘
Installation
- Upload the
effortless-simple-reviews-editorfolder to/wp-content/plugins/. - Activate the plugin through the Plugins menu in WordPress.
- A new Reviews menu (star icon) appears in the admin sidebar.
- Add
[elsre_reviews]to a page to display reviews. - Add
[elsre_form]to a page to allow visitors to submit reviews. - For one-time links: use
[elsre_form require_token="yes"], then generate links via Reviews Review Links.
FAQ
-
Where do submitted reviews go?
-
All submissions are saved with “Pending” status. Go to Reviews in the admin to approve them.
-
Can I display specific reviews only?
-
Yes, use the
idsattribute:[elsre_reviews ids="12,45,78"] -
How do I translate the plugin?
-
Copy
languages/elsre.pottolanguages/elsre-{locale}.po(e.g.elsre-fr_FR.po), translate, then compile to.mo.
Reviews
There are no reviews for this plugin.
Contributors & Developers
“EffortLess Simple Reviews Editor” is open source software. The following people have contributed to this plugin.
ContributorsTranslate “EffortLess Simple Reviews Editor” into your language.
Interested in development?
Browse the code, check out the SVN repository, or subscribe to the development log by RSS.
Changelog
2.2.3
- Security: added the
elsre_require_tokenfilter so sites can enforce invitation-only reviews server-side — when it returns true, tokenless submissions toadmin-ajax.phpare rejected (therequire_token="yes"shortcode attribute only hid the form in the browser). - Fix:
elsre_create_review_link()now keeps a reused token’s storedpage_idin sync with the link it builds, matching the admin Generate Link flow. - Code: token rollback after a failed insert is now guarded so it only runs for token-based submissions; shared review-query and ID-parsing logic extracted to
ELSRE_Shortcodeshelpers; flash-notice transients read via a singleconsume_transient()helper.
2.2.2
- Code: removed
plugins_apifilter and associatedplugin_row_meta“View details” link — WordPress.org hosting serves plugin information natively; the local interceptor was flagged as an unauthorized update/phone-home mechanism.
2.2.1
- Security: all table-name SQL references migrated from
esc_sql()+ backtick interpolation to the%iidentifier placeholder (WordPress 6.2+). - Security:
count_tokens()now wraps$wpdb->get_var()inprepare()instead of passing a raw SQL string. - UX: invalid email on the Generate Link form now shows an admin error notice instead of silently ignoring the input.
- Fix:
uninstall.phpnow also removeselsre_error_*transients created by the email validation notice.
2.2.0
- Fix: token is now restored (un-consumed) when
wp_insert_post()fails after atomic consume, so the review link remains valid and the client can retry. - Fix:
uninstall.phpnow also removes_transient_timeout_records forelsre_generated_,elsre_deleted_, andelsre_form_pagestransients, preventing orphan rows inwp_options. - Performance:
get_form_pages()result is now cached for one hour via transient (invalidated onsave_post/delete_post). - Performance: Review Links admin page now paginates token rows (50 per page) instead of loading all rows at once.
- Code:
render_admin_columns()switch now has an explicitdefaultbranch. - Code:
render_form()passes the template variable viaextract()to match theload_card_template()pattern. - Security: removed the descriptive
<!-- Honeypot field -->HTML comment from the front-end form.
2.1.9
- Fix:
post_titleauto-generation now only runs for new posts or posts with an empty/Auto Draft title — existing reviews with a manually set title are never overwritten.
2.1.8
- UX: removed the native “Add title” input from the review edit screen —
post_titleis now auto-generated from “Reviewer Name – Review Title” and remains visible in the admin list table.
2.1.7
- UX: admin “Review Details” meta box fields reordered to match the front-end form: Rating Reviewer Name Review Title Review Text Review Date.
- Fix:
maxlength="100"added to Reviewer Name input in admin meta box. - Fix:
maxlength="1000"added to Review Text textarea in admin meta box. - Security: server-side
mb_strlen/mb_substrguards added for reviewer name (100 chars) and review text (1000 chars) insave_meta().
2.1.6
- Code: removed
load_plugin_textdomain()call — WordPress 4.6+ loads translations automatically; the explicit call triggered a PluginCheck warning. - Code:
$tokenvariable inreview-form.phptemplate renamed to$elsre_tokento satisfy WordPress global variable prefix requirement.
2.1.5
- Security: token now consumed before the review post is inserted — eliminates race window that allowed token reuse on server crash.
- Security: REST API read access restricted to users with
edit_postscapability viaELSRE_REST_Controller— review content (including pending) is no longer publicly readable via the REST API. - Security: token delete action changed from a GET link to a POST form, preventing accidental deletion by browser prefetch or link scanners.
- Security:
handle_admin_actions()now checkscurrent_user_can()before reading any request parameters. - Fix: admin meta box now reads
post_contentfirst (authoritative) and falls back to_elsre_review_textmeta, matching the documented architecture and preventing translated content from being overwritten on save. - Fix:
load_plugin_textdomain()added toelsre_init()so translations load correctly on self-hosted installs. - Fix:
response.datanull guard added on JS success path to prevent TypeError when server returns{success:true, data:null}. - Fix: success message receives focus after form submission so keyboard and screen-reader users are not left on the hidden form.
- Fix:
submit_button()no longer receives a pre-escaped label — prevented double-escaping of special characters. - Code:
ms_gpt_translatable_post_typesfilter converted to a named function so third parties can callremove_filter(). - Code:
uninstall.phpDROP TABLEuses%iidentifier placeholder (WordPress 6.2+) instead ofesc_sql()workaround. - CSS:
prefers-reduced-motionmedia query added — disables spinner animation and CSS transitions for users who prefer reduced motion.
2.1.4
- Feature: live character counter on Name, Title, and Review fields — green while typing, orange within 5% of the limit, red at the limit. Counter is hidden until the user starts typing. Accessible via
aria-liveandaria-describedby.
2.1.3
- Fix:
uninstall.php—DROP TABLEquery now usesesc_sql()inline instead of a$tablevariable, resolving PluginCheckDirectDB.UnescapedDBParameterwarning.
2.1.2
- Fix:
uninstall.php— tokens tableDROPquery now guarded by apreg_match()pattern check on the table name, resolving PluginCheckDirectDB.UnescapedDBParameterwarning.
2.1.1
- Fix: assets and script data (
elsreData) now enqueued duringwp_enqueue_scriptsinstead of inside the shortcode render — prevents “elsreData is not defined” JS errors caused by caching and script-optimisation plugins (LiteSpeed, WP Rocket, Autoptimize, etc.). - Fix: form hidden on successful submission instead of calling
form.reset()— resolves permanently disabled submit button on Safari/WebKit after token-based submissions. - Fix: XHR handlers now cover all failure paths (onerror, ontimeout, onabort) with a 30-second timeout, so the submit button is always re-enabled even if the server does not respond.
2.1.0
- Feature: review title field added to the submission form, review cards, and admin meta box.
- Change: review text maximum length reduced from 2000 to 1000 characters.
- Change: submission form field order is now Rating Name Title Review.
2.0.1
- Code: PHPCS/WPCS zero errors, zero warnings. Alignment fixes auto-corrected by phpcbf. Rephrased doc comment to satisfy capitalisation rule. Removed unused
$blog_idparameter fromelsre_uninstall_site(). AddedPreparedSQLignore annotation for the dynamic-placeholder query inget_form_pages().
2.0.0
- Security: REST API meta fields now require
edit_postscapability viaauth_callback— previously any authenticated user could read review meta via the REST API. - Security:
get_client_ip()now defaults toREMOTE_ADDRonly. Proxy header trust (X-Forwarded-For/X-Real-IP) requires explicit opt-in via theelsre_trust_proxy_headersfilter to prevent rate-limit bypass on sites not behind a reverse proxy. - Security:
inject_post_content_before_save()now checkscurrent_user_can()in addition to nonce verification before modifyingpost_content. - Fix: double-escaping of translatable submit button label —
esc_attr__()replaced with__()to prevent corrupted output for translations containing apostrophes (e.g. French). - Fix:
uninstall.phpnow loops over all sites on multisite network installs, cleaning up posts, transients, tokens table, and options for each site. - Fix: token reuse now updates the stored
page_idwhen the admin selects a different form page, keeping the token record consistent with the generated URL. - Fix:
wp_create_nonce()is now called only when a shortcode is actually rendered on a page, not on every front-end page load. - Fix: copy-to-clipboard button now only shows “Copied!” when the clipboard write actually succeeded.
- Code:
load_card_template()usesextract()with an explicit named array instead of relying on PHP variable scope inheritance acrossinclude. - Code:
render_admin_columns()now appliesesc_attr()to inline star color values (WPCS compliance). - New:
elsre_form_page_post_typesfilter — allows custom post types to appear in the form page dropdown (useful for page-builder custom post types). - New:
elsre_trust_proxy_headersfilter — opt-in to readingX-Forwarded-For/X-Real-IPon sites behind a trusted reverse proxy.
1.9.5
- Fix: esc_sql() applied to table variable before interpolation in consume_token() query.
1.9.4
- Fix: JS — response.data null-guard added before accessing response.data.html in infinite scroll callback.
- Fix: JS — IntersectionObserver callback now checks entries.length before accessing entries[0].
- Fix: JS — hardcoded ‘Submit Review’ fallback replaced with translatable elsreData.i18n.submit (added to wp_localize_script).
- Fix: Accessibility — individual star spans in review-card.php now have aria-hidden=”true”; the parent div already carries the full aria-label.
- Fix: readme.txt — stale version number 1.4.4 updated in plugin ASCII art example.
1.9.3
- Code: PHPCS/WPCS — zero errors, zero warnings. Fixed short ternary operator (replaced ?: with explicit if/else), added missing docblock short description, fixed indentation in review-card.php template. Added extensions and exclude-pattern to phpcs.xml to scope checks to PHP only.
1.9.2
- Fix: SQL table names now consistently wrapped in backticks across all queries in class-elsre-tokens.php and uninstall.php.
- Fix: strtotime() return value now validated before passing to wp_date() — prevents current date/time showing for reviews with missing or malformed date meta.
- Fix: missing esc_attr() on CSS class output in review-card.php (WPCS compliance).
- Fix: replaced printf(esc_html__(…), ‘
') pattern with echo wp_kses_post(sprintf(__(...))) — correct approach for substituting HTML into translatable strings. - Fix: added PHP 8.0 union type hint false|object on the $api parameter of elsre_plugins_api_info().
1.9.1
- Fix: blank “Add New Review” screen in WordPress 6.9+ —
replace_editorfilter returningtruecaused WP 6.9 to skip the entire edit form, showing only the admin footer. Replaced with CSS-based editor suppression (.post-type-elsre_review #postdivrichetc.). - Fix: added
use_block_editor_for_postfilter alongsideuse_block_editor_for_post_typefor belt-and-suspenders block editor disabling. - New: plugin details modal — “View details” link on the Plugins page showing description, shortcode docs, installation guide, and changelog.
1.9.0
- Fix: editor suppression switched from
user_can_richeditfilter toreplace_editorfilter for WordPress 6.x compatibility.
1.8.3
- Fix: removed
postcustommeta box (Custom Fields) from review edit screen to keep the admin UI clean.
1.8.2
- Fix: translation reverting to source — meta fallback in inject_post_content_before_save now only fires when post_content is genuinely empty, never when translated content is already present.
- Fix: TinyMCE no longer appears on review edit screen (user_can_richedit filter).
1.8.1
- Fix: restored plain-textarea UI for review text (no TinyMCE, no image uploads). Native content editor hidden via remove_meta_box() while editor stays in CPT supports.
- Fix: removed sync_content_from_meta — its wp_update_post() fired a second save_post which triggered the translator twice, causing random translation results.
- inject_post_content_before_save is the single reliable sync point.
1.8.0
- Fix:
editoradded to CPT supports — translation plugins check post_type_supports before including post_content in jobs. Without it, post_content was silently skipped. Review text now translates correctly. - Block editor disabled for review posts; classic editor used. The content area holds the review text directly, like a standard post.
- Removed “Review Text” textarea from the structured meta box — it is now the native content field. Reviewer name, rating, and date remain in the meta box.
- Removed inject_post_content_before_save and sync_content_from_meta hooks — no longer needed with native editor support.
- Backward compat: card template still falls back to _elsre_review_text meta for reviews created before 1.8.0.
1.7.1
- Security: token consumption is now atomic (UPDATE WHERE is_used = 0) — prevents race condition where two simultaneous requests with the same token could both succeed.
- Security: REST API requests excluded from post_content restore hooks — translation plugins updating via REST no longer risk source-language overwrite.
- Security: server-side max-length validation added for reviewer name (100 chars) and review text (2000 chars).
- Security: REMOTE_ADDR validated as IP before use in rate limiting.
- Fix: uninstall.php now cleans up admin-notice transients.
1.7.0
- Requires PHP 8.0+ and WordPress 6.9+.
- PHP 8.0 type hints added to all methods and global functions.
matchexpressions replace if/else chains in token validation, AJAX order parsing, and error messages.wp_date()replacesdate_i18n()throughout.- Removed all
phpcs:ignore NonceVerificationsuppressions: nonce verified directly ininject_post_content_before_save(); programmatic saves detected via$_SERVER['REQUEST_METHOD']; admin notices use per-user transients instead of unverified$_GETparams. - Template variables renamed with
elsre_prefix — removes allphpcs:ignore NonPrefixedVariableFoundsuppressions.
1.6.3
- Fix: Plugin URI updated from example.com to domclic.com.
- Fix: removed deprecated load_plugin_textdomain() call.
- Fix: esc_sql() applied to table name in get_all_tokens().
- Fix: phpcs ignore on loop variable $i and $submit_label in templates.
1.6.2
- i18n: text domain changed from
elsretoeffortless-simple-reviews-editoracross all PHP files to match WordPress.org convention.
1.6.1
- Fix: infinite re-translation loop with multisite translation plugins —
inject_post_content_before_saveandsync_content_from_metanow skip programmatic saves (no$_POST) so translatedpost_contenton destination sites is never overwritten with source-language meta.
1.6.0
- Code: full PHPCS/WPCS compliance — zero errors, zero warnings.
- Fix: Yoda conditions in
validate_token()and token list rendering. - Fix: renamed
$posts/$post_idinuninstall.phpto avoid overriding WordPress globals. - Fix: suppressed false-positive nonce warnings on read-only redirect params.
- Fix: alignment and whitespace issues auto-corrected by phpcbf.
1.5.9
- Fix:
$id_arrayundefined variable notice when[elsre_reviews]is used without theidsattribute. - Fix: replaced
gmdate()+strtotime()withdate_i18n()— dates now respect WordPress timezone and locale. - Fix: rate limiting skips gracefully when client IP cannot be determined instead of hashing an empty string.
- Fix: AJAX
per_pagecapped at 100;pagecapped at 1000 to prevent DB abuse. - Fix: deprecated
bigint(20)syntax replaced withBIGINT UNSIGNEDin token table (DB version 1.2). - Fix: front-end form now has
method="post"for valid HTML.
1.5.8
- Compatibility: hooks
ms_gpt_translatable_post_typesfilter so EffortLess Multisite Auto Translate picks up the non-publicelsre_reviewCPT and syncs reviews across sites.
1.5.7
- Fix: PHP Notice “post type elsre_review is not registered” on REST API capability checks —
register_meta_fields()now hooks toinitat priority 11, afterregister_post_type()at priority 10.
1.5.6
- REST API support enabled on the
elsre_reviewpost type. - All custom meta fields registered with
show_in_rest: truefor REST-based translation plugins. - Added
custom-fieldsto CPT supports.
1.5.5
- Fix: multisite translation plugins were receiving empty
post_contentbecause our sync hook ran after the translation plugin’ssave_posthook. - New
wp_insert_post_datafilter injects review text intopost_contentbefore the database write, so translation plugins always sync the correct content.
1.5.4
- Fix:
$tokens_handlervariable scope bug insubmit_review()— was potentially undefined at token consumption. - Fix:
wp_insert_post()zero-return now treated as failure (not justWP_Error). - Fix: removed
$wpdb->prepare()with no placeholders inget_all_tokens(). - Security: CSS size attributes on shortcodes now validated against a unit whitelist.
1.5.3
- Fix: infinite recursion — removed
wp_update_post()fromsave_meta(). - Fix: WordPress was clearing
post_contenton every admin save (CPT without editor).sync_content_from_meta()now correctly restores it. - Replaced remove/re-add hook pattern with a static
$syncingflag.
1.5.2
- Fix: quick edit and bulk edit now correctly sync
post_contentfrom_elsre_review_textmeta. - Infinite-loop guard on the sync hook.
1.5.1
- Translation compatibility: review text now stored in
post_contentso multisite translators and translation plugins handle it natively. - Card display reads from
post_contentfirst, falls back to meta for reviews created before this version. - Admin meta box keeps
post_contentin sync when review text is edited.
1.5.0
- New
orderattribute on[elsre_reviews]:order="desc"(newest first, default) ororder="asc"(oldest first). - Sort order preserved across infinite scroll loads.
1.4.4
- Security: replaced MD5 with SHA-256 for rate-limit IP hashing.
- Security: proxy-aware IP detection — reads
X-Forwarded-For/X-Real-IPheaders with validation before falling back toREMOTE_ADDR. - Security: moved inline
onclickconfirm on delete links toaddEventListenerin JS. - Security: nonce verified before processing delete action; added
token_idguard. - Security: validate generated page ID exists before issuing a token.
- Code:
get_all_tokens()SQL query now uses$wpdb->prepare(). - Code: date validation uses
DateTime::createFromFormat()for strict round-trip check. - Code:
ELSRE_Shortcodes::load_card_template()is now static — no extra class instantiation in AJAX handler.
1.4.3
- Plugin renamed to EffortLess Simple Reviews Editor to match the
ELSRE_prefix convention.
1.4.2
- i18n ready:
load_plugin_textdomain()and.pottemplate file for translations.
1.4.1
- Review title now displayed in the card (between stars and review text).
1.4.0
- Customizable sizes:
star_size,text_size,name_sizeattributes on[elsre_reviews]. - Customizable star size on
[elsre_form]viastar_sizeattribute. - Sizes powered by CSS custom properties for easy theming.
1.3.0
- Client email is now the unique identifier for review links.
- If an unused link exists for the same email, it is reused (no duplicates).
- Email column added to the tokens table and admin Review Links page.
elsre_create_review_link()first parameter is now$email.
1.2.0
- New
elsre_create_review_link()PHP function for programmatic link generation. - Use it from your own plugin to automatically include a review link in emails.
1.1.0
- One-time-use review links: generate unique links for clients via Reviews Review Links.
- New
require_tokenattribute on[elsre_form]shortcode. - Admin page to generate, copy, and manage review links.
- Token consumed after submission — link can only be used once.
1.0.0
- Initial release.
- Custom post type for reviews with admin meta boxes.
[elsre_reviews]shortcode with infinite scroll and responsive grid.[elsre_form]shortcode with AJAX submission, honeypot, and rate limiting.