@@ -123,7 +123,7 @@ 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 ' ];
126+ $ is_note = in_array ( $ request ['type ' ], array ( ' note ' , ' reaction ' ), true ) ;
127127 $ is_edit_context = 'edit ' === $ request ['context ' ];
128128 $ protected_params = array ( 'author ' , 'author_exclude ' , 'author_email ' , 'type ' , 'status ' );
129129 $ forbidden_params = array ();
@@ -437,8 +437,8 @@ public function get_item_permissions_check( $request ) {
437437 return $ comment ;
438438 }
439439
440- // Re-map edit context capabilities when requesting `note` type.
441- $ edit_cap = ' note ' === $ comment ->comment_type ? array ( 'edit_comment ' , $ comment ->comment_ID ) : array ( 'moderate_comments ' );
440+ // Re-map edit context capabilities when requesting `note` or `reaction` type.
441+ $ edit_cap = in_array ( $ comment ->comment_type , array ( ' note ' , ' reaction ' ), true ) ? array ( 'edit_comment ' , $ comment ->comment_ID ) : array ( 'moderate_comments ' );
442442 if ( ! empty ( $ request ['context ' ] ) && 'edit ' === $ request ['context ' ] && ! current_user_can ( ...$ edit_cap ) ) {
443443 return new WP_Error (
444444 'rest_forbidden_context ' ,
@@ -497,7 +497,7 @@ public function get_item( $request ) {
497497 * @return true|WP_Error True if the request has access to create items, error object otherwise.
498498 */
499499 public function create_item_permissions_check ( $ request ) {
500- $ is_note = ! empty ( $ request ['type ' ] ) && ' note ' === $ request ['type ' ];
500+ $ is_note = ! empty ( $ request ['type ' ] ) && in_array ( $ request ['type ' ], array ( ' note ' , ' reaction ' ), true ) ;
501501
502502 if ( ! is_user_logged_in () && $ is_note ) {
503503 return new WP_Error (
@@ -649,14 +649,65 @@ public function create_item( $request ) {
649649 }
650650
651651 // Do not allow comments to be created with a non-core type.
652- if ( ! empty ( $ request ['type ' ] ) && ! in_array ( $ request ['type ' ], array ( 'comment ' , 'note ' ), true ) ) {
652+ if ( ! empty ( $ request ['type ' ] ) && ! in_array ( $ request ['type ' ], array ( 'comment ' , 'note ' , ' reaction ' ), true ) ) {
653653 return new WP_Error (
654654 'rest_invalid_comment_type ' ,
655655 __ ( 'Cannot create a comment with that type. ' ),
656656 array ( 'status ' => 400 )
657657 );
658658 }
659659
660+ // Validate reaction-specific constraints.
661+ if ( ! empty ( $ request ['type ' ] ) && 'reaction ' === $ request ['type ' ] ) {
662+ $ valid_emojis = array ( 'heart ' , 'celebration ' , 'smile ' , 'eyes ' , 'rocket ' );
663+
664+ // Reaction content must be a valid emoji slug.
665+ if ( empty ( $ request ['content ' ] ) || ! in_array ( $ request ['content ' ], $ valid_emojis , true ) ) {
666+ return new WP_Error (
667+ 'rest_reaction_invalid_emoji ' ,
668+ __ ( 'Reaction content must be a valid emoji slug. ' ),
669+ array ( 'status ' => 400 )
670+ );
671+ }
672+
673+ // Reaction parent must exist and be a note.
674+ if ( empty ( $ request ['parent ' ] ) ) {
675+ return new WP_Error (
676+ 'rest_reaction_parent_required ' ,
677+ __ ( 'Reactions must have a parent note. ' ),
678+ array ( 'status ' => 400 )
679+ );
680+ }
681+
682+ $ parent_comment = get_comment ( $ request ['parent ' ] );
683+ if ( ! $ parent_comment || 'note ' !== $ parent_comment ->comment_type ) {
684+ return new WP_Error (
685+ 'rest_reaction_invalid_parent ' ,
686+ __ ( 'Reactions can only be added to notes. ' ),
687+ array ( 'status ' => 400 )
688+ );
689+ }
690+
691+ // Enforce uniqueness: one emoji per user per note.
692+ $ existing = get_comments (
693+ array (
694+ 'comment_type ' => 'reaction ' ,
695+ 'comment_parent ' => $ request ['parent ' ],
696+ 'user_id ' => get_current_user_id (),
697+ 'search ' => $ request ['content ' ],
698+ 'count ' => true ,
699+ )
700+ );
701+
702+ if ( $ existing > 0 ) {
703+ return new WP_Error (
704+ 'rest_reaction_duplicate ' ,
705+ __ ( 'You have already added this reaction. ' ),
706+ array ( 'status ' => 409 )
707+ );
708+ }
709+ }
710+
660711 $ prepared_comment = $ this ->prepare_item_for_database ( $ request );
661712 if ( is_wp_error ( $ prepared_comment ) ) {
662713 return $ prepared_comment ;
@@ -735,9 +786,9 @@ public function create_item( $request ) {
735786 );
736787 }
737788
738- // Don't check for duplicates or flooding for notes.
789+ // Don't check for duplicates or flooding for notes or reactions .
739790 $ prepared_comment ['comment_approved ' ] =
740- ' note ' === $ prepared_comment ['comment_type ' ] ?
791+ in_array ( $ prepared_comment ['comment_type ' ], array ( ' note ' , ' reaction ' ), true ) ?
741792 '1 ' :
742793 wp_allow_comment ( $ prepared_comment , true );
743794
@@ -1297,7 +1348,7 @@ protected function prepare_links( $comment ) {
12971348 }
12981349
12991350 // Embedding children for notes requires `type` and `status` inheritance.
1300- if ( isset ( $ links ['children ' ] ) && ' note ' === $ comment ->comment_type ) {
1351+ if ( isset ( $ links ['children ' ] ) && in_array ( $ comment ->comment_type , array ( ' note ' , ' reaction ' ), true ) ) {
13011352 $ args = array (
13021353 'parent ' => $ comment ->comment_ID ,
13031354 'type ' => $ comment ->comment_type ,
@@ -1911,7 +1962,7 @@ protected function check_read_post_permission( $post, $request ) {
19111962 * @return bool Whether the comment can be read.
19121963 */
19131964 protected function check_read_permission ( $ comment , $ request ) {
1914- if ( ' note ' !== $ comment ->comment_type && ! empty ( $ comment ->comment_post_ID ) ) {
1965+ if ( ! in_array ( $ comment ->comment_type , array ( ' note ' , ' reaction ' ), true ) && ! empty ( $ comment ->comment_post_ID ) ) {
19151966 $ post = get_post ( $ comment ->comment_post_ID );
19161967 if ( $ post ) {
19171968 if ( $ this ->check_read_post_permission ( $ post , $ request ) && 1 === (int ) $ comment ->comment_approved ) {
@@ -2026,6 +2077,11 @@ protected function check_is_comment_content_allowed( $prepared_comment ) {
20262077 return true ;
20272078 }
20282079
2080+ // Reactions always have content (the emoji slug), so allow them.
2081+ if ( isset ( $ check ['comment_type ' ] ) && 'reaction ' === $ check ['comment_type ' ] ) {
2082+ return true ;
2083+ }
2084+
20292085 /*
20302086 * Do not allow a comment to be created with missing or empty
20312087 * comment_content. See wp_handle_comment_submission().
0 commit comments