{"id":323448,"date":"2026-06-10T13:47:18","date_gmt":"2026-06-10T13:47:18","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/tuft-feedback\/"},"modified":"2026-06-10T14:36:42","modified_gmt":"2026-06-10T14:36:42","slug":"tuft-feedback","status":"publish","type":"plugin","link":"https:\/\/wordpress.org\/plugins\/tuft-feedback\/","author":7045072,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.2.1","stable_tag":"1.2.1","tested":"7.0","requires":"6.0","requires_php":"7.4","requires_plugins":null,"header_name":"Tuft Feedback","header_author":"George Stephanis","header_description":"Soft on clients. Sharp on the details. Visual feedback with click-to-annotate and screenshots.","assets_banners_color":"fdf8f4","last_updated":"2026-06-10 14:36:42","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"","header_author_uri":"https:\/\/github.com\/georgestephanis","rating":0,"author_block_rating":0,"active_installs":0,"downloads":47,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.2.0":{"tag":"1.2.0","author":"georgestephanis","date":"2026-06-10 14:08:56"},"1.2.1":{"tag":"1.2.1","author":"georgestephanis","date":"2026-06-10 14:36:42"}},"upgrade_notice":{"1.2.0":"<p>Security hardening: the REST submission endpoint now enforces the widget visibility setting. No database changes; existing submissions are unaffected.<\/p>","1.1.0":"<p>Adds canvas drawing, visibility controls, rate limiting, and built-in email\/webhook notifications. No database changes; existing submissions are unaffected.<\/p>","1.0.0":"<p>Initial release. No upgrade steps required.<\/p>"},"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3567641,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3567641,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3567641,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3567641,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.2.0","1.2.1"],"block_files":[],"assets_screenshots":[],"screenshots":{"1":"The Tuft FAB button (~2\/3 down the right edge of a frontend page).","2":"Targeting mode \u2014 page dims, crosshair cursor, hovered element highlighted.","3":"The feedback modal after selecting an element, showing the annotated screenshot canvas and drawing toolbar.","4":"The Tuft admin list table with screenshot thumbnails.","5":"The full detail view for a single submission, including screenshot, selector, coordinates, and submitter info.","6":"The Settings \u2192 Tuft Feedback page with visibility controls, rate limiting, and notification options."}},"plugin_section":[],"plugin_tags":[15354,156887,4072,108,63174],"plugin_category":[42],"plugin_contributors":[77528],"plugin_business_model":[],"class_list":["post-323448","plugin","type-plugin","status-publish","hentry","plugin_tags-annotations","plugin_tags-client-review","plugin_tags-design","plugin_tags-feedback","plugin_tags-visual-feedback","plugin_category-contact-forms","plugin_contributors-georgestephanis","plugin_committers-georgestephanis"],"banners":{"banner":"https:\/\/ps.w.org\/tuft-feedback\/assets\/banner-772x250.png?rev=3567641","banner_2x":"https:\/\/ps.w.org\/tuft-feedback\/assets\/banner-1544x500.png?rev=3567641","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/tuft-feedback\/assets\/icon-128x128.png?rev=3567641","icon_2x":"https:\/\/ps.w.org\/tuft-feedback\/assets\/icon-256x256.png?rev=3567641","generated":false},"screenshots":[],"raw_content":"<!--section=description-->\n<p>Tuft adds a floating button to every page on your site. When clicked, it enters a targeting mode that lets the visitor click any element on the page to annotate it. The plugin captures the DOM selector, click coordinates, viewport dimensions, form field state, and an in-browser screenshot, then presents a drawing toolbar so the reviewer can mark up the screenshot before typing their feedback. Everything is stored locally as a custom post type for admin review.<\/p>\n\n<h4>Key features<\/h4>\n\n<ul>\n<li><strong>Click-to-annotate<\/strong> \u2014 click the \"Feedback\" button then click any element. The hovered element highlights so you know exactly what you're selecting.<\/li>\n<li><strong>In-browser screenshots<\/strong> \u2014 uses html2canvas (bundled with the plugin, no CDN dependency) to capture the visible viewport at the moment of submission.<\/li>\n<li><strong>Freehand canvas annotation<\/strong> \u2014 a drawing toolbar below the screenshot preview lets reviewers draw freehand strokes or rectangles, undo the last stroke, or clear all marks. Annotations are baked into the submitted JPEG on the client.<\/li>\n<li><strong>Context capture<\/strong> \u2014 records the CSS selector, viewport-relative click coordinates, viewport dimensions, and any visible form field values (passwords excluded).<\/li>\n<li><strong>Feedback modal<\/strong> \u2014 clean overlay collects the visitor's feedback text alongside the annotated screenshot. Logged-in users are not prompted for name or email \u2014 their WordPress account details are used automatically. Guest visitors see name and email fields.<\/li>\n<li><strong>Widget visibility controls<\/strong> \u2014 choose who sees the feedback button: everyone (including logged-out visitors), logged-in users only, editors and above, or administrators only. Configured under <strong>Settings \u2192 Tuft Feedback<\/strong>.<\/li>\n<li><strong>Submission rate limiting<\/strong> \u2014 cap submissions per IP address per hour to protect against spam. Set to 0 to disable. Tracked via post meta queries.<\/li>\n<li><strong>Built-in notifications<\/strong> \u2014 email a comma-separated list of addresses and\/or POST a JSON payload to any number of webhook URLs on every submission. Works with Slack incoming webhooks, Discord, Teams, Zapier, Make, and any HTTP endpoint.<\/li>\n<li><strong>Local storage<\/strong> \u2014 submissions saved as a <code>tuft_feedback<\/code> custom post type with full metadata and a screenshot attachment.<\/li>\n<li><strong>Admin review<\/strong> \u2014 list table with columns for feedback text, source page, element selector, submitter, and screenshot thumbnail. Full detail view with screenshot in the post editor.<\/li>\n<li><strong>Alpaca Issue Tracker integration<\/strong> \u2014 if <a href=\"https:\/\/wordpress.org\/plugins\/alpaca-issue-tracker\/\">Alpaca Issue Tracker<\/a> is installed, each submission is automatically mirrored as a Kanban issue on the Alpaca board. The Tuft admin menu moves under the Alpaca Project Board menu.<\/li>\n<\/ul>\n\n<h4>Intended use<\/h4>\n\n<p>This plugin is designed for <strong>local development and staging environments<\/strong> where you want clients or team members to leave visual design notes without logging in to a project management tool. The widget visibility setting under <strong>Settings \u2192 Tuft Feedback<\/strong> controls who sees the button; the REST endpoint that receives submissions is open by default \u2014 review the security notes before deploying to a publicly accessible production site.<\/p>\n\n<h4>Alpaca Issue Tracker integration<\/h4>\n\n<p>When <a href=\"https:\/\/wordpress.org\/plugins\/alpaca-issue-tracker\/\">Alpaca Issue Tracker<\/a> is active alongside Tuft:<\/p>\n\n<ul>\n<li>Each submission creates a matching <code>alpaca_issue<\/code> in your board's default (lowest-score) column.<\/li>\n<li>Issues are tagged with the submitter's browser and the type \"Tuft\" for easy filtering.<\/li>\n<li>The Tuft admin menu moves under the <strong>Project Board<\/strong> submenu, so the Alpaca board becomes the primary triage interface.<\/li>\n<li>Click any row in the Tuft list to open the full detail view including the annotated screenshot.<\/li>\n<\/ul>\n\n<!--section=installation-->\n<ol>\n<li>Upload the <code>tuft-feedback<\/code> folder to <code>wp-content\/plugins\/<\/code>.<\/li>\n<li>Activate <strong>Tuft<\/strong> through the <strong>Plugins<\/strong> menu in WordPress.<\/li>\n<li>Visit any frontend page \u2014 the Tuft FAB button appears ~2\/3 down the right edge of the screen.<\/li>\n<li>Configure who sees the button, rate limiting, and notification emails\/webhooks under <strong>Settings \u2192 Tuft Feedback<\/strong>.<\/li>\n<li>Optionally install and activate <strong>Alpaca Issue Tracker<\/strong> for Kanban board triage.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"who%20can%20submit%20feedback%3F\"><h3>Who can submit feedback?<\/h3><\/dt>\n<dd><p>This is configurable under <strong>Settings \u2192 Tuft Feedback \u2192 Widget visibility<\/strong>. The options are:<\/p>\n\n<ul>\n<li><strong>Everyone<\/strong> \u2014 all visitors, including logged-out guests (useful for anonymous client review)<\/li>\n<li><strong>Logged-in users only<\/strong> \u2014 any authenticated WordPress user (the default)<\/li>\n<li><strong>Editors and above<\/strong> \u2014 users with the <code>edit_others_posts<\/code> capability<\/li>\n<li><strong>Administrators only<\/strong> \u2014 users with the <code>manage_options<\/code> capability<\/li>\n<\/ul>\n\n<p>Logged-in users always have a streamlined experience: the name and email fields are hidden in the modal and their WordPress account details are submitted automatically.<\/p><\/dd>\n<dt id=\"where%20are%20submissions%20stored%3F\"><h3>Where are submissions stored?<\/h3><\/dt>\n<dd><p>In the WordPress database as a custom post type (<code>tuft_feedback<\/code>). You can review them under <strong>Tuft Feedback<\/strong> in the admin menu, or under <strong>Project Board \u2192 Tuft Feedback<\/strong> if Alpaca Issue Tracker is active.<\/p><\/dd>\n<dt id=\"do%20screenshots%20always%20work%3F\"><h3>Do screenshots always work?<\/h3><\/dt>\n<dd><p>html2canvas is bundled with the plugin and served directly from <code>assets\/js\/vendor\/<\/code> \u2014 there is no CDN dependency. Screenshots should work in any environment.<\/p>\n\n<p>In sandboxed environments like WordPress Playground where enqueued stylesheets suffer from cross-origin\/CORS restrictions, a built-in Playground helper dynamically inlines stylesheets as <code>&lt;style&gt;<\/code> blocks. This allows html2canvas to access style rules without triggering browser security blocks, ensuring screenshots render fully styled. The only case where a screenshot may be absent is very old browsers that do not support the Canvas API, which is vanishingly rare in practice.<\/p><\/dd>\n<dt id=\"can%20i%20get%20notified%20when%20someone%20submits%20feedback%3F\"><h3>Can I get notified when someone submits feedback?<\/h3><\/dt>\n<dd><p>Yes, without writing any code. Under <strong>Settings \u2192 Tuft Feedback \u2192 Notifications<\/strong>:<\/p>\n\n<ul>\n<li><strong>Notify email(s)<\/strong> \u2014 enter a comma-separated list of email addresses. A plain-text notification is sent to each address on every submission.<\/li>\n<li><strong>Webhook URL(s)<\/strong> \u2014 enter one URL per line. A JSON payload is POSTed to each URL on every submission. The payload is compatible with Slack incoming webhooks (it includes a <code>text<\/code> field), Discord, Teams, Zapier, Make, and any custom HTTP endpoint.<\/li>\n<\/ul>\n\n<p>For fully custom integrations, hook into the <code>tuft_feedback_submitted<\/code> action:<\/p>\n\n<pre><code>add_action( 'tuft_feedback_submitted', function ( int $post_id ) {\n    $feedback = get_post_meta( $post_id, '_tuft_feedback_text', true );\n    $page_url = get_post_meta( $post_id, '_tuft_page_url', true );\n    \/\/ create a GitHub issue, update a tracker, etc.\n} );\n<\/code><\/pre><\/dd>\n<dt id=\"is%20this%20safe%20for%20production%3F\"><h3>Is this safe for production?<\/h3><\/dt>\n<dd><p>The widget visibility setting controls both the frontend button <strong>and<\/strong> the REST submission endpoint \u2014 they are kept in sync automatically. Setting visibility to <strong>Logged-in users only<\/strong>, <strong>Editors and above<\/strong>, or <strong>Administrators only<\/strong> will block unauthenticated API submissions with a 401\/403 before any data is written. No additional configuration is required.<\/p><\/dd>\n<dt id=\"does%20it%20work%20with%20page%20builders%20and%20custom%20themes%3F\"><h3>Does it work with page builders and custom themes?<\/h3><\/dt>\n<dd><p>Yes. The plugin injects its UI via <code>wp_enqueue_scripts<\/code> and appends its elements directly to <code>document.body<\/code>, so it works alongside any theme or page builder. The element selector logic ignores elements with <code>tuft-<\/code> prefixed IDs to prevent accidentally annotating the plugin's own UI.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.2.0<\/h4>\n\n<ul>\n<li><strong>REST API permission enforcement<\/strong> \u2014 the <code>\/tuft\/v1\/submit<\/code> endpoint now mirrors the widget visibility setting; requests from users who don't meet the configured access level are rejected with a proper 401\/403 before any data is written.<\/li>\n<li><strong>Admin stylesheet<\/strong> \u2014 meta box styles extracted from inline <code>&lt;style&gt;<\/code> output to <code>assets\/css\/admin.css<\/code>, enqueued only on <code>tuft_feedback<\/code> screens. Resolves a plugin directory guideline violation.<\/li>\n<li><strong>Formatting toolchain<\/strong> \u2014 added <code>npm run format<\/code> (and <code>format:js<\/code>, <code>format:css<\/code>, <code>format:php<\/code>) backed by <code>wp-scripts format<\/code>, stylelint <code>--fix<\/code>, and <code>phpcbf<\/code>.<\/li>\n<li>Settings page: visibility field labels now pass through <code>wp_kses<\/code> with an explicit allowlist instead of unescaped output.<\/li>\n<\/ul>\n\n<h4>1.1.0<\/h4>\n\n<ul>\n<li><strong>Freehand canvas annotation<\/strong> \u2014 a drawing toolbar (pen, rectangle, undo, clear) is shown below the screenshot preview in the feedback modal. Strokes are baked into the submitted JPEG; no server-side overlay is applied.<\/li>\n<li><strong>Widget visibility settings<\/strong> \u2014 new Settings \u2192 Tuft Feedback page; choose to show the feedback button to everyone, logged-in users, editors and above, or administrators only. Role-gated options display approximate user counts.<\/li>\n<li><strong>Submission rate limiting<\/strong> \u2014 max submissions per IP per hour, tracked via post meta (<code>_tuft_submitter_ip<\/code>) rather than transients. Set to 0 to disable.<\/li>\n<li><strong>Email notifications<\/strong> \u2014 configure comma-separated recipient addresses to receive a plain-text email on every submission.<\/li>\n<li><strong>Webhook notifications<\/strong> \u2014 configure one or more webhook URLs to receive a JSON POST on every submission. The payload is compatible with Slack, Discord, Teams, Zapier, Make, and any HTTP endpoint.<\/li>\n<li>Admin menu labels renamed from \"Tuft\" to \"Tuft Feedback\" for clarity.<\/li>\n<li>Removed server-side SVG annotation overlay (made redundant by client-side canvas annotation).<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>Initial release.<\/li>\n<li>Click-to-annotate with element highlighting and crosshair targeting mode.<\/li>\n<li>Element bounding box captured and shown as a dashed rectangle in screenshot annotations.<\/li>\n<li>In-browser viewport screenshot via html2canvas, annotated with a spotlight and crosshair at the click point.<\/li>\n<li>Form field state capture (passwords excluded).<\/li>\n<li>Feedback modal: name\/email fields shown to guests, hidden for logged-in users whose account details are used automatically.<\/li>\n<li><code>tuft_feedback<\/code> custom post type with admin list table and detail meta box.<\/li>\n<li><code>tuft_feedback_submitted<\/code> action hook for custom integrations.<\/li>\n<li>Alpaca Issue Tracker integration: auto-creates mirrored <code>alpaca_issue<\/code> with context comment (including annotated screenshot), moves admin menu under Project Board.<\/li>\n<\/ul>","raw_excerpt":"Collect visual design feedback directly on the page \u2014 visitors click any element, annotate a screenshot, and add a note without leaving the browser.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/323448","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=323448"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/georgestephanis"}],"wp:attachment":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=323448"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=323448"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=323448"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=323448"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=323448"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=323448"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}