Skip to content

Commit 1c2c152

Browse files
enejbCopilot
andauthored
Forms: Add feedback notes support (#46309)
* Forms: Add feedback comments * changelog * fix typo Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * fix dependencies Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * add alt text Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * rename file with typo * Make it work nicer on mobile * Make it work with more then 100 comments Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * fix linter * Use the core store to store the comments updates instead of fetch endpoint * fix php tests * Remove the empty state css * Make isDeleteing be comment specific. * Update projects/packages/forms/src/dashboard/components/feedback-comments/comment-item.tsx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Remove perPage from dependencies * fix linter * wrap with safeHTML * make notes more locked down * Update the tests * update the pnpm lock files * Add support for enabling form notes feature Introduces a new isNotesEnabled flag in the forms config, controlled by a filter in the backend. Updates the dashboard and inspector components to conditionally render feedback comments based on this flag, and improves type definitions accordingly. * Pass throwOnError option to deleteEntityRecord Adds the throwOnError: true option to the deleteEntityRecord call when deleting a comment, ensuring errors are properly thrown and handled. * Fix typo * minor fix * minor fixes * Minor fixes --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 893ac38 commit 1c2c152

File tree

14 files changed

+826
-15
lines changed

14 files changed

+826
-15
lines changed

pnpm-lock.yaml

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Significance: minor
2+
Type: added
3+
4+
Forms: add feedback comments

projects/packages/forms/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
"@wordpress/core-data": "7.37.0",
5858
"@wordpress/data": "10.37.0",
5959
"@wordpress/dataviews": "11.0.0",
60+
"@wordpress/dom": "4.37.0",
6061
"@wordpress/dom-ready": "4.37.0",
6162
"@wordpress/editor": "14.37.0",
6263
"@wordpress/element": "6.37.0",

projects/packages/forms/src/contact-form/class-contact-form-endpoint.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1503,6 +1503,7 @@ public function get_forms_config( WP_REST_Request $request ) { // phpcs:ignore V
15031503
'pluginAssetsURL' => Jetpack_Forms::assets_url(),
15041504
'siteURL' => ( new Status() )->get_site_suffix(),
15051505
'hasFeedback' => ( new Forms_Dashboard() )->has_feedback(),
1506+
'isNotesEnabled' => Forms_Dashboard::is_notes_enabled(),
15061507
'isIntegrationsEnabled' => Jetpack_Forms::is_integrations_enabled(),
15071508
'isWebhooksEnabled' => Jetpack_Forms::is_webhooks_enabled(),
15081509
'showDashboardIntegrations' => Jetpack_Forms::show_dashboard_integrations(),

projects/packages/forms/src/contact-form/class-contact-form-plugin.php

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -237,29 +237,34 @@ protected function __construct() {
237237

238238
add_filter( 'use_block_editor_for_post_type', array( $this, 'use_block_editor_for_post_type' ), 10, 2 );
239239

240+
// Restrict feedback comments to logged-in users only
241+
add_filter( 'comments_open', array( $this, 'restrict_feedback_comments_to_logged_in' ), 10, 2 );
242+
240243
// custom post type we'll use to keep copies of the feedback items
241244
register_post_type(
242245
'feedback',
243246
array(
244-
'labels' => array(
247+
'labels' => array(
245248
'name' => __( 'Form Responses', 'jetpack-forms' ),
246249
'singular_name' => __( 'Form Responses', 'jetpack-forms' ),
247250
'search_items' => __( 'Search Responses', 'jetpack-forms' ),
248251
'not_found' => __( 'No responses found', 'jetpack-forms' ),
249252
'not_found_in_trash' => __( 'No responses found', 'jetpack-forms' ),
250253
),
251-
'menu_icon' => 'dashicons-feedback',
254+
'menu_icon' => 'dashicons-feedback',
252255
// when the legacy menu item is retired, we don't want to show the default post type listing
253-
'show_ui' => false,
254-
'show_in_menu' => false,
255-
'show_in_admin_bar' => false,
256-
'public' => false,
257-
'rewrite' => false,
258-
'query_var' => false,
259-
'capability_type' => 'page',
260-
'show_in_rest' => true,
261-
'rest_controller_class' => '\Automattic\Jetpack\Forms\ContactForm\Contact_Form_Endpoint',
262-
'capabilities' => array(
256+
'show_ui' => false,
257+
'show_in_menu' => false,
258+
'show_in_admin_bar' => false,
259+
'public' => false,
260+
'rewrite' => false,
261+
'query_var' => false,
262+
'capability_type' => 'page',
263+
'show_in_rest' => true,
264+
'rest_controller_class' => '\Automattic\Jetpack\Forms\ContactForm\Contact_Form_Endpoint',
265+
'supports' => array( 'comments' ),
266+
'default_comment_status' => 'open',
267+
'capabilities' => array(
263268
'create_posts' => 'do_not_allow',
264269
'publish_posts' => 'publish_pages',
265270
'edit_posts' => 'edit_pages',
@@ -271,7 +276,7 @@ protected function __construct() {
271276
'delete_post' => 'delete_page',
272277
'read_post' => 'read_page',
273278
),
274-
'map_meta_cap' => true,
279+
'map_meta_cap' => true,
275280
)
276281
);
277282
add_filter( 'wp_untrash_post_status', array( $this, 'untrash_feedback_status_handler' ), 10, 3 );
@@ -3501,6 +3506,29 @@ public function use_block_editor_for_post_type( $can_edit, $post_type ) {
35013506
return 'feedback' === $post_type ? false : $can_edit;
35023507
}
35033508

3509+
/**
3510+
* Restrict comments on feedback posts to logged-in users only.
3511+
* Hooks into comment permissions to enforce authentication requirement.
3512+
*
3513+
* For feedback posts, we override the comment_status field (which we use
3514+
* for read/unread tracking) and always allow comments for logged-in users.
3515+
*
3516+
* @param bool $open Whether comments are open.
3517+
* @param int $post_id Post ID.
3518+
* @return bool Whether comments are open for this post.
3519+
*/
3520+
public function restrict_feedback_comments_to_logged_in( $open, $post_id ) {
3521+
$post = get_post( $post_id );
3522+
3523+
if ( ! $post || 'feedback' !== $post->post_type ) {
3524+
return $open;
3525+
}
3526+
3527+
// For feedback posts, comments are always open for users that can read pages.
3528+
// regardless of comment_status (which we use for read/unread tracking).
3529+
return current_user_can( 'edit_pages' );
3530+
}
3531+
35043532
/**
35053533
* Kludge method: reverses the output of a standard print_r( $array ).
35063534
* Sort of what unserialize does to a serialized object.

projects/packages/forms/src/dashboard/class-dashboard.php

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ public function load_admin_scripts() {
9090
'in_footer' => true,
9191
'textdomain' => 'jetpack-forms',
9292
'enqueue' => true,
93-
'dependencies' => array( 'wp-api-fetch', 'wp-data', 'wp-core-data', 'wp-dom-ready' ),
93+
'dependencies' => array( 'wp-api-fetch', 'wp-data', 'wp-core-data', 'wp-dom-ready', 'wp-dom' ),
9494
)
9595
);
9696

@@ -255,4 +255,21 @@ public static function is_jetpack_forms_admin_page() {
255255
$screen = get_current_screen();
256256
return $screen && $screen->id === 'jetpack_page_jetpack-forms-admin';
257257
}
258+
259+
/**
260+
* Returns true if form notes feature is enabled.
261+
*
262+
* @return boolean
263+
*/
264+
public static function is_notes_enabled() {
265+
/**
266+
* Enable form notes feature in Jetpack Forms .
267+
*
268+
* @module contact-form
269+
* @since $$next-version$$
270+
*
271+
* @param bool $enabled Should the form notes feature be enabled? Defaults to false.
272+
*/
273+
return apply_filters( 'jetpack_forms_notes_enable', false );
274+
}
258275
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/**
2+
* External dependencies
3+
*/
4+
import { DropdownMenu } from '@wordpress/components';
5+
import { dateI18n, getSettings as getDateSettings } from '@wordpress/date';
6+
import { safeHTML } from '@wordpress/dom';
7+
import { __, sprintf } from '@wordpress/i18n';
8+
import { moreVertical, trash } from '@wordpress/icons';
9+
import type { FeedbackComment } from '../../../types';
10+
11+
export type CommentItemProps = {
12+
comment: FeedbackComment;
13+
onDelete: ( id: number ) => void;
14+
isDeleting: boolean;
15+
};
16+
17+
/**
18+
* Format comment date using WP settings.
19+
*
20+
* @param dateString - ISO date string from the comment
21+
* @return Formatted date/time string
22+
*/
23+
function formatCommentDate( dateString: string ) {
24+
return sprintf(
25+
/* Translators: %1$s is the date, %2$s is the time. */
26+
__( '%1$s at %2$s', 'jetpack-forms' ),
27+
dateI18n( getDateSettings().formats.date, dateString ),
28+
dateI18n( getDateSettings().formats.time, dateString )
29+
);
30+
}
31+
32+
/**
33+
* Renders a single feedback comment item, including author, date, content,
34+
* and an options menu to delete the comment.
35+
*
36+
* @param {CommentItemProps} props - Component props.
37+
* @param {FeedbackComment} props.comment - The feedback comment to display.
38+
* @param {(id: number) => void} props.onDelete - Callback invoked when the delete action is selected.
39+
* @param {boolean} props.isDeleting - Whether a delete operation is currently in progress.
40+
* @return {JSX.Element} The rendered feedback comment item element.
41+
*/
42+
const CommentItem = ( { comment, onDelete, isDeleting }: CommentItemProps ) => {
43+
return (
44+
<div key={ comment.id } className="jp-forms__feedback-comments-comment">
45+
<div className="jp-forms__feedback-comments-comment-meta">
46+
<strong className="jp-forms__feedback-comments-comment-author">
47+
{ comment.author_name }
48+
</strong>
49+
<span className="jp-forms__feedback-comments-comment-date">
50+
{ formatCommentDate( comment.date ) }
51+
</span>
52+
<DropdownMenu
53+
icon={ moreVertical }
54+
label={ __( 'Note options', 'jetpack-forms' ) }
55+
controls={ [
56+
{
57+
title: __( 'Delete', 'jetpack-forms' ),
58+
icon: trash,
59+
onClick: () => onDelete( comment.id ),
60+
isDisabled: isDeleting,
61+
},
62+
] }
63+
/>
64+
</div>
65+
<div
66+
className="jp-forms__feedback-comments-comment-content"
67+
// eslint-disable-next-line react/no-danger
68+
dangerouslySetInnerHTML={ { __html: safeHTML( comment.content.rendered ) } }
69+
/>
70+
</div>
71+
);
72+
};
73+
74+
export default CommentItem;

0 commit comments

Comments
 (0)