-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Incorporating foundation of "Notes" feature #10280
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 18 commits
e08eea2
c00b9e1
c1aebc0
495504c
f5207cf
954f534
7d1e549
3e4347b
7276884
f74effd
13defce
3cf787a
b351ddb
ce0f128
df8cb5d
4833d19
35375c8
4ab0abf
b0bcc8c
891d9d2
6caa20b
1f3b1d8
10e1023
ae2ba63
6ada59c
571ede1
c0d81db
a208f84
a21c51f
992a3bd
f0ee469
48cb687
278d274
a43a2b0
a643878
6eb536a
4edfc8d
2ad2332
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -726,6 +726,11 @@ function wp_allow_comment( $commentdata, $wp_error = false ) { | |
*/ | ||
$dupe_id = apply_filters( 'duplicate_comment_id', $dupe_id, $commentdata ); | ||
|
||
// Allow duplicate notes for resolution purposes. | ||
|
||
if ( isset( $commentdata['comment_type'] ) && 'note' === $commentdata['comment_type'] ) { | ||
$dupe_id = false; | ||
} | ||
|
||
if ( $dupe_id ) { | ||
/** | ||
* Fires immediately after a duplicate comment is detected. | ||
|
@@ -4103,3 +4108,30 @@ function _wp_check_for_scheduled_update_comment_type() { | |
wp_schedule_single_event( time() + MINUTE_IN_SECONDS, 'wp_update_comment_type_batch' ); | ||
} | ||
} | ||
|
||
/** | ||
* Register notes metadata for notes status. | ||
* | ||
* @since 6.9.0 | ||
*/ | ||
function wp_register_notes_metadata() { | ||
|
||
register_meta( | ||
'comment', | ||
'_wp_note_status', | ||
array( | ||
'type' => 'string', | ||
'description' => __( 'Note resolution status' ), | ||
'single' => true, | ||
'show_in_rest' => array( | ||
'schema' => array( | ||
'type' => 'string', | ||
'enum' => array( 'resolved', 'reopen' ), | ||
), | ||
), | ||
'auth_callback' => function ( $allowed, $meta_key, $object_id ) { | ||
return current_user_can( 'edit_comment', $object_id ); | ||
}, | ||
|
||
) | ||
); | ||
} | ||
add_action( 'init', 'wp_register_notes_metadata' ); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -123,11 +123,21 @@ public function register_routes() { | |
* @return true|WP_Error True if the request has read access, error object otherwise. | ||
*/ | ||
public function get_items_permissions_check( $request ) { | ||
$is_note = ! empty( $request['type'] ) && 'note' === $request['type']; | ||
$is_edit_context = ! empty( $request['context'] ) && 'edit' === $request['context']; | ||
|
||
|
||
if ( ! empty( $request['post'] ) ) { | ||
foreach ( (array) $request['post'] as $post_id ) { | ||
$post = get_post( $post_id ); | ||
|
||
if ( $post && $is_note && ! $this->check_post_type_supports_notes( $post->post_type ) ) { | ||
return new WP_Error( | ||
'rest_comment_not_supported_post_type', | ||
__( 'Sorry, this post type does not support notes.' ), | ||
array( 'status' => 403 ) | ||
); | ||
} | ||
|
||
if ( ! empty( $post_id ) && $post && ! $this->check_read_post_permission( $post, $request ) ) { | ||
return new WP_Error( | ||
'rest_cannot_read_post', | ||
|
@@ -144,7 +154,18 @@ public function get_items_permissions_check( $request ) { | |
} | ||
} | ||
|
||
if ( ! empty( $request['context'] ) && 'edit' === $request['context'] && ! current_user_can( 'moderate_comments' ) ) { | ||
// Re-map edit context capabilities when requesting `note` for a post. | ||
if ( $is_edit_context && $is_note && ! empty( $request['post'] ) ) { | ||
foreach ( (array) $request['post'] as $post_id ) { | ||
if ( ! current_user_can( 'edit_post', $post_id ) ) { | ||
return new WP_Error( | ||
'rest_forbidden_context', | ||
__( 'Sorry, you are not allowed to edit comments.' ), | ||
array( 'status' => rest_authorization_required_code() ) | ||
); | ||
} | ||
} | ||
} elseif ( $is_edit_context && ! current_user_can( 'moderate_comments' ) ) { | ||
return new WP_Error( | ||
'rest_forbidden_context', | ||
__( 'Sorry, you are not allowed to edit comments.' ), | ||
|
@@ -394,7 +415,9 @@ public function get_item_permissions_check( $request ) { | |
return $comment; | ||
} | ||
|
||
if ( ! empty( $request['context'] ) && 'edit' === $request['context'] && ! current_user_can( 'moderate_comments' ) ) { | ||
// Re-map edit context capabilities when requesting `note` type. | ||
$edit_cap = 'note' === $comment->comment_type ? array( 'edit_comment', $comment->comment_ID ) : array( 'moderate_comments' ); | ||
if ( ! empty( $request['context'] ) && 'edit' === $request['context'] && ! current_user_can( ...$edit_cap ) ) { | ||
return new WP_Error( | ||
'rest_forbidden_context', | ||
__( 'Sorry, you are not allowed to edit comments.' ), | ||
|
@@ -452,6 +475,16 @@ public function get_item( $request ) { | |
* @return true|WP_Error True if the request has access to create items, error object otherwise. | ||
*/ | ||
public function create_item_permissions_check( $request ) { | ||
$is_note = ! empty( $request['type'] ) && 'note' === $request['type']; | ||
|
||
if ( ! is_user_logged_in() && $is_note ) { | ||
return new WP_Error( | ||
'rest_comment_login_required', | ||
__( 'Sorry, you must be logged in to comment.' ), | ||
array( 'status' => 401 ) | ||
); | ||
} | ||
|
||
if ( ! is_user_logged_in() ) { | ||
if ( get_option( 'comment_registration' ) ) { | ||
return new WP_Error( | ||
|
@@ -505,7 +538,8 @@ public function create_item_permissions_check( $request ) { | |
} | ||
} | ||
|
||
if ( isset( $request['status'] ) && ! current_user_can( 'moderate_comments' ) ) { | ||
$edit_cap = $is_note ? array( 'edit_post', (int) $request['post'] ) : array( 'moderate_comments' ); | ||
if ( isset( $request['status'] ) && ! current_user_can( ...$edit_cap ) ) { | ||
return new WP_Error( | ||
'rest_comment_invalid_status', | ||
/* translators: %s: Request parameter. */ | ||
|
@@ -532,7 +566,15 @@ public function create_item_permissions_check( $request ) { | |
); | ||
} | ||
|
||
if ( 'draft' === $post->post_status ) { | ||
if ( $is_note && ! $this->check_post_type_supports_notes( $post->post_type ) ) { | ||
return new WP_Error( | ||
'rest_comment_not_supported_post_type', | ||
__( 'Sorry, this post type does not support notes.' ), | ||
array( 'status' => 403 ) | ||
); | ||
} | ||
|
||
if ( 'draft' === $post->post_status && ! $is_note ) { | ||
return new WP_Error( | ||
'rest_comment_draft_post', | ||
__( 'Sorry, you are not allowed to create a comment on this post.' ), | ||
|
@@ -556,7 +598,7 @@ public function create_item_permissions_check( $request ) { | |
); | ||
} | ||
|
||
if ( ! comments_open( $post->ID ) ) { | ||
if ( ! comments_open( $post->ID ) && ! $is_note ) { | ||
return new WP_Error( | ||
'rest_comment_closed', | ||
__( 'Sorry, comments are closed for this item.' ), | ||
|
@@ -584,26 +626,22 @@ public function create_item( $request ) { | |
); | ||
} | ||
|
||
// Do not allow comments to be created with a non-default type. | ||
if ( ! empty( $request['type'] ) && 'comment' !== $request['type'] ) { | ||
return new WP_Error( | ||
'rest_invalid_comment_type', | ||
__( 'Cannot create a comment with that type.' ), | ||
array( 'status' => 400 ) | ||
); | ||
} | ||
t-hamano marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
$prepared_comment = $this->prepare_item_for_database( $request ); | ||
if ( is_wp_error( $prepared_comment ) ) { | ||
return $prepared_comment; | ||
} | ||
|
||
$prepared_comment['comment_type'] = 'comment'; | ||
$prepared_comment['comment_type'] = $request['type']; | ||
t-hamano marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
if ( ! isset( $prepared_comment['comment_content'] ) ) { | ||
$prepared_comment['comment_content'] = ''; | ||
} | ||
|
||
// Include note metadata into check_is_comment_content_allowed. | ||
if ( isset( $request['meta']['_wp_note_status'] ) ) { | ||
$prepared_comment['meta']['_wp_note_status'] = $request['meta']['_wp_note_status']; | ||
} | ||
|
||
if ( ! $this->check_is_comment_content_allowed( $prepared_comment ) ) { | ||
return new WP_Error( | ||
'rest_comment_content_invalid', | ||
|
@@ -1518,8 +1556,9 @@ public function get_item_schema() { | |
'type' => array( | ||
'description' => __( 'Type of the comment.' ), | ||
'type' => 'string', | ||
'enum' => array( 'comment', 'note' ), | ||
t-hamano marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
'default' => 'comment', | ||
'context' => array( 'view', 'edit', 'embed' ), | ||
'readonly' => true, | ||
), | ||
), | ||
); | ||
|
@@ -1894,6 +1933,7 @@ public function check_comment_author_email( $value, $request, $param ) { | |
return $email; | ||
} | ||
|
||
|
||
t-hamano marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
/** | ||
* If empty comments are not allowed, checks if the provided comment content is not empty. | ||
* | ||
|
@@ -1922,10 +1962,42 @@ protected function check_is_comment_content_allowed( $prepared_comment ) { | |
return true; | ||
} | ||
|
||
// Allow empty notes only when resolution metadata is valid. | ||
if ( | ||
isset( $check['comment_type'] ) && | ||
'note' === $check['comment_type'] && | ||
isset( $check['meta']['_wp_note_status'] ) && | ||
in_array( $check['meta']['_wp_note_status'], array( 'resolved', 'reopen' ), true ) | ||
) { | ||
return true; | ||
} | ||
|
||
/* | ||
* Do not allow a comment to be created with missing or empty | ||
* comment_content. See wp_handle_comment_submission(). | ||
*/ | ||
return '' !== $check['comment_content']; | ||
} | ||
|
||
/** | ||
* Check if post type supports notes. | ||
* | ||
* @param string $post_type Post type name. | ||
* @return bool True if post type supports notes, false otherwise. | ||
*/ | ||
private function check_post_type_supports_notes( $post_type ) { | ||
$supports = get_all_post_type_supports( $post_type ); | ||
if ( ! isset( $supports['editor'] ) ) { | ||
return false; | ||
} | ||
if ( ! is_array( $supports['editor'] ) ) { | ||
return false; | ||
} | ||
foreach ( $supports['editor'] as $item ) { | ||
if ( is_array( $item ) && isset( $item['notes'] ) && true === $item['notes'] ) { | ||
t-hamano marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
return true; | ||
} | ||
} | ||
return true; | ||
t-hamano marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's another PR for
get_pending_comments_num
changes - #9869.Just noting for props.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a fan of hardcoding comment types. Long term we should think about using a filterable list of comment types to exclude or using (an improved)
WP_Comment_Query
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
100%. I think a long-term solution is to provide proper support for custom comment types, so we can avoid hardcoded patches like we've introduced with the current implementation.