Skip to content

Commit c62fe7e

Browse files
Editor: Introduce the PHP-related code for Notes.
Bring the PHP part of the new Notes feature into core for the 6.9 release. See related Gutenberg Issue: WordPress/gutenberg#71826. These changes do not impact any user facing functionality, they simply prepare core for the JavaScript functionality that will come over in a separate sync. Overview of changes: - Ensure Notes are not included in comment counts - Enable the note type (REST API) - Adjust capabilities so edit_post cap implies ability to edit notes - Enable empty and duplicate notes for resolve/re-open actions - Add control over notes with post type supports check - Register new note resolution status meta Props: ristojovanovic, adamsilverstein, jeffpaul, wildworks, mamaduka, swissspidy, timothyblynjacobs, kadamwhite. Fixes #64096. git-svn-id: https://develop.svn.wordpress.org/trunk@60987 602fd350-edb4-49c9-b593-d223f7449a82
1 parent 20b1cf6 commit c62fe7e

File tree

7 files changed

+600
-20
lines changed

7 files changed

+600
-20
lines changed

src/wp-admin/includes/class-wp-comments-list-table.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ public function prepare_items() {
151151
'order' => $order,
152152
'post_type' => $post_type,
153153
'update_comment_post_cache' => true,
154+
'type__not_in' => array( 'note' ),
154155
);
155156

156157
/**

src/wp-admin/includes/comment.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ function get_pending_comments_num( $post_id ) {
157157
$post_id_array = array_map( 'intval', $post_id_array );
158158
$post_id_in = "'" . implode( "', '", $post_id_array ) . "'";
159159

160-
$pending = $wpdb->get_results( "SELECT comment_post_ID, COUNT(comment_ID) as num_comments FROM $wpdb->comments WHERE comment_post_ID IN ( $post_id_in ) AND comment_approved = '0' GROUP BY comment_post_ID", ARRAY_A );
160+
$pending = $wpdb->get_results( "SELECT comment_post_ID, COUNT(comment_ID) as num_comments FROM $wpdb->comments WHERE comment_post_ID IN ( $post_id_in ) AND comment_approved = '0' AND comment_type != 'note' GROUP BY comment_post_ID", ARRAY_A );
161161

162162
if ( $single ) {
163163
if ( empty( $pending ) ) {

src/wp-includes/comment.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,7 @@ function get_comment_count( $post_id = 0 ) {
417417
'count' => true,
418418
'update_comment_meta_cache' => false,
419419
'orderby' => 'none',
420+
'type__not_in' => array( 'note' ),
420421
);
421422
if ( $post_id > 0 ) {
422423
$args['post_id'] = $post_id;
@@ -714,6 +715,11 @@ function wp_allow_comment( $commentdata, $wp_error = false ) {
714715

715716
$dupe_id = $wpdb->get_var( $dupe );
716717

718+
// Allow duplicate notes for resolution purposes.
719+
if ( isset( $commentdata['comment_type'] ) && 'note' === $commentdata['comment_type'] ) {
720+
$dupe_id = false;
721+
}
722+
717723
/**
718724
* Filters the ID, if any, of the duplicate comment found when creating a new comment.
719725
*
@@ -4103,3 +4109,27 @@ function _wp_check_for_scheduled_update_comment_type() {
41034109
wp_schedule_single_event( time() + MINUTE_IN_SECONDS, 'wp_update_comment_type_batch' );
41044110
}
41054111
}
4112+
4113+
/**
4114+
* Register initial note status meta.
4115+
*
4116+
* @since 6.9.0
4117+
*/
4118+
function wp_create_initial_comment_meta() {
4119+
register_meta(
4120+
'comment',
4121+
'_wp_note_status',
4122+
array(
4123+
'type' => 'string',
4124+
'description' => __( 'Note resolution status' ),
4125+
'single' => true,
4126+
'show_in_rest' => array(
4127+
'schema' => array(
4128+
'type' => 'string',
4129+
'enum' => array( 'resolved', 'reopen' ),
4130+
),
4131+
),
4132+
)
4133+
);
4134+
}
4135+
add_action( 'init', 'wp_create_initial_comment_meta' );

src/wp-includes/link-template.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4343,9 +4343,11 @@ function is_avatar_comment_type( $comment_type ) {
43434343
*
43444344
* @since 3.0.0
43454345
*
4346-
* @param array $types An array of content types. Default only contains 'comment'.
4346+
* @since 6.9.0 The 'note' comment type was added.
4347+
*
4348+
* @param array $types An array of content types. Default contains 'comment' and 'note'.
43474349
*/
4348-
$allowed_comment_types = apply_filters( 'get_avatar_comment_types', array( 'comment' ) );
4350+
$allowed_comment_types = apply_filters( 'get_avatar_comment_types', array( 'comment', 'note' ) );
43494351

43504352
return in_array( $comment_type, (array) $allowed_comment_types, true );
43514353
}

src/wp-includes/post.php

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,18 @@ function create_initial_post_types() {
3737
'rewrite' => false,
3838
'query_var' => false,
3939
'delete_with_user' => true,
40-
'supports' => array( 'title', 'editor', 'author', 'thumbnail', 'excerpt', 'trackbacks', 'custom-fields', 'comments', 'revisions', 'post-formats' ),
40+
'supports' => array(
41+
'title',
42+
'editor' => array( 'notes' => true ),
43+
'author',
44+
'thumbnail',
45+
'excerpt',
46+
'trackbacks',
47+
'custom-fields',
48+
'comments',
49+
'revisions',
50+
'post-formats',
51+
),
4152
'show_in_rest' => true,
4253
'rest_base' => 'posts',
4354
'rest_controller_class' => 'WP_REST_Posts_Controller',
@@ -62,7 +73,16 @@ function create_initial_post_types() {
6273
'rewrite' => false,
6374
'query_var' => false,
6475
'delete_with_user' => true,
65-
'supports' => array( 'title', 'editor', 'author', 'thumbnail', 'page-attributes', 'custom-fields', 'comments', 'revisions' ),
76+
'supports' => array(
77+
'title',
78+
'editor' => array( 'notes' => true ),
79+
'author',
80+
'thumbnail',
81+
'page-attributes',
82+
'custom-fields',
83+
'comments',
84+
'revisions',
85+
),
6686
'show_in_rest' => true,
6787
'rest_base' => 'pages',
6888
'rest_controller_class' => 'WP_REST_Posts_Controller',
@@ -2329,7 +2349,6 @@ function post_type_supports( $post_type, $feature ) {
23292349

23302350
return ( isset( $_wp_post_type_features[ $post_type ][ $feature ] ) );
23312351
}
2332-
23332352
/**
23342353
* Retrieves a list of post type names that support a specific feature.
23352354
*

src/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php

Lines changed: 88 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -123,11 +123,21 @@ public function register_routes() {
123123
* @return true|WP_Error True if the request has read access, error object otherwise.
124124
*/
125125
public function get_items_permissions_check( $request ) {
126+
$is_note = 'note' === $request['type'];
127+
$is_edit_context = 'edit' === $request['context'];
126128

127129
if ( ! empty( $request['post'] ) ) {
128130
foreach ( (array) $request['post'] as $post_id ) {
129131
$post = get_post( $post_id );
130132

133+
if ( $post && $is_note && ! $this->check_post_type_supports_notes( $post->post_type ) ) {
134+
return new WP_Error(
135+
'rest_comment_not_supported_post_type',
136+
__( 'Sorry, this post type does not support notes.' ),
137+
array( 'status' => 403 )
138+
);
139+
}
140+
131141
if ( ! empty( $post_id ) && $post && ! $this->check_read_post_permission( $post, $request ) ) {
132142
return new WP_Error(
133143
'rest_cannot_read_post',
@@ -144,7 +154,18 @@ public function get_items_permissions_check( $request ) {
144154
}
145155
}
146156

147-
if ( ! empty( $request['context'] ) && 'edit' === $request['context'] && ! current_user_can( 'moderate_comments' ) ) {
157+
// Re-map edit context capabilities when requesting `note` for a post.
158+
if ( $is_edit_context && $is_note && ! empty( $request['post'] ) ) {
159+
foreach ( (array) $request['post'] as $post_id ) {
160+
if ( ! current_user_can( 'edit_post', $post_id ) ) {
161+
return new WP_Error(
162+
'rest_forbidden_context',
163+
__( 'Sorry, you are not allowed to edit comments.' ),
164+
array( 'status' => rest_authorization_required_code() )
165+
);
166+
}
167+
}
168+
} elseif ( $is_edit_context && ! current_user_can( 'moderate_comments' ) ) {
148169
return new WP_Error(
149170
'rest_forbidden_context',
150171
__( 'Sorry, you are not allowed to edit comments.' ),
@@ -394,7 +415,9 @@ public function get_item_permissions_check( $request ) {
394415
return $comment;
395416
}
396417

397-
if ( ! empty( $request['context'] ) && 'edit' === $request['context'] && ! current_user_can( 'moderate_comments' ) ) {
418+
// Re-map edit context capabilities when requesting `note` type.
419+
$edit_cap = 'note' === $comment->comment_type ? array( 'edit_comment', $comment->comment_ID ) : array( 'moderate_comments' );
420+
if ( ! empty( $request['context'] ) && 'edit' === $request['context'] && ! current_user_can( ...$edit_cap ) ) {
398421
return new WP_Error(
399422
'rest_forbidden_context',
400423
__( 'Sorry, you are not allowed to edit comments.' ),
@@ -452,6 +475,16 @@ public function get_item( $request ) {
452475
* @return true|WP_Error True if the request has access to create items, error object otherwise.
453476
*/
454477
public function create_item_permissions_check( $request ) {
478+
$is_note = ! empty( $request['type'] ) && 'note' === $request['type'];
479+
480+
if ( ! is_user_logged_in() && $is_note ) {
481+
return new WP_Error(
482+
'rest_comment_login_required',
483+
__( 'Sorry, you must be logged in to comment.' ),
484+
array( 'status' => 401 )
485+
);
486+
}
487+
455488
if ( ! is_user_logged_in() ) {
456489
if ( get_option( 'comment_registration' ) ) {
457490
return new WP_Error(
@@ -505,7 +538,8 @@ public function create_item_permissions_check( $request ) {
505538
}
506539
}
507540

508-
if ( isset( $request['status'] ) && ! current_user_can( 'moderate_comments' ) ) {
541+
$edit_cap = $is_note ? array( 'edit_post', (int) $request['post'] ) : array( 'moderate_comments' );
542+
if ( isset( $request['status'] ) && ! current_user_can( ...$edit_cap ) ) {
509543
return new WP_Error(
510544
'rest_comment_invalid_status',
511545
/* translators: %s: Request parameter. */
@@ -532,7 +566,15 @@ public function create_item_permissions_check( $request ) {
532566
);
533567
}
534568

535-
if ( 'draft' === $post->post_status ) {
569+
if ( $is_note && ! $this->check_post_type_supports_notes( $post->post_type ) ) {
570+
return new WP_Error(
571+
'rest_comment_not_supported_post_type',
572+
__( 'Sorry, this post type does not support notes.' ),
573+
array( 'status' => 403 )
574+
);
575+
}
576+
577+
if ( 'draft' === $post->post_status && ! $is_note ) {
536578
return new WP_Error(
537579
'rest_comment_draft_post',
538580
__( 'Sorry, you are not allowed to create a comment on this post.' ),
@@ -556,7 +598,7 @@ public function create_item_permissions_check( $request ) {
556598
);
557599
}
558600

559-
if ( ! comments_open( $post->ID ) ) {
601+
if ( ! comments_open( $post->ID ) && ! $is_note ) {
560602
return new WP_Error(
561603
'rest_comment_closed',
562604
__( 'Sorry, comments are closed for this item.' ),
@@ -584,8 +626,8 @@ public function create_item( $request ) {
584626
);
585627
}
586628

587-
// Do not allow comments to be created with a non-default type.
588-
if ( ! empty( $request['type'] ) && 'comment' !== $request['type'] ) {
629+
// Do not allow comments to be created with a non-core type.
630+
if ( ! empty( $request['type'] ) && ! in_array( $request['type'], array( 'comment', 'note' ), true ) ) {
589631
return new WP_Error(
590632
'rest_invalid_comment_type',
591633
__( 'Cannot create a comment with that type.' ),
@@ -598,12 +640,17 @@ public function create_item( $request ) {
598640
return $prepared_comment;
599641
}
600642

601-
$prepared_comment['comment_type'] = 'comment';
643+
$prepared_comment['comment_type'] = $request['type'];
602644

603645
if ( ! isset( $prepared_comment['comment_content'] ) ) {
604646
$prepared_comment['comment_content'] = '';
605647
}
606648

649+
// Include note metadata into check_is_comment_content_allowed.
650+
if ( isset( $request['meta']['_wp_note_status'] ) ) {
651+
$prepared_comment['meta']['_wp_note_status'] = $request['meta']['_wp_note_status'];
652+
}
653+
607654
if ( ! $this->check_is_comment_content_allowed( $prepared_comment ) ) {
608655
return new WP_Error(
609656
'rest_comment_content_invalid',
@@ -1519,6 +1566,7 @@ public function get_item_schema() {
15191566
'type' => 'string',
15201567
'context' => array( 'view', 'edit', 'embed' ),
15211568
'readonly' => true,
1569+
'default' => 'comment',
15221570
),
15231571
),
15241572
);
@@ -1925,10 +1973,42 @@ protected function check_is_comment_content_allowed( $prepared_comment ) {
19251973
return true;
19261974
}
19271975

1976+
// Allow empty notes only when resolution metadata is valid.
1977+
if (
1978+
isset( $check['comment_type'] ) &&
1979+
'note' === $check['comment_type'] &&
1980+
isset( $check['meta']['_wp_note_status'] ) &&
1981+
in_array( $check['meta']['_wp_note_status'], array( 'resolved', 'reopen' ), true )
1982+
) {
1983+
return true;
1984+
}
1985+
19281986
/*
19291987
* Do not allow a comment to be created with missing or empty
19301988
* comment_content. See wp_handle_comment_submission().
19311989
*/
19321990
return '' !== $check['comment_content'];
19331991
}
1992+
1993+
/**
1994+
* Check if post type supports notes.
1995+
*
1996+
* @param string $post_type Post type name.
1997+
* @return bool True if post type supports notes, false otherwise.
1998+
*/
1999+
private function check_post_type_supports_notes( $post_type ) {
2000+
$supports = get_all_post_type_supports( $post_type );
2001+
if ( ! isset( $supports['editor'] ) ) {
2002+
return false;
2003+
}
2004+
if ( ! is_array( $supports['editor'] ) ) {
2005+
return false;
2006+
}
2007+
foreach ( $supports['editor'] as $item ) {
2008+
if ( ! empty( $item['notes'] ) ) {
2009+
return true;
2010+
}
2011+
}
2012+
return false;
2013+
}
19342014
}

0 commit comments

Comments
 (0)