feat: Leave Feedback form — multi-select checkboxes + actually-working submit
The right-column "Leave Feedback" form on the About page has been
expanded from two radio buttons (user picked one of two) to seven
checkboxes (user can pick any), plus an optional message textarea.
The submit button — which previously called toggleSection() on
element IDs that never existed and did nothing — now AJAX-posts
to a new server-side handler that emails the site admin via
wp_mail().
FORM OPTIONS (checkboxes — multi-select)
- I have ideas to improve this plugin
- I need help with this plugin
- I found a bug
- I'd like to request a new feature
- I'd like to share my use case
- Just saying thanks
- Other
SUBMISSION FLOW
- Client-side: at least one checkbox OR a message is required; an
inline hint shows otherwise.
- AJAX POST wp_notes_submit_feedback with topics[] + message + nonce.
- Server handler (manage_options capability + nonce checked)
sanitizes input, allow-lists the seven topic keys, builds a
plain-text email body (sender + site URL + plugin version +
checked topics with pretty labels + message), and ships it to
get_option('admin_email') via wp_mail() with Reply-To set to the
submitting user.
- Inline success message replaces the form on success; inline error
lets the user retry on failure.
The toggleSection() helper that the old broken handler used is kept
defined for now — it's no longer referenced anywhere on the About
page, so it's flagged in the changelog for a future Tier-2 removal
pass.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -657,6 +657,74 @@ function wp_notes_add_inline_scripts() {
|
||||
</script>";
|
||||
}
|
||||
|
||||
// Receive the "Leave Feedback" form from the About page and forward
|
||||
// it to the site admin via wp_mail(). Topics is an array of short
|
||||
// keys (improve / help / bug / feature / use-case / thanks / other);
|
||||
// message is an optional free-text textarea. Sender info is taken
|
||||
// from wp_get_current_user() so we never trust client-supplied
|
||||
// identity. Capability-gated to manage_options because the About
|
||||
// page is admin-only.
|
||||
add_action('wp_ajax_wp_notes_submit_feedback', 'wp_notes_ajax_submit_feedback');
|
||||
function wp_notes_ajax_submit_feedback() {
|
||||
if (!current_user_can('manage_options')) {
|
||||
wp_send_json_error('Insufficient permissions.', 403);
|
||||
}
|
||||
check_ajax_referer('wp_notes_feedback_submit', 'nonce');
|
||||
|
||||
$allowed_topics = ['improve', 'help', 'bug', 'feature', 'use-case', 'thanks', 'other'];
|
||||
$raw_topics = isset($_POST['topics']) && is_array($_POST['topics']) ? wp_unslash($_POST['topics']) : [];
|
||||
$topics = array_values(array_intersect($allowed_topics, array_map('sanitize_key', $raw_topics)));
|
||||
|
||||
$message = isset($_POST['message']) ? sanitize_textarea_field(wp_unslash($_POST['message'])) : '';
|
||||
|
||||
if (empty($topics) && $message === '') {
|
||||
wp_send_json_error('Pick at least one topic or write a message.', 400);
|
||||
}
|
||||
|
||||
$user = wp_get_current_user();
|
||||
$site = get_bloginfo('name');
|
||||
$to = get_option('admin_email');
|
||||
|
||||
$topic_labels = [
|
||||
'improve' => 'Ideas to improve the plugin',
|
||||
'help' => 'Needs help with the plugin',
|
||||
'bug' => 'Reporting a bug',
|
||||
'feature' => 'New feature request',
|
||||
'use-case' => 'Sharing a use case',
|
||||
'thanks' => 'Saying thanks',
|
||||
'other' => 'Other',
|
||||
];
|
||||
$topics_pretty = array_map(function ($t) use ($topic_labels) { return $topic_labels[$t] ?? $t; }, $topics);
|
||||
|
||||
$subject = sprintf('[%s] WP Notes feedback from %s', $site, $user->display_name ?: $user->user_login);
|
||||
$body = "Feedback received via WP Notes → About page\n";
|
||||
$body .= str_repeat('-', 48) . "\n\n";
|
||||
$body .= 'From: ' . ($user->display_name ?: $user->user_login) . ' <' . $user->user_email . ">\n";
|
||||
$body .= 'Site: ' . home_url() . "\n";
|
||||
$body .= 'Plugin: v' . WP_NOTES_VERSION . "\n\n";
|
||||
$body .= "Topics:\n";
|
||||
if (!empty($topics_pretty)) {
|
||||
foreach ($topics_pretty as $label) { $body .= ' - ' . $label . "\n"; }
|
||||
} else {
|
||||
$body .= " (none selected)\n";
|
||||
}
|
||||
$body .= "\nMessage:\n";
|
||||
$body .= $message !== '' ? $message . "\n" : "(no message provided)\n";
|
||||
|
||||
$headers = [
|
||||
'Content-Type: text/plain; charset=UTF-8',
|
||||
'Reply-To: ' . sanitize_email($user->user_email),
|
||||
];
|
||||
|
||||
$sent = wp_mail($to, $subject, $body, $headers);
|
||||
|
||||
if (!$sent) {
|
||||
wp_send_json_error('Email could not be sent. Check the site mail configuration.', 500);
|
||||
}
|
||||
|
||||
wp_send_json_success(['delivered_to' => $to]);
|
||||
}
|
||||
|
||||
// Persist a user's dismissal of the "No active/completed notes found"
|
||||
// empty-state notice so it doesn't reappear on the next page load.
|
||||
// Triggered by inline JS in wp_notes_add_inline_scripts() when the
|
||||
|
||||
Reference in New Issue
Block a user