EffortLess Simple Reviews Editor

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 — .pot translation 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 batch
  • columns (default: 3) — Grid columns on desktop (1–6)
  • ids (default: empty) — Comma-separated review IDs; disables pagination
  • order (default: desc) — Sort order: desc for newest first, asc for oldest first
  • star_size (default: 18px) — Star icon size (any CSS unit)
  • text_size (default: 15px) — Review text font size
  • name_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 to yes to require a one-time-use link token
  • star_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

  1. Upload the effortless-simple-reviews-editor folder to /wp-content/plugins/.
  2. Activate the plugin through the Plugins menu in WordPress.
  3. A new Reviews menu (star icon) appears in the admin sidebar.
  4. Add [elsre_reviews] to a page to display reviews.
  5. Add [elsre_form] to a page to allow visitors to submit reviews.
  6. 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 ids attribute: [elsre_reviews ids="12,45,78"]

How do I translate the plugin?

Copy languages/elsre.pot to languages/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.

Contributors

Changelog

2.2.3

  • Security: added the elsre_require_token filter so sites can enforce invitation-only reviews server-side — when it returns true, tokenless submissions to admin-ajax.php are rejected (the require_token="yes" shortcode attribute only hid the form in the browser).
  • Fix: elsre_create_review_link() now keeps a reused token’s stored page_id in 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_Shortcodes helpers; flash-notice transients read via a single consume_transient() helper.

2.2.2

  • Code: removed plugins_api filter and associated plugin_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 %i identifier placeholder (WordPress 6.2+).
  • Security: count_tokens() now wraps $wpdb->get_var() in prepare() 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.php now also removes elsre_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.php now also removes _transient_timeout_ records for elsre_generated_, elsre_deleted_, and elsre_form_pages transients, preventing orphan rows in wp_options.
  • Performance: get_form_pages() result is now cached for one hour via transient (invalidated on save_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 explicit default branch.
  • Code: render_form() passes the template variable via extract() to match the load_card_template() pattern.
  • Security: removed the descriptive <!-- Honeypot field --> HTML comment from the front-end form.

2.1.9

  • Fix: post_title auto-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_title is 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_substr guards added for reviewer name (100 chars) and review text (1000 chars) in save_meta().

2.1.6

  • Code: removed load_plugin_textdomain() call — WordPress 4.6+ loads translations automatically; the explicit call triggered a PluginCheck warning.
  • Code: $token variable in review-form.php template renamed to $elsre_token to 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_posts capability via ELSRE_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 checks current_user_can() before reading any request parameters.
  • Fix: admin meta box now reads post_content first (authoritative) and falls back to _elsre_review_text meta, matching the documented architecture and preventing translated content from being overwritten on save.
  • Fix: load_plugin_textdomain() added to elsre_init() so translations load correctly on self-hosted installs.
  • Fix: response.data null 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_types filter converted to a named function so third parties can call remove_filter().
  • Code: uninstall.php DROP TABLE uses %i identifier placeholder (WordPress 6.2+) instead of esc_sql() workaround.
  • CSS: prefers-reduced-motion media 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-live and aria-describedby.

2.1.3

  • Fix: uninstall.phpDROP TABLE query now uses esc_sql() inline instead of a $table variable, resolving PluginCheck DirectDB.UnescapedDBParameter warning.

2.1.2

  • Fix: uninstall.php — tokens table DROP query now guarded by a preg_match() pattern check on the table name, resolving PluginCheck DirectDB.UnescapedDBParameter warning.

2.1.1

  • Fix: assets and script data (elsreData) now enqueued during wp_enqueue_scripts instead 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_id parameter from elsre_uninstall_site(). Added PreparedSQL ignore annotation for the dynamic-placeholder query in get_form_pages().

2.0.0

  • Security: REST API meta fields now require edit_posts capability via auth_callback — previously any authenticated user could read review meta via the REST API.
  • Security: get_client_ip() now defaults to REMOTE_ADDR only. Proxy header trust (X-Forwarded-For / X-Real-IP) requires explicit opt-in via the elsre_trust_proxy_headers filter to prevent rate-limit bypass on sites not behind a reverse proxy.
  • Security: inject_post_content_before_save() now checks current_user_can() in addition to nonce verification before modifying post_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.php now 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_id when 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() uses extract() with an explicit named array instead of relying on PHP variable scope inheritance across include.
  • Code: render_admin_columns() now applies esc_attr() to inline star color values (WPCS compliance).
  • New: elsre_form_page_post_types filter — allows custom post types to appear in the form page dropdown (useful for page-builder custom post types).
  • New: elsre_trust_proxy_headers filter — opt-in to reading X-Forwarded-For / X-Real-IP on 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_editor filter returning true caused WP 6.9 to skip the entire edit form, showing only the admin footer. Replaced with CSS-based editor suppression (.post-type-elsre_review #postdivrich etc.).
  • Fix: added use_block_editor_for_post filter alongside use_block_editor_for_post_type for 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_richedit filter to replace_editor filter for WordPress 6.x compatibility.

1.8.3

  • Fix: removed postcustom meta 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: editor added 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.
  • match expressions replace if/else chains in token validation, AJAX order parsing, and error messages.
  • wp_date() replaces date_i18n() throughout.
  • Removed all phpcs:ignore NonceVerification suppressions: nonce verified directly in inject_post_content_before_save(); programmatic saves detected via $_SERVER['REQUEST_METHOD']; admin notices use per-user transients instead of unverified $_GET params.
  • Template variables renamed with elsre_ prefix — removes all phpcs:ignore NonPrefixedVariableFound suppressions.

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 elsre to effortless-simple-reviews-editor across all PHP files to match WordPress.org convention.

1.6.1

  • Fix: infinite re-translation loop with multisite translation plugins — inject_post_content_before_save and sync_content_from_meta now skip programmatic saves (no $_POST) so translated post_content on 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_id in uninstall.php to 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_array undefined variable notice when [elsre_reviews] is used without the ids attribute.
  • Fix: replaced gmdate()+strtotime() with date_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_page capped at 100; page capped at 1000 to prevent DB abuse.
  • Fix: deprecated bigint(20) syntax replaced with BIGINT UNSIGNED in 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_types filter so EffortLess Multisite Auto Translate picks up the non-public elsre_review CPT 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 to init at priority 11, after register_post_type() at priority 10.

1.5.6

  • REST API support enabled on the elsre_review post type.
  • All custom meta fields registered with show_in_rest: true for REST-based translation plugins.
  • Added custom-fields to CPT supports.

1.5.5

  • Fix: multisite translation plugins were receiving empty post_content because our sync hook ran after the translation plugin’s save_post hook.
  • New wp_insert_post_data filter injects review text into post_content before the database write, so translation plugins always sync the correct content.

1.5.4

  • Fix: $tokens_handler variable scope bug in submit_review() — was potentially undefined at token consumption.
  • Fix: wp_insert_post() zero-return now treated as failure (not just WP_Error).
  • Fix: removed $wpdb->prepare() with no placeholders in get_all_tokens().
  • Security: CSS size attributes on shortcodes now validated against a unit whitelist.

1.5.3

  • Fix: infinite recursion — removed wp_update_post() from save_meta().
  • Fix: WordPress was clearing post_content on every admin save (CPT without editor). sync_content_from_meta() now correctly restores it.
  • Replaced remove/re-add hook pattern with a static $syncing flag.

1.5.2

  • Fix: quick edit and bulk edit now correctly sync post_content from _elsre_review_text meta.
  • Infinite-loop guard on the sync hook.

1.5.1

  • Translation compatibility: review text now stored in post_content so multisite translators and translation plugins handle it natively.
  • Card display reads from post_content first, falls back to meta for reviews created before this version.
  • Admin meta box keeps post_content in sync when review text is edited.

1.5.0

  • New order attribute on [elsre_reviews]: order="desc" (newest first, default) or order="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-IP headers with validation before falling back to REMOTE_ADDR.
  • Security: moved inline onclick confirm on delete links to addEventListener in JS.
  • Security: nonce verified before processing delete action; added token_id guard.
  • 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 .pot template 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_size attributes on [elsre_reviews].
  • Customizable star size on [elsre_form] via star_size attribute.
  • 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_token attribute 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.