[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/rest-api/endpoints/ -> class-wp-rest-comments-controller.php (source)

   1  <?php
   2  /**
   3   * REST API: WP_REST_Comments_Controller class
   4   *
   5   * @package WordPress
   6   * @subpackage REST_API
   7   * @since 4.7.0
   8   */
   9  
  10  /**
  11   * Core controller used to access comments via the REST API.
  12   *
  13   * @since 4.7.0
  14   *
  15   * @see WP_REST_Controller
  16   */
  17  class WP_REST_Comments_Controller extends WP_REST_Controller {
  18  
  19      /**
  20       * Instance of a comment meta fields object.
  21       *
  22       * @since 4.7.0
  23       * @var WP_REST_Comment_Meta_Fields
  24       */
  25      protected $meta;
  26  
  27      /**
  28       * Constructor.
  29       *
  30       * @since 4.7.0
  31       */
  32  	public function __construct() {
  33          $this->namespace = 'wp/v2';
  34          $this->rest_base = 'comments';
  35  
  36          $this->meta = new WP_REST_Comment_Meta_Fields();
  37      }
  38  
  39      /**
  40       * Registers the routes for comments.
  41       *
  42       * @since 4.7.0
  43       *
  44       * @see register_rest_route()
  45       */
  46  	public function register_routes() {
  47  
  48          register_rest_route(
  49              $this->namespace,
  50              '/' . $this->rest_base,
  51              array(
  52                  array(
  53                      'methods'             => WP_REST_Server::READABLE,
  54                      'callback'            => array( $this, 'get_items' ),
  55                      'permission_callback' => array( $this, 'get_items_permissions_check' ),
  56                      'args'                => $this->get_collection_params(),
  57                  ),
  58                  array(
  59                      'methods'             => WP_REST_Server::CREATABLE,
  60                      'callback'            => array( $this, 'create_item' ),
  61                      'permission_callback' => array( $this, 'create_item_permissions_check' ),
  62                      'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
  63                  ),
  64                  'schema' => array( $this, 'get_public_item_schema' ),
  65              )
  66          );
  67  
  68          register_rest_route(
  69              $this->namespace,
  70              '/' . $this->rest_base . '/(?P<id>[\d]+)',
  71              array(
  72                  'args'   => array(
  73                      'id' => array(
  74                          'description' => __( 'Unique identifier for the comment.' ),
  75                          'type'        => 'integer',
  76                      ),
  77                  ),
  78                  array(
  79                      'methods'             => WP_REST_Server::READABLE,
  80                      'callback'            => array( $this, 'get_item' ),
  81                      'permission_callback' => array( $this, 'get_item_permissions_check' ),
  82                      'args'                => array(
  83                          'context'  => $this->get_context_param( array( 'default' => 'view' ) ),
  84                          'password' => array(
  85                              'description' => __( 'The password for the parent post of the comment (if the post is password protected).' ),
  86                              'type'        => 'string',
  87                          ),
  88                      ),
  89                  ),
  90                  array(
  91                      'methods'             => WP_REST_Server::EDITABLE,
  92                      'callback'            => array( $this, 'update_item' ),
  93                      'permission_callback' => array( $this, 'update_item_permissions_check' ),
  94                      'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
  95                  ),
  96                  array(
  97                      'methods'             => WP_REST_Server::DELETABLE,
  98                      'callback'            => array( $this, 'delete_item' ),
  99                      'permission_callback' => array( $this, 'delete_item_permissions_check' ),
 100                      'args'                => array(
 101                          'force'    => array(
 102                              'type'        => 'boolean',
 103                              'default'     => false,
 104                              'description' => __( 'Whether to bypass Trash and force deletion.' ),
 105                          ),
 106                          'password' => array(
 107                              'description' => __( 'The password for the parent post of the comment (if the post is password protected).' ),
 108                              'type'        => 'string',
 109                          ),
 110                      ),
 111                  ),
 112                  'schema' => array( $this, 'get_public_item_schema' ),
 113              )
 114          );
 115      }
 116  
 117      /**
 118       * Checks if a given request has access to read comments.
 119       *
 120       * @since 4.7.0
 121       *
 122       * @param WP_REST_Request $request Full details about the request.
 123       * @return true|WP_Error True if the request has read access, error object otherwise.
 124       */
 125  	public function get_items_permissions_check( $request ) {
 126          $is_note          = 'note' === $request['type'];
 127          $is_edit_context  = 'edit' === $request['context'];
 128          $protected_params = array( 'author', 'author_exclude', 'author_email', 'type', 'status' );
 129          $forbidden_params = array();
 130  
 131          if ( ! empty( $request['post'] ) ) {
 132              foreach ( (array) $request['post'] as $post_id ) {
 133                  $post = get_post( $post_id );
 134  
 135                  if ( ! empty( $post_id ) && $post && ! $this->check_read_post_permission( $post, $request ) ) {
 136                      return new WP_Error(
 137                          'rest_cannot_read_post',
 138                          __( 'Sorry, you are not allowed to read the post for this comment.' ),
 139                          array( 'status' => rest_authorization_required_code() )
 140                      );
 141                  } elseif ( 0 === $post_id && ! current_user_can( 'moderate_comments' ) ) {
 142                      return new WP_Error(
 143                          'rest_cannot_read',
 144                          __( 'Sorry, you are not allowed to read comments without a post.' ),
 145                          array( 'status' => rest_authorization_required_code() )
 146                      );
 147                  }
 148  
 149                  if ( $post && $is_note && ! $this->check_post_type_supports_notes( $post->post_type ) ) {
 150                      if ( current_user_can( 'edit_post', $post->ID ) ) {
 151                          return new WP_Error(
 152                              'rest_comment_not_supported_post_type',
 153                              __( 'Sorry, this post type does not support notes.' ),
 154                              array( 'status' => 403 )
 155                          );
 156                      }
 157  
 158                      foreach ( $protected_params as $param ) {
 159                          if ( 'status' === $param ) {
 160                              if ( 'approve' !== $request[ $param ] ) {
 161                                  $forbidden_params[] = $param;
 162                              }
 163                          } elseif ( 'type' === $param ) {
 164                              if ( 'comment' !== $request[ $param ] ) {
 165                                  $forbidden_params[] = $param;
 166                              }
 167                          } elseif ( ! empty( $request[ $param ] ) ) {
 168                              $forbidden_params[] = $param;
 169                          }
 170                      }
 171                      return new WP_Error(
 172                          'rest_forbidden_param',
 173                          /* translators: %s: List of forbidden parameters. */
 174                          sprintf( __( 'Query parameter not permitted: %s' ), implode( ', ', $forbidden_params ) ),
 175                          array( 'status' => rest_authorization_required_code() )
 176                      );
 177                  }
 178              }
 179          }
 180  
 181          // Re-map edit context capabilities when requesting `note` for a post.
 182          if ( $is_edit_context && $is_note && ! empty( $request['post'] ) ) {
 183              foreach ( (array) $request['post'] as $post_id ) {
 184                  if ( ! current_user_can( 'edit_post', $post_id ) ) {
 185                      return new WP_Error(
 186                          'rest_forbidden_context',
 187                          __( 'Sorry, you are not allowed to edit comments.' ),
 188                          array( 'status' => rest_authorization_required_code() )
 189                      );
 190                  }
 191              }
 192          } elseif ( $is_edit_context && ! current_user_can( 'moderate_comments' ) ) {
 193              return new WP_Error(
 194                  'rest_forbidden_context',
 195                  __( 'Sorry, you are not allowed to edit comments.' ),
 196                  array( 'status' => rest_authorization_required_code() )
 197              );
 198          }
 199  
 200          if ( ! current_user_can( 'edit_posts' ) ) {
 201              foreach ( $protected_params as $param ) {
 202                  if ( 'status' === $param ) {
 203                      if ( 'approve' !== $request[ $param ] ) {
 204                          $forbidden_params[] = $param;
 205                      }
 206                  } elseif ( 'type' === $param ) {
 207                      if ( 'comment' !== $request[ $param ] ) {
 208                          $forbidden_params[] = $param;
 209                      }
 210                  } elseif ( ! empty( $request[ $param ] ) ) {
 211                      $forbidden_params[] = $param;
 212                  }
 213              }
 214  
 215              if ( ! empty( $forbidden_params ) ) {
 216                  return new WP_Error(
 217                      'rest_forbidden_param',
 218                      /* translators: %s: List of forbidden parameters. */
 219                      sprintf( __( 'Query parameter not permitted: %s' ), implode( ', ', $forbidden_params ) ),
 220                      array( 'status' => rest_authorization_required_code() )
 221                  );
 222              }
 223          }
 224  
 225          return true;
 226      }
 227  
 228      /**
 229       * Retrieves a list of comment items.
 230       *
 231       * @since 4.7.0
 232       *
 233       * @param WP_REST_Request $request Full details about the request.
 234       * @return WP_REST_Response|WP_Error Response object on success, or error object on failure.
 235       */
 236  	public function get_items( $request ) {
 237  
 238          // Retrieve the list of registered collection query parameters.
 239          $registered = $this->get_collection_params();
 240  
 241          /*
 242           * This array defines mappings between public API query parameters whose
 243           * values are accepted as-passed, and their internal WP_Query parameter
 244           * name equivalents (some are the same). Only values which are also
 245           * present in $registered will be set.
 246           */
 247          $parameter_mappings = array(
 248              'author'         => 'author__in',
 249              'author_email'   => 'author_email',
 250              'author_exclude' => 'author__not_in',
 251              'exclude'        => 'comment__not_in',
 252              'include'        => 'comment__in',
 253              'offset'         => 'offset',
 254              'order'          => 'order',
 255              'parent'         => 'parent__in',
 256              'parent_exclude' => 'parent__not_in',
 257              'per_page'       => 'number',
 258              'post'           => 'post__in',
 259              'search'         => 'search',
 260              'status'         => 'status',
 261              'type'           => 'type',
 262          );
 263  
 264          $prepared_args = array();
 265  
 266          /*
 267           * For each known parameter which is both registered and present in the request,
 268           * set the parameter's value on the query $prepared_args.
 269           */
 270          foreach ( $parameter_mappings as $api_param => $wp_param ) {
 271              if ( isset( $registered[ $api_param ], $request[ $api_param ] ) ) {
 272                  $prepared_args[ $wp_param ] = $request[ $api_param ];
 273              }
 274          }
 275  
 276          // Ensure certain parameter values default to empty strings.
 277          foreach ( array( 'author_email', 'search' ) as $param ) {
 278              if ( ! isset( $prepared_args[ $param ] ) ) {
 279                  $prepared_args[ $param ] = '';
 280              }
 281          }
 282  
 283          if ( isset( $registered['orderby'] ) ) {
 284              $prepared_args['orderby'] = $this->normalize_query_param( $request['orderby'] );
 285          }
 286  
 287          $prepared_args['no_found_rows'] = false;
 288  
 289          $prepared_args['update_comment_post_cache'] = true;
 290  
 291          $prepared_args['date_query'] = array();
 292  
 293          // Set before into date query. Date query must be specified as an array of an array.
 294          if ( isset( $registered['before'], $request['before'] ) ) {
 295              $prepared_args['date_query'][0]['before'] = $request['before'];
 296          }
 297  
 298          // Set after into date query. Date query must be specified as an array of an array.
 299          if ( isset( $registered['after'], $request['after'] ) ) {
 300              $prepared_args['date_query'][0]['after'] = $request['after'];
 301          }
 302  
 303          if ( isset( $registered['page'] ) && empty( $request['offset'] ) ) {
 304              $prepared_args['offset'] = $prepared_args['number'] * ( absint( $request['page'] ) - 1 );
 305          }
 306  
 307          $is_head_request = $request->is_method( 'HEAD' );
 308          if ( $is_head_request ) {
 309              // Force the 'fields' argument. For HEAD requests, only post IDs are required to calculate pagination.
 310              $prepared_args['fields'] = 'ids';
 311              // Disable priming comment meta for HEAD requests to improve performance.
 312              $prepared_args['update_comment_meta_cache'] = false;
 313          }
 314  
 315          /**
 316           * Filters WP_Comment_Query arguments when querying comments via the REST API.
 317           *
 318           * @since 4.7.0
 319           *
 320           * @link https://developer.wordpress.org/reference/classes/wp_comment_query/
 321           *
 322           * @param array           $prepared_args Array of arguments for WP_Comment_Query.
 323           * @param WP_REST_Request $request       The REST API request.
 324           */
 325          $prepared_args = apply_filters( 'rest_comment_query', $prepared_args, $request );
 326  
 327          $query        = new WP_Comment_Query();
 328          $query_result = $query->query( $prepared_args );
 329  
 330          if ( ! $is_head_request ) {
 331              $comments = array();
 332  
 333              foreach ( $query_result as $comment ) {
 334                  if ( ! $this->check_read_permission( $comment, $request ) ) {
 335                      continue;
 336                  }
 337  
 338                  $data       = $this->prepare_item_for_response( $comment, $request );
 339                  $comments[] = $this->prepare_response_for_collection( $data );
 340              }
 341          }
 342  
 343          $total_comments = (int) $query->found_comments;
 344          $max_pages      = (int) $query->max_num_pages;
 345  
 346          if ( $total_comments < 1 ) {
 347              // Out-of-bounds, run the query without pagination/offset to get the total count.
 348              unset( $prepared_args['number'], $prepared_args['offset'] );
 349  
 350              $query                                      = new WP_Comment_Query();
 351              $prepared_args['count']                     = true;
 352              $prepared_args['orderby']                   = 'none';
 353              $prepared_args['update_comment_meta_cache'] = false;
 354  
 355              $total_comments = $query->query( $prepared_args );
 356              $max_pages      = (int) ceil( $total_comments / $request['per_page'] );
 357          }
 358  
 359          $response = $is_head_request ? new WP_REST_Response( array() ) : rest_ensure_response( $comments );
 360          $response->header( 'X-WP-Total', (string) $total_comments );
 361          $response->header( 'X-WP-TotalPages', (string) $max_pages );
 362  
 363          $base = add_query_arg( urlencode_deep( $request->get_query_params() ), rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ) );
 364  
 365          if ( $request['page'] > 1 ) {
 366              $prev_page = $request['page'] - 1;
 367  
 368              if ( $prev_page > $max_pages ) {
 369                  $prev_page = $max_pages;
 370              }
 371  
 372              $prev_link = add_query_arg( 'page', $prev_page, $base );
 373              $response->link_header( 'prev', $prev_link );
 374          }
 375  
 376          if ( $max_pages > $request['page'] ) {
 377              $next_page = $request['page'] + 1;
 378              $next_link = add_query_arg( 'page', $next_page, $base );
 379  
 380              $response->link_header( 'next', $next_link );
 381          }
 382  
 383          return $response;
 384      }
 385  
 386      /**
 387       * Get the comment, if the ID is valid.
 388       *
 389       * @since 4.7.2
 390       *
 391       * @param int $id Supplied ID.
 392       * @return WP_Comment|WP_Error Comment object if ID is valid, WP_Error otherwise.
 393       */
 394  	protected function get_comment( $id ) {
 395          $error = new WP_Error(
 396              'rest_comment_invalid_id',
 397              __( 'Invalid comment ID.' ),
 398              array( 'status' => 404 )
 399          );
 400  
 401          if ( (int) $id <= 0 ) {
 402              return $error;
 403          }
 404  
 405          $id      = (int) $id;
 406          $comment = get_comment( $id );
 407          if ( empty( $comment ) ) {
 408              return $error;
 409          }
 410  
 411          if ( ! empty( $comment->comment_post_ID ) ) {
 412              $post = get_post( (int) $comment->comment_post_ID );
 413  
 414              if ( empty( $post ) ) {
 415                  return new WP_Error(
 416                      'rest_post_invalid_id',
 417                      __( 'Invalid post ID.' ),
 418                      array( 'status' => 404 )
 419                  );
 420              }
 421          }
 422  
 423          return $comment;
 424      }
 425  
 426      /**
 427       * Checks if a given request has access to read the comment.
 428       *
 429       * @since 4.7.0
 430       *
 431       * @param WP_REST_Request $request Full details about the request.
 432       * @return true|WP_Error True if the request has read access for the item, error object otherwise.
 433       */
 434  	public function get_item_permissions_check( $request ) {
 435          $comment = $this->get_comment( $request['id'] );
 436          if ( is_wp_error( $comment ) ) {
 437              return $comment;
 438          }
 439  
 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' );
 442          if ( ! empty( $request['context'] ) && 'edit' === $request['context'] && ! current_user_can( ...$edit_cap ) ) {
 443              return new WP_Error(
 444                  'rest_forbidden_context',
 445                  __( 'Sorry, you are not allowed to edit comments.' ),
 446                  array( 'status' => rest_authorization_required_code() )
 447              );
 448          }
 449  
 450          $post = get_post( $comment->comment_post_ID );
 451  
 452          if ( ! $this->check_read_permission( $comment, $request ) ) {
 453              return new WP_Error(
 454                  'rest_cannot_read',
 455                  __( 'Sorry, you are not allowed to read this comment.' ),
 456                  array( 'status' => rest_authorization_required_code() )
 457              );
 458          }
 459  
 460          if ( $post && ! $this->check_read_post_permission( $post, $request ) ) {
 461              return new WP_Error(
 462                  'rest_cannot_read_post',
 463                  __( 'Sorry, you are not allowed to read the post for this comment.' ),
 464                  array( 'status' => rest_authorization_required_code() )
 465              );
 466          }
 467  
 468          return true;
 469      }
 470  
 471      /**
 472       * Retrieves a comment.
 473       *
 474       * @since 4.7.0
 475       *
 476       * @param WP_REST_Request $request Full details about the request.
 477       * @return WP_REST_Response|WP_Error Response object on success, or error object on failure.
 478       */
 479  	public function get_item( $request ) {
 480          $comment = $this->get_comment( $request['id'] );
 481          if ( is_wp_error( $comment ) ) {
 482              return $comment;
 483          }
 484  
 485          $data     = $this->prepare_item_for_response( $comment, $request );
 486          $response = rest_ensure_response( $data );
 487  
 488          return $response;
 489      }
 490  
 491      /**
 492       * Checks if a given request has access to create a comment.
 493       *
 494       * @since 4.7.0
 495       *
 496       * @param WP_REST_Request $request Full details about the request.
 497       * @return true|WP_Error True if the request has access to create items, error object otherwise.
 498       */
 499  	public function create_item_permissions_check( $request ) {
 500          $is_note = ! empty( $request['type'] ) && 'note' === $request['type'];
 501  
 502          if ( ! is_user_logged_in() && $is_note ) {
 503              return new WP_Error(
 504                  'rest_comment_login_required',
 505                  __( 'Sorry, you must be logged in to comment.' ),
 506                  array( 'status' => 401 )
 507              );
 508          }
 509  
 510          if ( ! is_user_logged_in() ) {
 511              if ( get_option( 'comment_registration' ) ) {
 512                  return new WP_Error(
 513                      'rest_comment_login_required',
 514                      __( 'Sorry, you must be logged in to comment.' ),
 515                      array( 'status' => 401 )
 516                  );
 517              }
 518  
 519              /**
 520               * Filters whether comments can be created via the REST API without authentication.
 521               *
 522               * Enables creating comments for anonymous users.
 523               *
 524               * @since 4.7.0
 525               *
 526               * @param bool $allow_anonymous Whether to allow anonymous comments to
 527               *                              be created. Default `false`.
 528               * @param WP_REST_Request $request Request used to generate the
 529               *                                 response.
 530               */
 531              $allow_anonymous = apply_filters( 'rest_allow_anonymous_comments', false, $request );
 532  
 533              if ( ! $allow_anonymous ) {
 534                  return new WP_Error(
 535                      'rest_comment_login_required',
 536                      __( 'Sorry, you must be logged in to comment.' ),
 537                      array( 'status' => 401 )
 538                  );
 539              }
 540          }
 541  
 542          // Limit who can set comment `author`, `author_ip` or `status` to anything other than the default.
 543          if ( isset( $request['author'] ) && get_current_user_id() !== $request['author'] && ! current_user_can( 'moderate_comments' ) ) {
 544              return new WP_Error(
 545                  'rest_comment_invalid_author',
 546                  /* translators: %s: Request parameter. */
 547                  sprintf( __( "Sorry, you are not allowed to edit '%s' for comments." ), 'author' ),
 548                  array( 'status' => rest_authorization_required_code() )
 549              );
 550          }
 551  
 552          if ( isset( $request['author_ip'] ) && ! current_user_can( 'moderate_comments' ) ) {
 553              if ( empty( $_SERVER['REMOTE_ADDR'] ) || $request['author_ip'] !== $_SERVER['REMOTE_ADDR'] ) {
 554                  return new WP_Error(
 555                      'rest_comment_invalid_author_ip',
 556                      /* translators: %s: Request parameter. */
 557                      sprintf( __( "Sorry, you are not allowed to edit '%s' for comments." ), 'author_ip' ),
 558                      array( 'status' => rest_authorization_required_code() )
 559                  );
 560              }
 561          }
 562  
 563          if ( $is_note && ! empty( $request['post'] ) && ! current_user_can( 'edit_post', (int) $request['post'] ) ) {
 564              return new WP_Error(
 565                  'rest_cannot_create_note',
 566                  __( 'Sorry, you are not allowed to create notes for this post.' ),
 567                  array( 'status' => rest_authorization_required_code() )
 568              );
 569          }
 570  
 571          $edit_cap = $is_note ? array( 'edit_post', (int) $request['post'] ) : array( 'moderate_comments' );
 572          if ( isset( $request['status'] ) && ! current_user_can( ...$edit_cap ) ) {
 573              return new WP_Error(
 574                  'rest_comment_invalid_status',
 575                  /* translators: %s: Request parameter. */
 576                  sprintf( __( "Sorry, you are not allowed to edit '%s' for comments." ), 'status' ),
 577                  array( 'status' => rest_authorization_required_code() )
 578              );
 579          }
 580  
 581          if ( empty( $request['post'] ) ) {
 582              return new WP_Error(
 583                  'rest_comment_invalid_post_id',
 584                  __( 'Sorry, you are not allowed to create this comment without a post.' ),
 585                  array( 'status' => 403 )
 586              );
 587          }
 588  
 589          $post = get_post( (int) $request['post'] );
 590  
 591          if ( ! $post ) {
 592              return new WP_Error(
 593                  'rest_comment_invalid_post_id',
 594                  __( 'Sorry, you are not allowed to create this comment without a post.' ),
 595                  array( 'status' => 403 )
 596              );
 597          }
 598  
 599          if ( $is_note && ! $this->check_post_type_supports_notes( $post->post_type ) ) {
 600              return new WP_Error(
 601                  'rest_comment_not_supported_post_type',
 602                  __( 'Sorry, this post type does not support notes.' ),
 603                  array( 'status' => 403 )
 604              );
 605          }
 606  
 607          if ( 'draft' === $post->post_status && ! $is_note ) {
 608              return new WP_Error(
 609                  'rest_comment_draft_post',
 610                  __( 'Sorry, you are not allowed to create a comment on this post.' ),
 611                  array( 'status' => 403 )
 612              );
 613          }
 614  
 615          if ( 'trash' === $post->post_status ) {
 616              return new WP_Error(
 617                  'rest_comment_trash_post',
 618                  __( 'Sorry, you are not allowed to create a comment on this post.' ),
 619                  array( 'status' => 403 )
 620              );
 621          }
 622  
 623          if ( ! $this->check_read_post_permission( $post, $request ) ) {
 624              return new WP_Error(
 625                  'rest_cannot_read_post',
 626                  __( 'Sorry, you are not allowed to read the post for this comment.' ),
 627                  array( 'status' => rest_authorization_required_code() )
 628              );
 629          }
 630  
 631          if ( ! comments_open( $post->ID ) && ! $is_note ) {
 632              return new WP_Error(
 633                  'rest_comment_closed',
 634                  __( 'Sorry, comments are closed for this item.' ),
 635                  array( 'status' => 403 )
 636              );
 637          }
 638  
 639          return true;
 640      }
 641  
 642      /**
 643       * Creates a comment.
 644       *
 645       * @since 4.7.0
 646       *
 647       * @param WP_REST_Request $request Full details about the request.
 648       * @return WP_REST_Response|WP_Error Response object on success, or error object on failure.
 649       */
 650  	public function create_item( $request ) {
 651          if ( ! empty( $request['id'] ) ) {
 652              return new WP_Error(
 653                  'rest_comment_exists',
 654                  __( 'Cannot create existing comment.' ),
 655                  array( 'status' => 400 )
 656              );
 657          }
 658  
 659          // Do not allow comments to be created with a non-core type.
 660          if ( ! empty( $request['type'] ) && ! in_array( $request['type'], array( 'comment', 'note' ), true ) ) {
 661              return new WP_Error(
 662                  'rest_invalid_comment_type',
 663                  __( 'Cannot create a comment with that type.' ),
 664                  array( 'status' => 400 )
 665              );
 666          }
 667  
 668          $prepared_comment = $this->prepare_item_for_database( $request );
 669          if ( is_wp_error( $prepared_comment ) ) {
 670              return $prepared_comment;
 671          }
 672  
 673          $prepared_comment['comment_type'] = $request['type'];
 674  
 675          if ( ! isset( $prepared_comment['comment_content'] ) ) {
 676              $prepared_comment['comment_content'] = '';
 677          }
 678  
 679          // Include note metadata into check_is_comment_content_allowed.
 680          if ( isset( $request['meta']['_wp_note_status'] ) ) {
 681              $prepared_comment['meta']['_wp_note_status'] = $request['meta']['_wp_note_status'];
 682          }
 683  
 684          if ( ! $this->check_is_comment_content_allowed( $prepared_comment ) ) {
 685              return new WP_Error(
 686                  'rest_comment_content_invalid',
 687                  __( 'Invalid comment content.' ),
 688                  array( 'status' => 400 )
 689              );
 690          }
 691  
 692          // Setting remaining values before wp_insert_comment so we can use wp_allow_comment().
 693          if ( ! isset( $prepared_comment['comment_date_gmt'] ) ) {
 694              $prepared_comment['comment_date_gmt'] = current_time( 'mysql', true );
 695          }
 696  
 697          // Set author data if the user's logged in.
 698          $missing_author = empty( $prepared_comment['user_id'] )
 699              && empty( $prepared_comment['comment_author'] )
 700              && empty( $prepared_comment['comment_author_email'] )
 701              && empty( $prepared_comment['comment_author_url'] );
 702  
 703          if ( is_user_logged_in() && $missing_author ) {
 704              $user = wp_get_current_user();
 705  
 706              $prepared_comment['user_id']              = $user->ID;
 707              $prepared_comment['comment_author']       = $user->display_name;
 708              $prepared_comment['comment_author_email'] = $user->user_email;
 709              $prepared_comment['comment_author_url']   = $user->user_url;
 710          }
 711  
 712          // Honor the discussion setting that requires a name and email address of the comment author.
 713          if ( get_option( 'require_name_email' ) ) {
 714              if ( empty( $prepared_comment['comment_author'] ) || empty( $prepared_comment['comment_author_email'] ) ) {
 715                  return new WP_Error(
 716                      'rest_comment_author_data_required',
 717                      __( 'Creating a comment requires valid author name and email values.' ),
 718                      array( 'status' => 400 )
 719                  );
 720              }
 721          }
 722  
 723          if ( ! isset( $prepared_comment['comment_author_email'] ) ) {
 724              $prepared_comment['comment_author_email'] = '';
 725          }
 726  
 727          if ( ! isset( $prepared_comment['comment_author_url'] ) ) {
 728              $prepared_comment['comment_author_url'] = '';
 729          }
 730  
 731          if ( ! isset( $prepared_comment['comment_agent'] ) ) {
 732              $prepared_comment['comment_agent'] = '';
 733          }
 734  
 735          $check_comment_lengths = wp_check_comment_data_max_lengths( $prepared_comment );
 736  
 737          if ( is_wp_error( $check_comment_lengths ) ) {
 738              $error_code = $check_comment_lengths->get_error_code();
 739              return new WP_Error(
 740                  $error_code,
 741                  __( 'Comment field exceeds maximum length allowed.' ),
 742                  array( 'status' => 400 )
 743              );
 744          }
 745  
 746          // Don't check for duplicates or flooding for notes.
 747          $prepared_comment['comment_approved'] =
 748              'note' === $prepared_comment['comment_type'] ?
 749              '1' :
 750              wp_allow_comment( $prepared_comment, true );
 751  
 752          if ( is_wp_error( $prepared_comment['comment_approved'] ) ) {
 753              $error_code    = $prepared_comment['comment_approved']->get_error_code();
 754              $error_message = $prepared_comment['comment_approved']->get_error_message();
 755  
 756              if ( 'comment_duplicate' === $error_code ) {
 757                  return new WP_Error(
 758                      $error_code,
 759                      $error_message,
 760                      array( 'status' => 409 )
 761                  );
 762              }
 763  
 764              if ( 'comment_flood' === $error_code ) {
 765                  return new WP_Error(
 766                      $error_code,
 767                      $error_message,
 768                      array( 'status' => 400 )
 769                  );
 770              }
 771  
 772              return $prepared_comment['comment_approved'];
 773          }
 774  
 775          /**
 776           * Filters a comment before it is inserted via the REST API.
 777           *
 778           * Allows modification of the comment right before it is inserted via wp_insert_comment().
 779           * Returning a WP_Error value from the filter will short-circuit insertion and allow
 780           * skipping further processing.
 781           *
 782           * @since 4.7.0
 783           * @since 4.8.0 `$prepared_comment` can now be a WP_Error to short-circuit insertion.
 784           *
 785           * @param array|WP_Error  $prepared_comment The prepared comment data for wp_insert_comment().
 786           * @param WP_REST_Request $request          Request used to insert the comment.
 787           */
 788          $prepared_comment = apply_filters( 'rest_pre_insert_comment', $prepared_comment, $request );
 789          if ( is_wp_error( $prepared_comment ) ) {
 790              return $prepared_comment;
 791          }
 792  
 793          $comment_id = wp_insert_comment( wp_filter_comment( wp_slash( (array) $prepared_comment ) ) );
 794  
 795          if ( ! $comment_id ) {
 796              return new WP_Error(
 797                  'rest_comment_failed_create',
 798                  __( 'Creating comment failed.' ),
 799                  array( 'status' => 500 )
 800              );
 801          }
 802  
 803          if ( isset( $request['status'] ) ) {
 804              $this->handle_status_param( $request['status'], $comment_id );
 805          }
 806  
 807          $comment = get_comment( $comment_id );
 808  
 809          /**
 810           * Fires after a comment is created or updated via the REST API.
 811           *
 812           * @since 4.7.0
 813           *
 814           * @param WP_Comment      $comment  Inserted or updated comment object.
 815           * @param WP_REST_Request $request  Request object.
 816           * @param bool            $creating True when creating a comment, false
 817           *                                  when updating.
 818           */
 819          do_action( 'rest_insert_comment', $comment, $request, true );
 820  
 821          $schema = $this->get_item_schema();
 822  
 823          if ( ! empty( $schema['properties']['meta'] ) && isset( $request['meta'] ) ) {
 824              $meta_update = $this->meta->update_value( $request['meta'], $comment_id );
 825  
 826              if ( is_wp_error( $meta_update ) ) {
 827                  return $meta_update;
 828              }
 829          }
 830  
 831          $fields_update = $this->update_additional_fields_for_object( $comment, $request );
 832  
 833          if ( is_wp_error( $fields_update ) ) {
 834              return $fields_update;
 835          }
 836  
 837          $context = current_user_can( 'moderate_comments' ) ? 'edit' : 'view';
 838          $request->set_param( 'context', $context );
 839  
 840          /**
 841           * Fires completely after a comment is created or updated via the REST API.
 842           *
 843           * @since 5.0.0
 844           *
 845           * @param WP_Comment      $comment  Inserted or updated comment object.
 846           * @param WP_REST_Request $request  Request object.
 847           * @param bool            $creating True when creating a comment, false
 848           *                                  when updating.
 849           */
 850          do_action( 'rest_after_insert_comment', $comment, $request, true );
 851  
 852          $response = $this->prepare_item_for_response( $comment, $request );
 853          $response = rest_ensure_response( $response );
 854  
 855          $response->set_status( 201 );
 856          $response->header( 'Location', rest_url( sprintf( '%s/%s/%d', $this->namespace, $this->rest_base, $comment_id ) ) );
 857  
 858          return $response;
 859      }
 860  
 861      /**
 862       * Checks if a given REST request has access to update a comment.
 863       *
 864       * @since 4.7.0
 865       *
 866       * @param WP_REST_Request $request Full details about the request.
 867       * @return true|WP_Error True if the request has access to update the item, error object otherwise.
 868       */
 869  	public function update_item_permissions_check( $request ) {
 870          $comment = $this->get_comment( $request['id'] );
 871          if ( is_wp_error( $comment ) ) {
 872              return $comment;
 873          }
 874  
 875          if ( ! $this->check_edit_permission( $comment ) ) {
 876              return new WP_Error(
 877                  'rest_cannot_edit',
 878                  __( 'Sorry, you are not allowed to edit this comment.' ),
 879                  array( 'status' => rest_authorization_required_code() )
 880              );
 881          }
 882  
 883          return true;
 884      }
 885  
 886      /**
 887       * Updates a comment.
 888       *
 889       * @since 4.7.0
 890       *
 891       * @param WP_REST_Request $request Full details about the request.
 892       * @return WP_REST_Response|WP_Error Response object on success, or error object on failure.
 893       */
 894  	public function update_item( $request ) {
 895          $comment = $this->get_comment( $request['id'] );
 896          if ( is_wp_error( $comment ) ) {
 897              return $comment;
 898          }
 899  
 900          $id = $comment->comment_ID;
 901  
 902          if ( isset( $request['type'] ) && get_comment_type( $id ) !== $request['type'] ) {
 903              return new WP_Error(
 904                  'rest_comment_invalid_type',
 905                  __( 'Sorry, you are not allowed to change the comment type.' ),
 906                  array( 'status' => 404 )
 907              );
 908          }
 909  
 910          $prepared_args = $this->prepare_item_for_database( $request );
 911  
 912          if ( is_wp_error( $prepared_args ) ) {
 913              return $prepared_args;
 914          }
 915  
 916          if ( ! empty( $prepared_args['comment_post_ID'] ) ) {
 917              $post = get_post( $prepared_args['comment_post_ID'] );
 918  
 919              if ( empty( $post ) ) {
 920                  return new WP_Error(
 921                      'rest_comment_invalid_post_id',
 922                      __( 'Invalid post ID.' ),
 923                      array( 'status' => 403 )
 924                  );
 925              }
 926          }
 927  
 928          if ( empty( $prepared_args ) && isset( $request['status'] ) ) {
 929              // Only the comment status is being changed.
 930              $change = $this->handle_status_param( $request['status'], $id );
 931  
 932              if ( ! $change ) {
 933                  return new WP_Error(
 934                      'rest_comment_failed_edit',
 935                      __( 'Updating comment status failed.' ),
 936                      array( 'status' => 500 )
 937                  );
 938              }
 939          } elseif ( ! empty( $prepared_args ) ) {
 940              if ( is_wp_error( $prepared_args ) ) {
 941                  return $prepared_args;
 942              }
 943              if ( ! $this->check_is_comment_content_allowed( $prepared_args ) ) {
 944                  return new WP_Error(
 945                      'rest_comment_content_invalid',
 946                      __( 'Invalid comment content.' ),
 947                      array( 'status' => 400 )
 948                  );
 949              }
 950  
 951              $prepared_args['comment_ID'] = $id;
 952  
 953              $check_comment_lengths = wp_check_comment_data_max_lengths( $prepared_args );
 954  
 955              if ( is_wp_error( $check_comment_lengths ) ) {
 956                  $error_code = $check_comment_lengths->get_error_code();
 957                  return new WP_Error(
 958                      $error_code,
 959                      __( 'Comment field exceeds maximum length allowed.' ),
 960                      array( 'status' => 400 )
 961                  );
 962              }
 963  
 964              $updated = wp_update_comment( wp_slash( (array) $prepared_args ), true );
 965  
 966              if ( is_wp_error( $updated ) ) {
 967                  return new WP_Error(
 968                      'rest_comment_failed_edit',
 969                      __( 'Updating comment failed.' ),
 970                      array( 'status' => 500 )
 971                  );
 972              }
 973  
 974              if ( isset( $request['status'] ) ) {
 975                  $this->handle_status_param( $request['status'], $id );
 976              }
 977          }
 978  
 979          $comment = get_comment( $id );
 980  
 981          /** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php */
 982          do_action( 'rest_insert_comment', $comment, $request, false );
 983  
 984          $schema = $this->get_item_schema();
 985  
 986          if ( ! empty( $schema['properties']['meta'] ) && isset( $request['meta'] ) ) {
 987              $meta_update = $this->meta->update_value( $request['meta'], $id );
 988  
 989              if ( is_wp_error( $meta_update ) ) {
 990                  return $meta_update;
 991              }
 992          }
 993  
 994          $fields_update = $this->update_additional_fields_for_object( $comment, $request );
 995  
 996          if ( is_wp_error( $fields_update ) ) {
 997              return $fields_update;
 998          }
 999  
1000          $request->set_param( 'context', 'edit' );
1001  
1002          /** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php */
1003          do_action( 'rest_after_insert_comment', $comment, $request, false );
1004  
1005          $response = $this->prepare_item_for_response( $comment, $request );
1006  
1007          return rest_ensure_response( $response );
1008      }
1009  
1010      /**
1011       * Checks if a given request has access to delete a comment.
1012       *
1013       * @since 4.7.0
1014       *
1015       * @param WP_REST_Request $request Full details about the request.
1016       * @return true|WP_Error True if the request has access to delete the item, error object otherwise.
1017       */
1018  	public function delete_item_permissions_check( $request ) {
1019          $comment = $this->get_comment( $request['id'] );
1020          if ( is_wp_error( $comment ) ) {
1021              return $comment;
1022          }
1023  
1024          if ( ! $this->check_edit_permission( $comment ) ) {
1025              return new WP_Error(
1026                  'rest_cannot_delete',
1027                  __( 'Sorry, you are not allowed to delete this comment.' ),
1028                  array( 'status' => rest_authorization_required_code() )
1029              );
1030          }
1031          return true;
1032      }
1033  
1034      /**
1035       * Deletes a comment.
1036       *
1037       * @since 4.7.0
1038       *
1039       * @param WP_REST_Request $request Full details about the request.
1040       * @return WP_REST_Response|WP_Error Response object on success, or error object on failure.
1041       */
1042  	public function delete_item( $request ) {
1043          $comment = $this->get_comment( $request['id'] );
1044          if ( is_wp_error( $comment ) ) {
1045              return $comment;
1046          }
1047  
1048          $force = isset( $request['force'] ) ? (bool) $request['force'] : false;
1049  
1050          /**
1051           * Filters whether a comment can be trashed via the REST API.
1052           *
1053           * Return false to disable trash support for the comment.
1054           *
1055           * @since 4.7.0
1056           *
1057           * @param bool       $supports_trash Whether the comment supports trashing.
1058           * @param WP_Comment $comment        The comment object being considered for trashing support.
1059           */
1060          $supports_trash = apply_filters( 'rest_comment_trashable', ( EMPTY_TRASH_DAYS > 0 ), $comment );
1061  
1062          $request->set_param( 'context', 'edit' );
1063  
1064          if ( $force ) {
1065              $previous = $this->prepare_item_for_response( $comment, $request );
1066              $result   = wp_delete_comment( $comment->comment_ID, true );
1067              $response = new WP_REST_Response();
1068              $response->set_data(
1069                  array(
1070                      'deleted'  => true,
1071                      'previous' => $previous->get_data(),
1072                  )
1073              );
1074          } else {
1075              // If this type doesn't support trashing, error out.
1076              if ( ! $supports_trash ) {
1077                  return new WP_Error(
1078                      'rest_trash_not_supported',
1079                      /* translators: %s: force=true */
1080                      sprintf( __( "The comment does not support trashing. Set '%s' to delete." ), 'force=true' ),
1081                      array( 'status' => 501 )
1082                  );
1083              }
1084  
1085              if ( 'trash' === $comment->comment_approved ) {
1086                  return new WP_Error(
1087                      'rest_already_trashed',
1088                      __( 'The comment has already been trashed.' ),
1089                      array( 'status' => 410 )
1090                  );
1091              }
1092  
1093              $result   = wp_trash_comment( $comment->comment_ID );
1094              $comment  = get_comment( $comment->comment_ID );
1095              $response = $this->prepare_item_for_response( $comment, $request );
1096          }
1097  
1098          if ( ! $result ) {
1099              return new WP_Error(
1100                  'rest_cannot_delete',
1101                  __( 'The comment cannot be deleted.' ),
1102                  array( 'status' => 500 )
1103              );
1104          }
1105  
1106          /**
1107           * Fires after a comment is deleted via the REST API.
1108           *
1109           * @since 4.7.0
1110           *
1111           * @param WP_Comment       $comment  The deleted comment data.
1112           * @param WP_REST_Response $response The response returned from the API.
1113           * @param WP_REST_Request  $request  The request sent to the API.
1114           */
1115          do_action( 'rest_delete_comment', $comment, $response, $request );
1116  
1117          return $response;
1118      }
1119  
1120      /**
1121       * Prepares a single comment output for response.
1122       *
1123       * @since 4.7.0
1124       * @since 5.9.0 Renamed `$comment` to `$item` to match parent class for PHP 8 named parameter support.
1125       *
1126       * @param WP_Comment      $item    Comment object.
1127       * @param WP_REST_Request $request Request object.
1128       * @return WP_REST_Response Response object.
1129       */
1130  	public function prepare_item_for_response( $item, $request ) {
1131          // Restores the more descriptive, specific name for use within this method.
1132          $comment = $item;
1133  
1134          // Don't prepare the response body for HEAD requests.
1135          if ( $request->is_method( 'HEAD' ) ) {
1136              /** This filter is documented in wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php */
1137              return apply_filters( 'rest_prepare_comment', new WP_REST_Response( array() ), $comment, $request );
1138          }
1139  
1140          $fields = $this->get_fields_for_response( $request );
1141          $data   = array();
1142  
1143          if ( in_array( 'id', $fields, true ) ) {
1144              $data['id'] = (int) $comment->comment_ID;
1145          }
1146  
1147          if ( in_array( 'post', $fields, true ) ) {
1148              $data['post'] = (int) $comment->comment_post_ID;
1149          }
1150  
1151          if ( in_array( 'parent', $fields, true ) ) {
1152              $data['parent'] = (int) $comment->comment_parent;
1153          }
1154  
1155          if ( in_array( 'author', $fields, true ) ) {
1156              $data['author'] = (int) $comment->user_id;
1157          }
1158  
1159          if ( in_array( 'author_name', $fields, true ) ) {
1160              $data['author_name'] = $comment->comment_author;
1161          }
1162  
1163          if ( in_array( 'author_email', $fields, true ) ) {
1164              $data['author_email'] = $comment->comment_author_email;
1165          }
1166  
1167          if ( in_array( 'author_url', $fields, true ) ) {
1168              $data['author_url'] = $comment->comment_author_url;
1169          }
1170  
1171          if ( in_array( 'author_ip', $fields, true ) ) {
1172              $data['author_ip'] = $comment->comment_author_IP;
1173          }
1174  
1175          if ( in_array( 'author_user_agent', $fields, true ) ) {
1176              $data['author_user_agent'] = $comment->comment_agent;
1177          }
1178  
1179          if ( in_array( 'date', $fields, true ) ) {
1180              $data['date'] = mysql_to_rfc3339( $comment->comment_date );
1181          }
1182  
1183          if ( in_array( 'date_gmt', $fields, true ) ) {
1184              $data['date_gmt'] = mysql_to_rfc3339( $comment->comment_date_gmt );
1185          }
1186  
1187          if ( in_array( 'content', $fields, true ) ) {
1188              $data['content'] = array(
1189                  /** This filter is documented in wp-includes/comment-template.php */
1190                  'rendered' => apply_filters( 'comment_text', $comment->comment_content, $comment, array() ),
1191                  'raw'      => $comment->comment_content,
1192              );
1193          }
1194  
1195          if ( in_array( 'link', $fields, true ) ) {
1196              $data['link'] = get_comment_link( $comment );
1197          }
1198  
1199          if ( in_array( 'status', $fields, true ) ) {
1200              $data['status'] = $this->prepare_status_response( $comment->comment_approved );
1201          }
1202  
1203          if ( in_array( 'type', $fields, true ) ) {
1204              $data['type'] = get_comment_type( $comment->comment_ID );
1205          }
1206  
1207          if ( in_array( 'author_avatar_urls', $fields, true ) ) {
1208              $data['author_avatar_urls'] = rest_get_avatar_urls( $comment );
1209          }
1210  
1211          if ( in_array( 'meta', $fields, true ) ) {
1212              $data['meta'] = $this->meta->get_value( $comment->comment_ID, $request );
1213          }
1214  
1215          $context = ! empty( $request['context'] ) ? $request['context'] : 'view';
1216          $data    = $this->add_additional_fields_to_object( $data, $request );
1217          $data    = $this->filter_response_by_context( $data, $context );
1218  
1219          // Wrap the data in a response object.
1220          $response = rest_ensure_response( $data );
1221  
1222          if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) {
1223              $response->add_links( $this->prepare_links( $comment ) );
1224          }
1225  
1226          /**
1227           * Filters a comment returned from the REST API.
1228           *
1229           * Allows modification of the comment right before it is returned.
1230           *
1231           * @since 4.7.0
1232           *
1233           * @param WP_REST_Response  $response The response object.
1234           * @param WP_Comment        $comment  The original comment object.
1235           * @param WP_REST_Request   $request  Request used to generate the response.
1236           */
1237          return apply_filters( 'rest_prepare_comment', $response, $comment, $request );
1238      }
1239  
1240      /**
1241       * Prepares links for the request.
1242       *
1243       * @since 4.7.0
1244       *
1245       * @param WP_Comment $comment Comment object.
1246       * @return array Links for the given comment.
1247       */
1248  	protected function prepare_links( $comment ) {
1249          $links = array(
1250              'self'       => array(
1251                  'href' => rest_url( sprintf( '%s/%s/%d', $this->namespace, $this->rest_base, $comment->comment_ID ) ),
1252              ),
1253              'collection' => array(
1254                  'href' => rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ),
1255              ),
1256          );
1257  
1258          if ( 0 !== (int) $comment->user_id ) {
1259              $links['author'] = array(
1260                  'href'       => rest_url( 'wp/v2/users/' . $comment->user_id ),
1261                  'embeddable' => true,
1262              );
1263          }
1264  
1265          if ( 0 !== (int) $comment->comment_post_ID ) {
1266              $post       = get_post( $comment->comment_post_ID );
1267              $post_route = rest_get_route_for_post( $post );
1268  
1269              if ( ! empty( $post->ID ) && $post_route ) {
1270                  $links['up'] = array(
1271                      'href'       => rest_url( $post_route ),
1272                      'embeddable' => true,
1273                      'post_type'  => $post->post_type,
1274                  );
1275              }
1276          }
1277  
1278          if ( 0 !== (int) $comment->comment_parent ) {
1279              $links['in-reply-to'] = array(
1280                  'href'       => rest_url( sprintf( '%s/%s/%d', $this->namespace, $this->rest_base, $comment->comment_parent ) ),
1281                  'embeddable' => true,
1282              );
1283          }
1284  
1285          // Only grab one comment to verify the comment has children.
1286          $comment_children = $comment->get_children(
1287              array(
1288                  'count'   => true,
1289                  'orderby' => 'none',
1290                  'type'    => 'all',
1291              )
1292          );
1293  
1294          if ( ! empty( $comment_children ) ) {
1295              $args = array(
1296                  'parent' => $comment->comment_ID,
1297              );
1298  
1299              $rest_url = add_query_arg( $args, rest_url( $this->namespace . '/' . $this->rest_base ) );
1300  
1301              $links['children'] = array(
1302                  'href'       => $rest_url,
1303                  'embeddable' => true,
1304              );
1305          }
1306  
1307          // Embedding children for notes requires `type` and `status` inheritance.
1308          if ( isset( $links['children'] ) && 'note' === $comment->comment_type ) {
1309              $args = array(
1310                  'parent' => $comment->comment_ID,
1311                  'type'   => $comment->comment_type,
1312                  'status' => 'all',
1313              );
1314  
1315              $rest_url = add_query_arg( $args, rest_url( $this->namespace . '/' . $this->rest_base ) );
1316  
1317              $links['children'] = array(
1318                  'href'       => $rest_url,
1319                  'embeddable' => true,
1320              );
1321          }
1322  
1323          return $links;
1324      }
1325  
1326      /**
1327       * Prepends internal property prefix to query parameters to match our response fields.
1328       *
1329       * @since 4.7.0
1330       *
1331       * @param string $query_param Query parameter.
1332       * @return string The normalized query parameter.
1333       */
1334  	protected function normalize_query_param( $query_param ) {
1335          $prefix = 'comment_';
1336  
1337          switch ( $query_param ) {
1338              case 'id':
1339                  $normalized = $prefix . 'ID';
1340                  break;
1341              case 'post':
1342                  $normalized = $prefix . 'post_ID';
1343                  break;
1344              case 'parent':
1345                  $normalized = $prefix . 'parent';
1346                  break;
1347              case 'include':
1348                  $normalized = 'comment__in';
1349                  break;
1350              default:
1351                  $normalized = $prefix . $query_param;
1352                  break;
1353          }
1354  
1355          return $normalized;
1356      }
1357  
1358      /**
1359       * Checks comment_approved to set comment status for single comment output.
1360       *
1361       * @since 4.7.0
1362       *
1363       * @param string $comment_approved Comment status.
1364       * @return string Comment status.
1365       */
1366  	protected function prepare_status_response( $comment_approved ) {
1367  
1368          switch ( $comment_approved ) {
1369              case 'hold':
1370              case '0':
1371                  $status = 'hold';
1372                  break;
1373  
1374              case 'approve':
1375              case '1':
1376                  $status = 'approved';
1377                  break;
1378  
1379              case 'spam':
1380              case 'trash':
1381              default:
1382                  $status = $comment_approved;
1383                  break;
1384          }
1385  
1386          return $status;
1387      }
1388  
1389      /**
1390       * Prepares a single comment to be inserted into the database.
1391       *
1392       * @since 4.7.0
1393       *
1394       * @param WP_REST_Request $request Request object.
1395       * @return array|WP_Error Prepared comment, otherwise WP_Error object.
1396       */
1397  	protected function prepare_item_for_database( $request ) {
1398          $prepared_comment = array();
1399  
1400          /*
1401           * Allow the comment_content to be set via the 'content' or
1402           * the 'content.raw' properties of the Request object.
1403           */
1404          if ( isset( $request['content'] ) && is_string( $request['content'] ) ) {
1405              $prepared_comment['comment_content'] = trim( $request['content'] );
1406          } elseif ( isset( $request['content']['raw'] ) && is_string( $request['content']['raw'] ) ) {
1407              $prepared_comment['comment_content'] = trim( $request['content']['raw'] );
1408          }
1409  
1410          if ( isset( $request['post'] ) ) {
1411              $prepared_comment['comment_post_ID'] = (int) $request['post'];
1412          }
1413  
1414          if ( isset( $request['parent'] ) ) {
1415              $prepared_comment['comment_parent'] = $request['parent'];
1416          }
1417  
1418          if ( isset( $request['author'] ) ) {
1419              $user = new WP_User( $request['author'] );
1420  
1421              if ( $user->exists() ) {
1422                  $prepared_comment['user_id']              = $user->ID;
1423                  $prepared_comment['comment_author']       = $user->display_name;
1424                  $prepared_comment['comment_author_email'] = $user->user_email;
1425                  $prepared_comment['comment_author_url']   = $user->user_url;
1426              } else {
1427                  return new WP_Error(
1428                      'rest_comment_author_invalid',
1429                      __( 'Invalid comment author ID.' ),
1430                      array( 'status' => 400 )
1431                  );
1432              }
1433          }
1434  
1435          if ( isset( $request['author_name'] ) ) {
1436              $prepared_comment['comment_author'] = $request['author_name'];
1437          }
1438  
1439          if ( isset( $request['author_email'] ) ) {
1440              $prepared_comment['comment_author_email'] = $request['author_email'];
1441          }
1442  
1443          if ( isset( $request['author_url'] ) ) {
1444              $prepared_comment['comment_author_url'] = $request['author_url'];
1445          }
1446  
1447          if ( isset( $request['author_ip'] ) && current_user_can( 'moderate_comments' ) ) {
1448              $prepared_comment['comment_author_IP'] = $request['author_ip'];
1449          } elseif ( ! empty( $_SERVER['REMOTE_ADDR'] ) && rest_is_ip_address( $_SERVER['REMOTE_ADDR'] ) ) {
1450              $prepared_comment['comment_author_IP'] = $_SERVER['REMOTE_ADDR'];
1451          } else {
1452              $prepared_comment['comment_author_IP'] = '127.0.0.1';
1453          }
1454  
1455          if ( ! empty( $request['author_user_agent'] ) ) {
1456              $prepared_comment['comment_agent'] = $request['author_user_agent'];
1457          } elseif ( $request->get_header( 'user_agent' ) ) {
1458              $prepared_comment['comment_agent'] = $request->get_header( 'user_agent' );
1459          }
1460  
1461          if ( ! empty( $request['date'] ) ) {
1462              $date_data = rest_get_date_with_gmt( $request['date'] );
1463  
1464              if ( ! empty( $date_data ) ) {
1465                  list( $prepared_comment['comment_date'], $prepared_comment['comment_date_gmt'] ) = $date_data;
1466              }
1467          } elseif ( ! empty( $request['date_gmt'] ) ) {
1468              $date_data = rest_get_date_with_gmt( $request['date_gmt'], true );
1469  
1470              if ( ! empty( $date_data ) ) {
1471                  list( $prepared_comment['comment_date'], $prepared_comment['comment_date_gmt'] ) = $date_data;
1472              }
1473          }
1474  
1475          /**
1476           * Filters a comment added via the REST API after it is prepared for insertion into the database.
1477           *
1478           * Allows modification of the comment right after it is prepared for the database.
1479           *
1480           * @since 4.7.0
1481           *
1482           * @param array           $prepared_comment The prepared comment data for `wp_insert_comment`.
1483           * @param WP_REST_Request $request          The current request.
1484           */
1485          return apply_filters( 'rest_preprocess_comment', $prepared_comment, $request );
1486      }
1487  
1488      /**
1489       * Retrieves the comment's schema, conforming to JSON Schema.
1490       *
1491       * @since 4.7.0
1492       *
1493       * @return array
1494       */
1495  	public function get_item_schema() {
1496          if ( $this->schema ) {
1497              return $this->add_additional_fields_schema( $this->schema );
1498          }
1499  
1500          $schema = array(
1501              '$schema'    => 'http://json-schema.org/draft-04/schema#',
1502              'title'      => 'comment',
1503              'type'       => 'object',
1504              'properties' => array(
1505                  'id'                => array(
1506                      'description' => __( 'Unique identifier for the comment.' ),
1507                      'type'        => 'integer',
1508                      'context'     => array( 'view', 'edit', 'embed' ),
1509                      'readonly'    => true,
1510                  ),
1511                  'author'            => array(
1512                      'description' => __( 'The ID of the user object, if author was a user.' ),
1513                      'type'        => 'integer',
1514                      'context'     => array( 'view', 'edit', 'embed' ),
1515                  ),
1516                  'author_email'      => array(
1517                      'description' => __( 'Email address for the comment author.' ),
1518                      'type'        => 'string',
1519                      'format'      => 'email',
1520                      'context'     => array( 'edit' ),
1521                      'arg_options' => array(
1522                          'sanitize_callback' => array( $this, 'check_comment_author_email' ),
1523                          'validate_callback' => null, // Skip built-in validation of 'email'.
1524                      ),
1525                  ),
1526                  'author_ip'         => array(
1527                      'description' => __( 'IP address for the comment author.' ),
1528                      'type'        => 'string',
1529                      'format'      => 'ip',
1530                      'context'     => array( 'edit' ),
1531                  ),
1532                  'author_name'       => array(
1533                      'description' => __( 'Display name for the comment author.' ),
1534                      'type'        => 'string',
1535                      'context'     => array( 'view', 'edit', 'embed' ),
1536                      'arg_options' => array(
1537                          'sanitize_callback' => 'sanitize_text_field',
1538                      ),
1539                  ),
1540                  'author_url'        => array(
1541                      'description' => __( 'URL for the comment author.' ),
1542                      'type'        => 'string',
1543                      'format'      => 'uri',
1544                      'context'     => array( 'view', 'edit', 'embed' ),
1545                  ),
1546                  'author_user_agent' => array(
1547                      'description' => __( 'User agent for the comment author.' ),
1548                      'type'        => 'string',
1549                      'context'     => array( 'edit' ),
1550                      'arg_options' => array(
1551                          'sanitize_callback' => 'sanitize_text_field',
1552                      ),
1553                  ),
1554                  'content'           => array(
1555                      'description' => __( 'The content for the comment.' ),
1556                      'type'        => 'object',
1557                      'context'     => array( 'view', 'edit', 'embed' ),
1558                      'arg_options' => array(
1559                          'sanitize_callback' => null, // Note: sanitization implemented in self::prepare_item_for_database().
1560                          'validate_callback' => null, // Note: validation implemented in self::prepare_item_for_database().
1561                      ),
1562                      'properties'  => array(
1563                          'raw'      => array(
1564                              'description' => __( 'Content for the comment, as it exists in the database.' ),
1565                              'type'        => 'string',
1566                              'context'     => array( 'edit' ),
1567                          ),
1568                          'rendered' => array(
1569                              'description' => __( 'HTML content for the comment, transformed for display.' ),
1570                              'type'        => 'string',
1571                              'context'     => array( 'view', 'edit', 'embed' ),
1572                              'readonly'    => true,
1573                          ),
1574                      ),
1575                  ),
1576                  'date'              => array(
1577                      'description' => __( "The date the comment was published, in the site's timezone." ),
1578                      'type'        => 'string',
1579                      'format'      => 'date-time',
1580                      'context'     => array( 'view', 'edit', 'embed' ),
1581                  ),
1582                  'date_gmt'          => array(
1583                      'description' => __( 'The date the comment was published, as GMT.' ),
1584                      'type'        => 'string',
1585                      'format'      => 'date-time',
1586                      'context'     => array( 'view', 'edit' ),
1587                  ),
1588                  'link'              => array(
1589                      'description' => __( 'URL to the comment.' ),
1590                      'type'        => 'string',
1591                      'format'      => 'uri',
1592                      'context'     => array( 'view', 'edit', 'embed' ),
1593                      'readonly'    => true,
1594                  ),
1595                  'parent'            => array(
1596                      'description' => __( 'The ID for the parent of the comment.' ),
1597                      'type'        => 'integer',
1598                      'context'     => array( 'view', 'edit', 'embed' ),
1599                      'default'     => 0,
1600                  ),
1601                  'post'              => array(
1602                      'description' => __( 'The ID of the associated post object.' ),
1603                      'type'        => 'integer',
1604                      'context'     => array( 'view', 'edit' ),
1605                      'default'     => 0,
1606                  ),
1607                  'status'            => array(
1608                      'description' => __( 'State of the comment.' ),
1609                      'type'        => 'string',
1610                      'context'     => array( 'view', 'edit' ),
1611                      'arg_options' => array(
1612                          'sanitize_callback' => 'sanitize_key',
1613                      ),
1614                  ),
1615                  'type'              => array(
1616                      'description' => __( 'Type of the comment.' ),
1617                      'type'        => 'string',
1618                      'context'     => array( 'view', 'edit', 'embed' ),
1619                      'readonly'    => true,
1620                      'default'     => 'comment',
1621                  ),
1622              ),
1623          );
1624  
1625          if ( get_option( 'show_avatars' ) ) {
1626              $avatar_properties = array();
1627  
1628              $avatar_sizes = rest_get_avatar_sizes();
1629  
1630              foreach ( $avatar_sizes as $size ) {
1631                  $avatar_properties[ $size ] = array(
1632                      /* translators: %d: Avatar image size in pixels. */
1633                      'description' => sprintf( __( 'Avatar URL with image size of %d pixels.' ), $size ),
1634                      'type'        => 'string',
1635                      'format'      => 'uri',
1636                      'context'     => array( 'embed', 'view', 'edit' ),
1637                  );
1638              }
1639  
1640              $schema['properties']['author_avatar_urls'] = array(
1641                  'description' => __( 'Avatar URLs for the comment author.' ),
1642                  'type'        => 'object',
1643                  'context'     => array( 'view', 'edit', 'embed' ),
1644                  'readonly'    => true,
1645                  'properties'  => $avatar_properties,
1646              );
1647          }
1648  
1649          $schema['properties']['meta'] = $this->meta->get_field_schema();
1650  
1651          $this->schema = $schema;
1652  
1653          return $this->add_additional_fields_schema( $this->schema );
1654      }
1655  
1656      /**
1657       * Retrieves the query params for collections.
1658       *
1659       * @since 4.7.0
1660       *
1661       * @return array Comments collection parameters.
1662       */
1663  	public function get_collection_params() {
1664          $query_params = parent::get_collection_params();
1665  
1666          $query_params['context']['default'] = 'view';
1667  
1668          $query_params['after'] = array(
1669              'description' => __( 'Limit response to comments published after a given ISO8601 compliant date.' ),
1670              'type'        => 'string',
1671              'format'      => 'date-time',
1672          );
1673  
1674          $query_params['author'] = array(
1675              'description' => __( 'Limit result set to comments assigned to specific user IDs. Requires authorization.' ),
1676              'type'        => 'array',
1677              'items'       => array(
1678                  'type' => 'integer',
1679              ),
1680          );
1681  
1682          $query_params['author_exclude'] = array(
1683              'description' => __( 'Ensure result set excludes comments assigned to specific user IDs. Requires authorization.' ),
1684              'type'        => 'array',
1685              'items'       => array(
1686                  'type' => 'integer',
1687              ),
1688          );
1689  
1690          $query_params['author_email'] = array(
1691              'default'     => null,
1692              'description' => __( 'Limit result set to that from a specific author email. Requires authorization.' ),
1693              'format'      => 'email',
1694              'type'        => 'string',
1695          );
1696  
1697          $query_params['before'] = array(
1698              'description' => __( 'Limit response to comments published before a given ISO8601 compliant date.' ),
1699              'type'        => 'string',
1700              'format'      => 'date-time',
1701          );
1702  
1703          $query_params['exclude'] = array(
1704              'description' => __( 'Ensure result set excludes specific IDs.' ),
1705              'type'        => 'array',
1706              'items'       => array(
1707                  'type' => 'integer',
1708              ),
1709              'default'     => array(),
1710          );
1711  
1712          $query_params['include'] = array(
1713              'description' => __( 'Limit result set to specific IDs.' ),
1714              'type'        => 'array',
1715              'items'       => array(
1716                  'type' => 'integer',
1717              ),
1718              'default'     => array(),
1719          );
1720  
1721          $query_params['offset'] = array(
1722              'description' => __( 'Offset the result set by a specific number of items.' ),
1723              'type'        => 'integer',
1724          );
1725  
1726          $query_params['order'] = array(
1727              'description' => __( 'Order sort attribute ascending or descending.' ),
1728              'type'        => 'string',
1729              'default'     => 'desc',
1730              'enum'        => array(
1731                  'asc',
1732                  'desc',
1733              ),
1734          );
1735  
1736          $query_params['orderby'] = array(
1737              'description' => __( 'Sort collection by comment attribute.' ),
1738              'type'        => 'string',
1739              'default'     => 'date_gmt',
1740              'enum'        => array(
1741                  'date',
1742                  'date_gmt',
1743                  'id',
1744                  'include',
1745                  'post',
1746                  'parent',
1747                  'type',
1748              ),
1749          );
1750  
1751          $query_params['parent'] = array(
1752              'default'     => array(),
1753              'description' => __( 'Limit result set to comments of specific parent IDs.' ),
1754              'type'        => 'array',
1755              'items'       => array(
1756                  'type' => 'integer',
1757              ),
1758          );
1759  
1760          $query_params['parent_exclude'] = array(
1761              'default'     => array(),
1762              'description' => __( 'Ensure result set excludes specific parent IDs.' ),
1763              'type'        => 'array',
1764              'items'       => array(
1765                  'type' => 'integer',
1766              ),
1767          );
1768  
1769          $query_params['post'] = array(
1770              'default'     => array(),
1771              'description' => __( 'Limit result set to comments assigned to specific post IDs.' ),
1772              'type'        => 'array',
1773              'items'       => array(
1774                  'type' => 'integer',
1775              ),
1776          );
1777  
1778          $query_params['status'] = array(
1779              'default'           => 'approve',
1780              'description'       => __( 'Limit result set to comments assigned a specific status. Requires authorization.' ),
1781              'sanitize_callback' => 'sanitize_key',
1782              'type'              => 'string',
1783              'validate_callback' => 'rest_validate_request_arg',
1784          );
1785  
1786          $query_params['type'] = array(
1787              'default'           => 'comment',
1788              'description'       => __( 'Limit result set to comments assigned a specific type. Requires authorization.' ),
1789              'sanitize_callback' => 'sanitize_key',
1790              'type'              => 'string',
1791              'validate_callback' => 'rest_validate_request_arg',
1792          );
1793  
1794          $query_params['password'] = array(
1795              'description' => __( 'The password for the post if it is password protected.' ),
1796              'type'        => 'string',
1797          );
1798  
1799          /**
1800           * Filters REST API collection parameters for the comments controller.
1801           *
1802           * This filter registers the collection parameter, but does not map the
1803           * collection parameter to an internal WP_Comment_Query parameter. Use the
1804           * `rest_comment_query` filter to set WP_Comment_Query parameters.
1805           *
1806           * @since 4.7.0
1807           *
1808           * @param array $query_params JSON Schema-formatted collection parameters.
1809           */
1810          return apply_filters( 'rest_comment_collection_params', $query_params );
1811      }
1812  
1813      /**
1814       * Sets the comment_status of a given comment object when creating or updating a comment.
1815       *
1816       * @since 4.7.0
1817       *
1818       * @param string|int $new_status New comment status.
1819       * @param int        $comment_id Comment ID.
1820       * @return bool Whether the status was changed.
1821       */
1822  	protected function handle_status_param( $new_status, $comment_id ) {
1823          $old_status = wp_get_comment_status( $comment_id );
1824  
1825          if ( $new_status === $old_status ) {
1826              return false;
1827          }
1828  
1829          switch ( $new_status ) {
1830              case 'approved':
1831              case 'approve':
1832              case '1':
1833                  $changed = wp_set_comment_status( $comment_id, 'approve' );
1834                  break;
1835              case 'hold':
1836              case '0':
1837                  $changed = wp_set_comment_status( $comment_id, 'hold' );
1838                  break;
1839              case 'spam':
1840                  $changed = wp_spam_comment( $comment_id );
1841                  break;
1842              case 'unspam':
1843                  $changed = wp_unspam_comment( $comment_id );
1844                  break;
1845              case 'trash':
1846                  $changed = wp_trash_comment( $comment_id );
1847                  break;
1848              case 'untrash':
1849                  $changed = wp_untrash_comment( $comment_id );
1850                  break;
1851              default:
1852                  $changed = false;
1853                  break;
1854          }
1855  
1856          return $changed;
1857      }
1858  
1859      /**
1860       * Checks if the post can be read.
1861       *
1862       * Correctly handles posts with the inherit status.
1863       *
1864       * @since 4.7.0
1865       *
1866       * @param WP_Post         $post    Post object.
1867       * @param WP_REST_Request $request Request data to check.
1868       * @return bool Whether post can be read.
1869       */
1870  	protected function check_read_post_permission( $post, $request ) {
1871          $post_type = get_post_type_object( $post->post_type );
1872  
1873          // Return false if custom post type doesn't exist
1874          if ( ! $post_type ) {
1875              return false;
1876          }
1877  
1878          $posts_controller = $post_type->get_rest_controller();
1879  
1880          /*
1881           * Ensure the posts controller is specifically a WP_REST_Posts_Controller instance
1882           * before using methods specific to that controller.
1883           */
1884          if ( ! $posts_controller instanceof WP_REST_Posts_Controller ) {
1885              $posts_controller = new WP_REST_Posts_Controller( $post->post_type );
1886          }
1887  
1888          $has_password_filter = false;
1889  
1890          // Only check password if a specific post was queried for or a single comment
1891          $requested_post    = ! empty( $request['post'] ) && ( ! is_array( $request['post'] ) || 1 === count( $request['post'] ) );
1892          $requested_comment = ! empty( $request['id'] );
1893          if ( ( $requested_post || $requested_comment ) && $posts_controller->can_access_password_content( $post, $request ) ) {
1894              add_filter( 'post_password_required', '__return_false' );
1895  
1896              $has_password_filter = true;
1897          }
1898  
1899          if ( post_password_required( $post ) ) {
1900              $result = current_user_can( 'edit_post', $post->ID );
1901          } else {
1902              $result = $posts_controller->check_read_permission( $post );
1903          }
1904  
1905          if ( $has_password_filter ) {
1906              remove_filter( 'post_password_required', '__return_false' );
1907          }
1908  
1909          return $result;
1910      }
1911  
1912      /**
1913       * Checks if the comment can be read.
1914       *
1915       * @since 4.7.0
1916       *
1917       * @param WP_Comment      $comment Comment object.
1918       * @param WP_REST_Request $request Request data to check.
1919       * @return bool Whether the comment can be read.
1920       */
1921  	protected function check_read_permission( $comment, $request ) {
1922          if ( 'note' !== $comment->comment_type && ! empty( $comment->comment_post_ID ) ) {
1923              $post = get_post( $comment->comment_post_ID );
1924              if ( $post ) {
1925                  if ( $this->check_read_post_permission( $post, $request ) && 1 === (int) $comment->comment_approved ) {
1926                      return true;
1927                  }
1928              }
1929          }
1930  
1931          if ( 0 === get_current_user_id() ) {
1932              return false;
1933          }
1934  
1935          if ( empty( $comment->comment_post_ID ) && ! current_user_can( 'moderate_comments' ) ) {
1936              return false;
1937          }
1938  
1939          if ( ! empty( $comment->user_id ) && get_current_user_id() === (int) $comment->user_id ) {
1940              return true;
1941          }
1942  
1943          return current_user_can( 'edit_comment', $comment->comment_ID );
1944      }
1945  
1946      /**
1947       * Checks if a comment can be edited or deleted.
1948       *
1949       * @since 4.7.0
1950       *
1951       * @param WP_Comment $comment Comment object.
1952       * @return bool Whether the comment can be edited or deleted.
1953       */
1954  	protected function check_edit_permission( $comment ) {
1955          if ( 0 === (int) get_current_user_id() ) {
1956              return false;
1957          }
1958  
1959          if ( current_user_can( 'moderate_comments' ) ) {
1960              return true;
1961          }
1962  
1963          return current_user_can( 'edit_comment', $comment->comment_ID );
1964      }
1965  
1966      /**
1967       * Checks a comment author email for validity.
1968       *
1969       * Accepts either a valid email address or empty string as a valid comment
1970       * author email address. Setting the comment author email to an empty
1971       * string is allowed when a comment is being updated.
1972       *
1973       * @since 4.7.0
1974       *
1975       * @param string          $value   Author email value submitted.
1976       * @param WP_REST_Request $request Full details about the request.
1977       * @param string          $param   The parameter name.
1978       * @return string|WP_Error The sanitized email address, if valid,
1979       *                         otherwise an error.
1980       */
1981  	public function check_comment_author_email( $value, $request, $param ) {
1982          $email = (string) $value;
1983          if ( empty( $email ) ) {
1984              return $email;
1985          }
1986  
1987          $check_email = rest_validate_request_arg( $email, $request, $param );
1988          if ( is_wp_error( $check_email ) ) {
1989              return $check_email;
1990          }
1991  
1992          return $email;
1993      }
1994  
1995      /**
1996       * If empty comments are not allowed, checks if the provided comment content is not empty.
1997       *
1998       * @since 5.6.0
1999       *
2000       * @param array $prepared_comment The prepared comment data.
2001       * @return bool True if the content is allowed, false otherwise.
2002       */
2003  	protected function check_is_comment_content_allowed( $prepared_comment ) {
2004          if ( ! isset( $prepared_comment['comment_content'] ) ) {
2005              return true;
2006          }
2007  
2008          $check = wp_parse_args(
2009              $prepared_comment,
2010              array(
2011                  'comment_post_ID'      => 0,
2012                  'comment_author'       => null,
2013                  'comment_author_email' => null,
2014                  'comment_author_url'   => null,
2015                  'comment_parent'       => 0,
2016                  'user_id'              => 0,
2017              )
2018          );
2019  
2020          /** This filter is documented in wp-includes/comment.php */
2021          $allow_empty = apply_filters( 'allow_empty_comment', false, $check );
2022  
2023          if ( $allow_empty ) {
2024              return true;
2025          }
2026  
2027          // Allow empty notes only when resolution metadata is valid.
2028          if (
2029              isset( $check['comment_type'] ) &&
2030              'note' === $check['comment_type'] &&
2031              isset( $check['meta']['_wp_note_status'] ) &&
2032              in_array( $check['meta']['_wp_note_status'], array( 'resolved', 'reopen' ), true )
2033          ) {
2034              return true;
2035          }
2036  
2037          /*
2038           * Do not allow a comment to be created with missing or empty
2039           * comment_content. See wp_handle_comment_submission().
2040           */
2041          return '' !== $check['comment_content'];
2042      }
2043  
2044      /**
2045       * Check if post type supports notes.
2046       *
2047       * @param string $post_type Post type name.
2048       * @return bool True if post type supports notes, false otherwise.
2049       */
2050  	private function check_post_type_supports_notes( $post_type ) {
2051          $supports = get_all_post_type_supports( $post_type );
2052          if ( ! isset( $supports['editor'] ) ) {
2053              return false;
2054          }
2055          if ( ! is_array( $supports['editor'] ) ) {
2056              return false;
2057          }
2058          foreach ( $supports['editor'] as $item ) {
2059              if ( ! empty( $item['notes'] ) ) {
2060                  return true;
2061              }
2062          }
2063          return false;
2064      }
2065  }


Generated : Sun Jun 14 08:20:09 2026 Cross-referenced by PHPXref